Tim Van Wassenhove

Passionate geek, interested in Technology. Proud father of two

02 Aug 2008

Presenting the SortableBindingList<T> (take two)

I’m in the progress of adding classes that i find interesting to the BeTimvwFramework project. The original implementation of my SortableBindingList relied on IComparable to implement ApplySortCore(PropertyDescriptor property, ListSortDirection direction). I received some good feedback and blogged about those improvements.

Because some of my classes only implement IComparable i needed support for this too. My first thought was to use Comparer

IComparer comparer = Comparer<t>.Default;
itemsList.Sort(delegate(T t1, T t2)
{
	object property1 = prop.GetValue(t1);
	object property2 = prop.GetValue(t2);
	return reverse * comparer.Compare(property1, property2);
});

Obviously that didn’t work. The problem is that i received the default Comparer for T, instead of the Comparer for the type of the property. Anyway, with a bit of reflection i got access to that Comparer

Type comparablePropertyType = typeof(Comparer<>).MakeGenericType(property.PropertyType);
IComparer comparer = (IComparer)comparablePropertyType.InvokeMember("Default", BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public, null, null, null);

After a bit of refactoring i ended up with a PropertyComparer which allowed me to implement the sorting as following

Type propertyType = property.PropertyType;

// this cache minimizes the cost of reflection in the PropertyComparer constructor
PropertyComparer<t> comparer;
if (!this.comparers.TryGetValue(propertyType, out comparer))
{
	comparer = new PropertyComparer<t>(property, direction);
	this.comparers.Add(propertyType, comparer);
}
else
{
	comparer.SetListSortDirection(direction);
}

itemsList.Sort(comparer);

In order to write unittests, i needed a way to get instances of a PropertyDescriptor. This was achieved by using the TypeDescriptor as following

PropertyDescriptor GetPropertyDescriptor(object component, string propertyName)
{
	PropertyDescriptorCollection propertyDescriptors = TypeDescriptor.GetProperties(component);
	foreach (PropertyDescriptor propertyDescriptor in propertyDescriptors)
	{
		if (propertyDescriptor.Name == propertyName)
		{
			return propertyDescriptor;
		}
	}
	throw new ArgumentException(string.Format("The property '{0}' was not found.", propertyName));
}

Feel free to download the updated demo application: sortablebindinglist.zip. There are even real applications that use this class, eg: VSTrac and MonoTorrent. If you’re interested in the unittests you’ll have to get the code at BeTimvwFramework.