The life and times of this developer...

WPF, C#, XML and other stuff

  Home  |   Contact  |   Syndication    |   Login
  23 Posts | 0 Stories | 26 Comments | 0 Trackbacks

News

Twitter












Tag Cloud


Archives

Post Categories

Cool Tools

Microsoft provide an article of the same name (previously published as Q319401) and it shows a nice class 'ListViewColumnSorter ' for sorting a standard ListView when the user clicks the column header.

This is very useful for String values, however for Numeric or DateTime data it gives odd results. E.g. 100 would come before 99 in an ascending sort as the string compare sees 1 < 9. So my challenge was to allow other types to be sorted. This turned out to be fairly simple as I just needed to create an inner class in ListViewColumnSorter which extends the .Net CaseInsensitiveComparer class, and then use this as the ObjectCompare member's type.

Note: Ideally we would be able to use IComparer as the member's type, but the Compare method is not virtual in CaseInsensitiveComparer , so we have to create an exact type:

public class ListViewColumnSorter : IComparer
{
    private CaseInsensitiveComparer ObjectCompare;
    private MyComparer ObjectCompare;

    ... rest of Microsofts class implementation...
}

Here is my private inner comparer class, note the 'new int Compare' as Compare is not virtual, and also note we pass the values to the base compare as the correct type (e.g. Decimal, DateTime) so they compare correctly:

private class MyComparer : CaseInsensitiveComparer
{
    public new int Compare(object x, object y)
    {
        try
        {
            string s1 = x.ToString();
            string s2 = y.ToString();
 
            // check for a numeric column
            decimal n1, n2 = 0;
            if (Decimal.TryParse(s1, out n1) && Decimal.TryParse(s2, out n2))
                return base.Compare(n1, n2);
            else
            {
                // check for a date column
                DateTime d1, d2;
                if (DateTime.TryParse(s1, out d1) && DateTime.TryParse(s2, out d2))
                    return base.Compare(d1, d2);
            }
        }
        catch (ArgumentException) { }
 
        // just use base string compare
        return base.Compare(x, y);
    }
}

You could extend this for other types, even custom classes as long as they support ICompare.

Microsoft also have another article How to: Sort a GridView Column When a Header Is Clicked that shows this for WPF, which looks conceptually very similar. I need to test it out to see if it handles non-string types.

#

posted on Monday, February 28, 2011 5:55 PM