Monday, December 23, 2013

Sorting Evolution (2) - Sorting a WPF ListView/GridView by clicking on the header - Sort Direction Indicators

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 { getset; }

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

  1. Sorting a WPF ListView/GridView by clicking on the header
  2. Sort Direction Indicators 
  3. Sort in ViewModel 
  4. Sort Direction Indicators with Adorners
  5. Reusability
  6. More Reusability
  7. Attached Property
  8. Behaviors (Expression Blend)

1 comment: