Tuesday, May 20, 2014

Using a converter to allow datagrids to sort properly

This post is for WPF 4.0.

I have a datagrid that lists reports. One column, a datetime called LastRun, tells the user when they last ran the report. Rather than simply display the date and time, I decided to display it in a more friendly way i.e. "32 minutes ago" or "Yesterday at 8:32 AM".

I wrote a utility function to do this and populated a new string column in the datagrid's ItemsSource called FriendlyLastRun. I bound the DataGridTextColumn to FriendlyLastRun and all looks good.

 
Reports sorted alphabetically

This works great until the user tries to sort on the Last Run column. It sorts as a string which means "0" is before "4" which is before "L". This is not what I want. There are two potential solutions.

The obvious solution is to specify a SortMemberPath on the column. This allows the designer to display the contents of one datacolumn but sort on the contents of another datacolumn. This works fine, but essentially requires the same data to be represented twice which is never good design and creates issues if the column is updatable. You would achieve this with the following XAML.

<DataGridTextColumn Header="Last Run" Binding="{Binding FriendlyLastRun}" SortMemberPath="LastRun"/>

A less obvious solution is to write a converter that calls the utility function. This allows me to get rid of the FriendlyLastRun datacolumn and bind to LastRun using a converter. The XAML looks like this.

<DataGridTextColumn Header="Last Run" Binding="{Binding LastRun, Converter={StaticResource DisplayAgeConverter}}"/>

Because datagrids sort on the contents of the ItemsSource and not on the displayed value, this works correctly and does not require me to hold the same information in two places. Furthermore, if Last Run was editable, the ConvertBack method of the converter would update the ItemsSource correctly.

Reports sorted most recent first

No comments:

Post a Comment