Sorting custom collections gets a little cumbersome. In the past I have create a custom collection by subclassing ArrayList and then adding custom classes that implement IComparer. This works ok if you can pre-define all the different ways you want to sort a collection. I wanted to be able to sort custom collections on the fly in code by one or more columns in ascending or descending order.
Basically, you create an ArrayList of your custom objects, then use the ZenComparer class listed below, pass in the Propery names that you would like sorted by and viola! ex.
ex. Lets say you have a Person class with two properties FirstName and Age. You add a bunch of these objects to an ArrayList. Then you want to sort them by First Name:
al.Sort( new ZenComparer(typeof(Person), "FirstName") );
al.Sort( new ZenComparer(typeof(Person), "Age DESC") );
al.Sort( new ZenComparer(typeof(Person), "FirstName", "Age") );
Those three examples will sort the ArrayList by FirstName, then Age Descending, then FirstName and Age.
For the ZenComparer to work, the ArrayList must be homogeneous, i.e. only contain one type of object. The object you are sorting must have the Properties you specify, Properties are case-sensitive! The Properties you specify must implement IComparer, as long as you are using value types as properties i.e. int, string, bool, DateTime, you should be alright. You can specify as many search parameters as you want, and also an optional DESC for a descending sort on each Property.
Enjoy:
using System;
namespace Development
{
public class ZenComparer : System.Collections.IComparer
{
private Type _objectType;
private int[] _sortDir;
private System.Reflection.PropertyInfo[] _pi;
private static System.Collections.Comparer _comparer = System.Collections.Comparer.Default;
private static readonly string DESCENDING = " DESC";
private static readonly string ASCENDING = " ASC";
public ZenComparer( Type t, params string[] PropertyNames)
{
_objectType = t;
_pi = new System.Reflection.PropertyInfo[ PropertyNames.Length ];
_sortDir = new int[ PropertyNames.Length ];
for( int i=0; i<PropertyNames.Length; i++ )
{
string s = PropertyNames[i];
string prop = string.Empty;
if( s.ToUpper().EndsWith( DESCENDING ) )
{
_sortDir[i] = 1;
prop = s.Substring( 0, s.Length-DESCENDING.Length);
}
else if( s.ToUpper().EndsWith( ASCENDING ) )
{
_sortDir[i] = -1;
prop = s.Substring( 0, s.Length-ASCENDING.Length );
}
else
{
_sortDir[i] = -1;
prop = s;
}
_pi[i] = _objectType.GetProperty( prop );
}
}
#region IComparer Members
public int Compare(object x, object y)
{
int result = 0;
int i=0;
while( result == 0 && i<_pi.Length )
{
object vX = _pi[i].GetValue( y, null );
object vY = _pi[i].GetValue( x, null );
result = _comparer.Compare( vX, vY );
result *= _sortDir[i];
i++;
}
return result;
}
#endregion
}
}
posted @ Monday, January 31, 2005 9:07 AM