There doesn't seem to be a lot of information around on getting sorting in a WinForms DataGrid to work with custom collections. So I've done the hard work for you and here it is. First I wrote a sorting class, hopefully generic enough to sort pretty much any kind of simple data types (if your collection contains other objects you'll probably need to update this somewhat).
internal class Comparer : IComparer { private PropertyDescriptor sortProperty; private ListSortDirection sortDirection; public Comparer(PropertyDescriptor sortProperty, ListSortDirection sortDirection) { this.sortProperty = sortProperty; this.sortDirection = sortDirection; } #region IComparer Members public int Compare(object x, object y) { Type propType = sortProperty.PropertyType; int sort = 0; if (propType == typeof(string)) sort = string.Compare((string)sortProperty.GetValue(x), (string)sortProperty.GetValue(y)); else if (propType == typeof(DateTime)) sort = DateTime.Compare((DateTime)sortProperty.GetValue(x), (DateTime)sortProperty.GetValue(y)); else if (propType.IsEnum) sort = (int)sortProperty.GetValue(x) - (int)sortProperty.GetValue(y); else if (propType == typeof(int)) sort = (int)sortProperty.GetValue(x) - (int)sortProperty.GetValue(y); else if (propType == typeof(Type)) sort = string.Compare(sortProperty.GetValue(x).ToString(), sortProperty.GetValue(y).ToString()); else if (propType == typeof(bool)) sort = string.Compare(sortProperty.GetValue(x).ToString(), sortProperty.GetValue(y).ToString()); else throw new NotSupportedException(); if (sortDirection == ListSortDirection.Descending) sort = -sort; return sort; } #endregion }
Then I had to implement the IBindingList interface. Actually most of the IBindingList interface is redundant (makes me wonder why it wasn't broken down into a few smaller interfaces, ISortList, ISearchList etc), so here are the bits that are different to the stubs provided by Visual Studio.
void IBindingList.ApplySort(PropertyDescriptor property, ListSortDirection direction) { sortProperty = property; sortDirection = direction; objectList.Sort(new Comparer(sortProperty, sortDirection)); } private PropertyDescriptor sortProperty; PropertyDescriptor IBindingList.SortProperty { get { return sortProperty; } } bool IBindingList.SupportsSorting { get { return true; } } bool IBindingList.IsSorted { get { return (sortProperty != null); } } void IBindingList.RemoveSort() { sortProperty = null; } private ListSortDirection sortDirection; ListSortDirection IBindingList.SortDirection { get { return sortDirection; } }
objectList is my internal ArrayList that contains the collection of objects I'm interested in.
I'm not entirely happy with this solution. I have a lot of collection classes and each one has this same bit of code in it, which always smells a bit bad to me. At some point I might try to create a base class that encapsulates this functionality but it doesn't look too straightforward, since IBindingList requires IList, ICollection and IEnumerable implementations as well...