Second Generation
After I had implemented sorting (
First Generation) of
WPF ListView, I wanted to add small glyphs that indicates the sorted
column and the sorting direction. In my application sorting is only used
if the user triggers it on the view and it changes only the view and
not the data. So I decided to move sorting code to
code-behind what made
it easier to add the small sorting direction arrows to a column header.
First I defined the small glyphs that are used to indicate the sorting direction.
<UserControl.Resources>
<DataTemplate x:Key="ArrowUp">
<DockPanel>
<TextBlock HorizontalAlignment="Center"
Text="{Binding}" />
<Path VerticalAlignment="Center"
Fill="Black"
Data="M 5,5 15,5 10,0 5,5" />
</DockPanel>
</DataTemplate>
<DataTemplate x:Key="ArrowDown">
<DockPanel>
<TextBlock HorizontalAlignment="Center"
Text="{Binding}" />
<Path VerticalAlignment="Center"
Fill="Black"
Data="M 5,0 10,5 15,0 5,0" />
</DockPanel>
</DataTemplate>
</UserControl.Resources>
Then I changed the View. I removed the commanding and added a click event handler.
<ListView x:Name="SecondResultData"
ItemsSource="{Binding SecondResultData}"
GridViewColumnHeader.Click="SecondResultDataViewClick">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding ResultNumber}">
<GridViewColumnHeader Content="Number" />
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding ResultOutput}">
<GridViewColumnHeader Content="Output" />
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The ItemsSource is still binded to a property in the ViewModel.
public ObservableCollection<ResultData> SecondResultData { get; set; }
The click event handler is implemented in
code-behind.
private ListSortDirection _sortDirection;
private GridViewColumnHeader _sortColumn;
private void SecondResultDataViewClick(object sender, RoutedEventArgs e)
{
GridViewColumnHeader column = e.OriginalSource as GridViewColumnHeader;
if (column == null)
{
return;
}
if (_sortColumn == column)
{
// Toggle sorting direction
_sortDirection = _sortDirection == ListSortDirection.Ascending ?
ListSortDirection.Descending :
ListSortDirection.Ascending;
}
else
{
// Remove arrow from previously sorted header
if (_sortColumn != null)
{
_sortColumn.Column.HeaderTemplate = null;
_sortColumn.Column.Width = _sortColumn.ActualWidth - 20;
}
_sortColumn = column;
_sortDirection = ListSortDirection.Ascending;
column.Column.Width = column.ActualWidth + 20;
}
if (_sortDirection == ListSortDirection.Ascending)
{
column.Column.HeaderTemplate = Resources["ArrowUp"] as DataTemplate;
}
else
{
column.Column.HeaderTemplate = Resources["ArrowDown"] as DataTemplate;
}
string header = string.Empty;
// if binding is used and property name doesn't match header content
Binding b = _sortColumn.Column.DisplayMemberBinding as Binding;
if (b != null)
{
header = b.Path.Path;
}
ICollectionView resultDataView = CollectionViewSource.GetDefaultView(
SecondResultData.ItemsSource);
resultDataView.SortDescriptions.Clear();
resultDataView.SortDescriptions.Add(
new SortDescription(header, _sortDirection));
}
The click event handler set the HeaderTemplate of the columns. Therefore the previously defined glyphs are used. The column that is used to sort gets an arrow that indicates the sorting direction. The arrow is removed from previously sorted column, if necessary.
The source code can be downloaded from
http://code.msdn.microsoft.com/Sorting-a-WPF-ListView-by-5769086f
Further Posts
- Sorting a WPF ListView/GridView by clicking on the header
- Sort Direction Indicators
- Sort in ViewModel
- Sort Direction Indicators with Adorners
- Reusability
- More Reusability
- Attached Property
- Behaviors (Expression Blend)