A while back I needed to solve the problem of making all of the
DataGridView controls in our application sortable, but without needing to implement a custom sort in every single form. The problem is that the
DataGridView, for reasons unknown to me, does not include default sorting. The only way I could find to get automatic sorting was if the data source was a
DataSet or if the columns and rows are added manually rather than using a data source. I toyed with the idea of manually adding columns and rows, but that did not last long as I realized that would be entirely too tedious and prone to break. I was also not able to use a
DataSet as my data source.
Through some research, I did find that when bound to a
DataGridView checks the
BindingList.SupportsSortingCore property. This is normally
false, but if you create your own
BindingList (using inheritance) and override the sort-specific properties, you can implement sorting and the
DataGridView will take care of the rest.
Let me briefly explain how the
DataGridView sorting works in relation to the
DataGridView calls the
BindingList.ApplySortCore method, passing a
PropertyDescriptor for the sort column and the sort direction. Internally, you’ll use the
List<T>.Sort() method to handle the sort algorithm, but it is up to you for the item comparison logic. The
DataGridView will then display the sorted data along with a sorting glyph indicating the sort direction. The sorting glyph has no relation with the data; it is simply tracking internally by the
This leaves you with two options regarding the implementation of the sorting. You can accomplish sorting using some generic code that tries to compare the properties using the
IComparable interface for the property value. Alternatively, you can create a custom sorter for every type of object that you might have sorted in a grid and provide that custom sorter to the
BindingList. Let me explain the benefits and drawbacks of each method.
Generic Sort Comparer
- Automatically covers any new data types
- Does not compare types that do not implement
- Not as flexible for complex sorting algorithm
Type-Specific Sort Comparer
- Supports advanced sorting and comparison of complex data types
- Supports sorting of types which do not implement
- Must implement a new sort comparer for each data type to be sorted
- Must maintain the sort comparer as the class changes
I ultimately decided to use a combination of the two methods. To start with, small data sets that don’t need any complex sorting just use the generic sort comparer, which is the default sort comparer in my custom BindingList. However, I do provide the ability for the
BindingList to be provided an
ISortComparer<T> to be used in place of the generic sort comparer. For large data sets or complex comparisons, I provide the
BindingList with a custom sort comparer and performance improves tremendously.
I’ve uploaded the source files for the concepts mentioned above to gist.github.com.