ICollectionView Sorting issue in ListView
I saw ICollectionView
being introduced with WPF to handle situations when you need sorting and filtering enabled. I even saw few articles which sort items, but my main concern is why my approach is failing. Lets see my code :
<ListView ItemsSource="{Binding}" x:Name="lvItems" GridViewColumnHeader.Click="ListView_Click开发者_StackOverflow中文版">
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id}" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Developer">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Developer}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Salary">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Salary}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
In codebehind, when the Item is clicked I am doing like this :
ICollectionView Source { get; set; }
private void ListView_Click(object sender, RoutedEventArgs e)
{
GridViewColumnHeader currentHeader = e.OriginalSource as GridViewColumnHeader;
if(currentHeader != null && currentHeader.Role != GridViewColumnHeaderRole.Padding)
{
//using (this.Source.DeferRefresh())
//{
SortDescription currentPropertySort = this.Source.SortDescriptions.FirstOrDefault<SortDescription>(item => item.PropertyName.Equals(currentHeader.Column.Header.ToString()));
if (currentPropertySort != null)
{
if (currentPropertySort.Direction == ListSortDirection.Ascending)
currentPropertySort.Direction = ListSortDirection.Descending;
else
currentPropertySort.Direction = ListSortDirection.Ascending;
}
else
this.Source.SortDescriptions.Add(new SortDescription(currentHeader.Column.Header.ToString(), ListSortDirection.Ascending));
//}
this.Source.Refresh();
this.lvItems.DataContext = this.Source;
this.lvItems.UpdateLayout();
}
}
So whenever the header for the ListBox
is clicked, the item need to be sorted. I am holding the collection using a property called Source and then using it by calling lvItems.DataContext = this.Source.
But the code does not seem to be working.
Here's an updated version of your ListView_Click method that somewhat works. I'm not sure exactly what sorting behavior you were looking for but the version below "stacks up" a set of sort descriptions, making the last clicked column as the "primary sort description". I hope this makes sense and I hope the code below helps. =)
private void ListView_Click(object sender, RoutedEventArgs e)
{
GridViewColumnHeader currentHeader = e.OriginalSource as GridViewColumnHeader;
if(currentHeader != null && currentHeader.Role != GridViewColumnHeaderRole.Padding)
{
if (this.Source.SortDescriptions
.Count((item) => item.PropertyName.Equals(currentHeader.Column.Header.ToString())) > 0)
{
SortDescription currentPropertySort = this.Source
.SortDescriptions
.First<SortDescription>(item => item.PropertyName.Equals(currentHeader.Column.Header.ToString()));
//Toggle sort direction.
ListSortDirection direction =
(currentPropertySort.Direction == ListSortDirection.Ascending)?
ListSortDirection.Descending : ListSortDirection.Ascending;
//Remove existing sort
this.Source.SortDescriptions.Remove(currentPropertySort);
this.Source.SortDescriptions.Insert(0, new SortDescription(currentHeader.Column.Header.ToString(), direction));
}
else
{
this.Source.SortDescriptions.Insert(0, new SortDescription(currentHeader.Column.Header.ToString(), ListSortDirection.Ascending));
}
this.Source.Refresh();
}
}
EDIT:
By the way, one of the problems in your code above is your call to "FirstOrDefault" to query an existing SortDescription. See, SortDescription is a struct, which is non-nullable so the call to FirstOrDefault will never be null and will always return an instance. Therefore, the "else-statement" in your code above will never get called.
精彩评论