GSharper

Monday 13 August 2007

Sorting databound datagridviews

I was asked to provide sorting on a databound gridview. At first it looked easy. Just bind my generic list to the gridview and enable sorting. 

But, no can do. You cannot bind a standard generic list to a datagridview.

The solution is to create your own sortable binding list. This is the way to do it

First we create our own implementation of the list

public class SortableBindingList<T> : BindingList<T>
{
private bool _isSorted;

protected override bool SupportsSortingCore
{
get
{
return true;
}
}

protected override void ApplySortCore(
PropertyDescriptor property, ListSortDirection
direction)
{
List
<T> items = this.Items as List<T>;
if (items != null)
{
PropertyComparer
<T> pc =
new PropertyComparer<T>(property,
direction);

items.Sort(pc);
_isSorted
= true;
}
else
{
_isSorted
= false;
}

this.OnListChanged(
new ListChangedEventArgs(ListChangedType.Reset,
-1));
}

protected override bool IsSortedCore
{
get { return _isSorted; }
}
}


Now it's time to implement our own sorting algorithm using reflection



public class PropertyComparer<T> : System.Collections.Generic.IComparer<T>
{
private PropertyDescriptor _property;
private ListSortDirection _direction;

public PropertyComparer(PropertyDescriptor property,
ListSortDirection direction)
{
_property
= property;
_direction
= direction;
}

public int Compare(T col1, T col2)
{
object col1Value = GetPropertyValue(col1,
_property.Name);

object col2Value = GetPropertyValue(col2,
_property.Name);

if (_direction == ListSortDirection.Ascending)
{
return CompareAscending(col1Value,
col2Value);
}
else
{
return CompareDescending(col1Value,
col2Value);
}
}

public bool Equals(T col1, T col2)
{
return col1.Equals(col2);
}

public int GetHashCode(T obj)
{
return obj.GetHashCode();
}

private int CompareAscending(object x, object y)
{
int result;

if (x is IComparable)
{
result
= ((IComparable)x).CompareTo(y);
}
else if (x.Equals(y))
{
result
= 0;
}
else result = ((IComparable)x).CompareTo(y);

return result;
}

private int CompareDescending(object x, object y)
{
return -CompareAscending(x, y);
}

private object GetPropertyValue(T value, string
property)
{
PropertyInfo propertyInfo
=
value.GetType().GetProperty(property);

return propertyInfo.GetValue(value, null);
}
}
Now it's time to fill and bind the custom made list. lI've created this simple Person class for demonstration purposes.



dataGridView1.AutoGenerateColumns = false;

Person pers1
= new Person();
Person pers2
= new Person();
Person pers3
= new Person();
Person pers4
= new Person();

pers1.FirstName
= "Glenn";
pers2.FirstName
= "San";
pers3.FirstName
= "Yannick";
pers4.FirstName
= "Alfred";

pers1.LastName
= "Goovaerts";
pers2.LastName
= "Zodiac";
pers3.LastName
= "Smits";
pers4.LastName
= "Anvers";

pers1.Age
= 6;
pers2.Age
= 18;
pers3.Age
= 78;
pers4.Age
= 1;

pers1.BirthDate
= new DateTime(2007,1,1,12,5,4);
pers2.BirthDate
= new DateTime(2007,1, 1, 12, 5, 3);
pers3.BirthDate
= new DateTime(2007, 1, 1, 12, 5, 5);
pers4.BirthDate
= new DateTime(2005, 1, 1, 12, 5, 4);

SortableBindingList
<Person> source =
new SortableBindingList<Person>();

source.Add(pers1);
source.Add(pers2);
source.Add(pers3);
source.Add(pers4);

this.dataGridView1.DataSource = source;
dataGridView1.AutoResizeColumns();
The only thing we have to do now is to react to the column header click



private void dataGridView1_ColumnHeaderMouseClick
(
object sender, DataGridViewCellMouseEventArgs e)
{
DataGridViewColumn selectedColumn
=
dataGridView1.Columns[e.ColumnIndex];

ListSortDirection direction;

if (sortedDescending == false)
{
direction
= ListSortDirection.Descending;
sortedDescending
= true;
}
else
{
direction
= ListSortDirection.Ascending;
sortedDescending
= false;
}

dataGridView1.Sort(selectedColumn, direction);

selectedColumn.HeaderCell.SortGlyphDirection
=
direction
== ListSortDirection.Ascending ?
SortOrder.Ascending : SortOrder.Descending;
}
Hope this can help someone.                                           Greetz, G

5 Comments:

Post a Comment

Subscribe to Post Comments [Atom]



<< Home