Sorting Data in the Silverlight DataGrid

This post has been updated to work with the RTW version of the Silverlight 2 DataGrid.  The code examples are not guaranteed to work with previous Beta versions of the DataGrid. Read more about the features that the Silverlight 2 DataGrid has to offer...

Multi-column Sorting

One of the most requested features in Beta 1 was a way to sort the data contained in the DataGrid.  In fact it was so desired that clever developers such as Matt Berseth simply created their own implementation.  Fortunately, you no longer have to put much work into getting this functionality out of the box. 

To get sorting functionality in your DataGrid you will need to perform the following steps:

  1. Make sure that the collection that you use as the DataGrid's ItemsSource implements IList.  Common implementations are List<T> and ObservableCollection<T>. 
  2. That's it, you don't need to do anything else

Why this odd requirement?  Under the covers, when a DataGrid is data bound to a collection that implements IList, it creates an internal ListCollectionView to provide the sorting functionality.  Since CollectionViews can handle multiple levels of sorting, the DataGrid also possesses this functionality and exposes it by allowing your users to click on multiple headers while holding the Shift key.

Here is the DataGrid showing off multi-column sorting:

 MultiColumnSort

Customizing Sorting

Alternatively if you want more control over how the sorting algorithm is performed, you can implement the ICollectionView interface currently found in System.Windows.Controls.Data.  The DataGrid knows that when it is bound to an implementation of ICollectionView that it should delegate all sorting to it, listening to its SortDescriptions collection and visually displaying the sorting status of the CollectionView.  Additionally by using an external CollectionView, you can have multiple controls share the same sort order.

Turning Off Sorting

It is easy to get sorting out of the box, but you might not want to allow your DataGrid or a particular column to be sorted by your user.  To turn this off, use DataGrid's CanUserSortColumns property to turn on or off all sorting at the DataGrid level, or use DataGridColumn's CanUserSort to turn on or off sorting for a particular column.

C#

 dataGrid1.CanUserSortColumns = false;
 unsortableColumn.CanUserSort = false;

VB

 DataGrid1.CanUserSortColumns = False
 UnsortableColumn.CanUserSort = False
Choosing Which Property to Sort By

Sometimes the property that your column is bound to is not always the one that you want it to sort by.  Normally a column sorts by the property that it is bound to through the Binding property.  However, if you look at the Template Column there is no Binding property, meaning that the DataGrid has no idea of how to sort the data if you were to click on that column's header.  To give the DataGrid that information, you can use a property found on all column types called SortMemberPath.  This property allows you to specify a path to the property on the data item that you want that particular column to sort by.  Now if you create a template column that uses a DatePicker to allow your user to select a date instead of the standard TextBox, you can still provide sorting for that column by setting the SortMemberPath.

C#

 datePickerColumn.SortMemberPath = "Birthday";

VB

 DatePickerColumn.SortMemberPath = "Birthday"

Notice that since SortMemberPath is on DataGridColumn, you can use this beyond just template columns and can actually have a column bound to one property, but sort based on another property.  This is a much less common scenario, but becomes useful when working with types that normally don't support sorting such as Colors or Images.

Sorting UI Cues

In the picture above you can see that each sorted column has an arrow in its header indicating if it is sorted ascending or descending.  It also has a subtle animation when switching between the two.  If you want to customize how this looks or behaves, the easiest way to do this is to use the Visual State Manager in Blend.  Otherwise, you can manually override the default DataGridColumnHeader template using the DataGrid.ColumnHeaderStyle property.  The template contains two storyboards, one named "SortAscending" and the other named "SortDescending".  These two storyboards are ran by the DataGrid when a column is sorted ascending or descending.  Finally there is a third storyboard called "Unsorted" that is ran when the data is no longer being sorted by that column and can be used to clean up any UI that you used to display sort status.