Tuesday, 31 July 2012

WPF DataGrid Custom Column Sorting

With thanks to Aran Holland with this Stackoverflow answer.
I wanted to sort a DataGrid by StudentID. Unfortunately the StudentID is mainly numeric but with an alpha prefix - typically S12345. Paul had previously written SortableStringValue so I just needed to hook that up to the DataGrid using a custom class that implements IComparer.
In the code-behind I hooked up the DataGrid's Sorting event in the constructor.

public StudentCourseSearchView()
{
   InitializeComponent();

   SearchResults.Sorting += new DataGridSortingEventHandler(SearchResults_Sorting);
}
Then in the private SearchResults_Sorting method I determine if it is the StudentID column that is being sorted and instantiate the custom sorting class.

void SearchResults_Sorting(object sender, System.Windows.Controls.DataGridSortingEventArgs e)
{
   DataGridColumn column = e.Column;

   // I'm only interested in a custom sort for the StudentID column
   if (column.SortMemberPath != "StudentID.Number") return;

   IComparer comparer = null;

   // Prevent the built-in sort from sorting 
   e.Handled = true;

   ListSortDirection direction = (column.SortDirection != ListSortDirection.Ascending) ? ListSortDirection.Ascending : ListSortDirection.Descending;

   // Set the sort order on the column 
   column.SortDirection = direction;

   //use a ListCollectionView to do the sort. 
   ListCollectionView lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(TypedViewModel.Students);

   // Instantiate the custom sort class which implements IComparer
   comparer = new StudentSearchResultStudentIdSort(direction);

   // Apply the sort 
   lcv.CustomSort = comparer;
}
Finally, the StudentSearchResultStudentIdSort class implements the Compare method using the SortableStringValue extension method.

public class StudentSearchResultStudentIdSort : IComparer
{
   ListSortDirection _direction;

   public StudentSearchResultStudentIdSort(ListSortDirection direction)
   {
      _direction = direction;
   }
   public int Compare(object x, object y)
   {
      string studentIdX = (x as StudentSearchResult).StudentID.Value;
      string studentIdY = (y as StudentSearchResult).StudentID.Value;

      if (_direction == ListSortDirection.Ascending)
      {
         return studentIdX.SortableStringValue().CompareTo(studentIdY.SortableStringValue());
      }
      else
      {
         return studentIdY.SortableStringValue().CompareTo(studentIdX.SortableStringValue());
      }
   }
}