One of the things I wanted to achieve in Crystal Toolkit release 74 was the ability to sort my generic List<> of images (CrystalImageItem objects). I needed to be able to sort on many different properties within CrystalImageItem, and also to sort in ascending or descending order. Realizing that I probably needed to implement IComparer and IComparable, I decided that was way too much work, and my XBox Achivements score is really ridiculously low. A Google search on the topic lead me to this CodeProject article by Johannes Hansen on Dynamic List sorting. I found his approach intriguing, because he uses Reflection to key on properties within an object and use them as the basis for a compare operation. The resulting sort times are impressive, though I saw a couple of glitches reported on the CodeProject message board. Luckily, another programmer (Marc Brooks) took up the baton and released a C# library that includes a new, improved DynamicComparer. I highly recommend downloading Marc's library as it contains some nifty C# utilities.
Getting DynamicComparer to work was very easy. First, I had to make sure that the properties within the CrystalImageItem object were public, so that Reflection could find them. No problem there, I had four properties, two strings and two dates within CrystalImageItem:
public class CrystalImageItem { public string ImageName ... public string ImageFormatString ... public DateTime LastWriteTime ... public DateTime CreationTime ...
To make it convenient to specify which property I wanted to sort, I created an enumerator called CrystalSortType:
public enum CrystalSortType { ImageName = 0, ImageType = 1, CreationTime = 2, LastWriteTime = 3 }
The CrystalFileCollector is the controller class that manages a CrystalImageGridView and a CrystalImageGridModel. I created a public method called SortCrystalList, which takes a CrystalSortType enumerator, a boolean to indicate ascending or descending sort, and a boolean that tells the controller to redraw the grid (inside CrystalImageGridView) when the sort is completed:
public virtual void SortCrystalList(CrystalSortType sortType, bool ascendingOrder, bool reDrawGrid)
The protected SortCrystalList method translates the enumerator key to a string and calls a final overloaded method:
protected virtual void SortCrystalList(CrystalSortType sortType, bool ascendingOrder) { string orderBy = string.Empty; switch (sortType) { case CrystalSortType.ImageName: orderBy = "ImageName"; break; case CrystalSortType.ImageType: orderBy = "ImageFormatString"; break; case CrystalSortType.CreationTime: orderBy = "CreationTime"; break; case CrystalSortType.LastWriteTime: orderBy = "LastWriteTime"; break; } SortCrystalList(orderBy, ascendingOrder); }
The last version of SortCrystalList takes the string key, adds either ASC or DESC to the string (for ascending or descending sort) and creates the DynamicComparer. The List<CrystalImageItem> object inside the GridModel is sorted according to this key:
protected virtual void SortCrystalList(string orderBy, bool ascendingOrder) { if (_gridModel == null) return; if (ascendingOrder) orderBy += " ASC"; else orderBy += " DESC"; // Create the comparer for Person types and define // the sort fields. DynamicComparer<CrystalImageItem> comparer = new DynamicComparer<CrystalImageItem>(orderBy); // Sort the list. _gridModel.CrystalImageList.Sort(comparer.Compare); }
By default, CrystalFileCollector sorts the internal list by the ImageName property in CrystalImageItem. When the dynamic comparer object is created, the orderBy key looks like "ImageName ASC". If you read Johannes article, you will see that properties can be combined for more interesting sorts like "FirstName, LastName ASC". This is rather like doing a query on your objects, and so far the performance has been really good. You can naturally see that the Linq Project is going to make this sort of thing obsolete, but kudos to Johannes for coming up with this way back in December 2005.



Leave a comment