Code Snippet
/// <summary>
/// Default implementation of BindingList does not support sorting.
/// This class fixes that problem. However it does not support filtering.
/// </summary>
/// <typeparam name="T">Type of object that will be stored</typeparam>
public class SortableBindingList<T> : BindingList<T>
{
#region Private Variables
private bool _Sorted = false;
private PropertyDescriptor _sortProperty = null;
private ListSortDirection _sortDirection = ListSortDirection.Ascending;
#endregion
#region Constructors
public SortableBindingList() : base()
{
}
public SortableBindingList(IList<T> list)
: base(list)
{
}
#endregion
#region Sorting
/// <summary>
/// Returns whether this object supports Sorting
/// </summary>
protected override bool SupportsSortingCore
{
get { return true; }
}
/// <summary>
/// Whether the collection has been sorted.
/// </summary>
protected override bool IsSortedCore
{
get { return _Sorted; }
}
/// <summary>
/// Direction in which sorting was last performed (Ascending/Descending).
/// </summary>
protected override ListSortDirection SortDirectionCore
{
get { return _sortDirection; }
}
/// <summary>
/// Property on which the sort has been last performed
/// </summary>
protected override PropertyDescriptor SortPropertyCore
{
get { return _sortProperty; }
}
/// <summary>
/// Sort the collection.
/// </summary>
/// <param name="prop">Property on which the sort will be performed.</param>
/// <param name="direction">The direction in which the collection should be sorted.</param>
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
// Get list to sort
List<T> items = this.Items as List<T>;
// Apply and set the sort
if (items != null)
{
PropertyComparer<T> pc = new PropertyComparer<T>(prop, direction);
items.Sort(pc);
_Sorted = true;
_sortProperty = prop;
_sortDirection = direction;
// Let bound controls know they should refresh their views
//OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
else
{
_Sorted = false;
}
}
protected override void RemoveSortCore()
{
throw new NotSupportedException();
//_Sorted = false;
//this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
#endregion
}
public class PropertyComparer<T> : System.Collections.Generic.IComparer<T>
{
// The following code contains code implemented by Rockford Lhotka:
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/html/vbnet01272004.asp
private PropertyDescriptor _property;
private ListSortDirection _direction;
public PropertyComparer(PropertyDescriptor property, ListSortDirection direction)
{
_property = property;
_direction = direction;
}
#region IComparer<T>
public int Compare(T xWord, T yWord)
{
// Get property values
object xValue = GetPropertyValue(xWord, _property.Name);
object yValue = GetPropertyValue(yWord, _property.Name);
// Determine sort order
if (_direction == ListSortDirection.Ascending)
{
return CompareAscending(xValue, yValue);
}
else
{
return CompareDescending(xValue, yValue);
}
}
public bool Equals(T xWord, T yWord)
{
return xWord.Equals(yWord);
}
public int GetHashCode(T obj)
{
return obj.GetHashCode();
}
#endregion
// Compare two property values of any type
private int CompareAscending(object xValue, object yValue)
{
int result;
// If values implement IComparer
if (xValue is IComparable)
{
result = ((IComparable)xValue).CompareTo(yValue);
}
// If values don't implement IComparer but are equivalent
else if (xValue.Equals(yValue))
{
result = 0;
}
// Values don't implement IComparer and are not equivalent, so compare as string values
else result = xValue.ToString().CompareTo(yValue.ToString());
// Return result
return result;
}
private int CompareDescending(object xValue, object yValue)
{
// Return result adjusted for ascending or descending sort order ie
// multiplied by 1 for ascending or -1 for descending
return CompareAscending(xValue, yValue) * -1;
}
private object GetPropertyValue(T value, string property)
{
// Get property
PropertyInfo propertyInfo = value.GetType().GetProperty(property);
// Return value
return propertyInfo.GetValue(value, null);
}
}