How to sort a DataBound column in a DataGridView when a column header is clicked?

I believe this should be handled automatically. I bind a DataGridView to an array of objects:

 public class Entity { public string Name { get; set; } public int PrimaryKey { get; set; } } 

Mesh Binding:

 public void BindGrid(Entity[] entities) { grdEntities.DataSource = entities; } 

When I click the column heading in the Name column, nothing happens even if the SortMode parameter SortMode set to Automatic. The sort character is also missing in the column header.

I tried to bind to IBindingList as well as IList , but that didn't work.

I hope there is a simple, elegant solution with property settings for a DataGridView or DataGridViewColumn , and not to create a new class to support sorting. What should I do to support sorting by column by clicking the header on the DataBound DataGridView ?

+3
source share
2 answers

I created a new interface based on IComparer, which allows you to specify both the column and the direction. I just did it because I need my sort code to be as general as possible - I have two lattices that need to be sorted like this, and I don't want to support the code twice. Here is the interface, quite simple:

  public interface IByColumnComparer : IComparer { string SortColumn { get; set; } bool SortDescending { get; set; } } 

Obviously, if you are not worried about keeping things common (you probably should), then this is not strictly necessary. Then I built a new class based on the BindingList <>. This allowed me to override the sort code and provide my own IByColumnComparer in a column by column, which allowed for the flexibility I needed. Check this:

 public class SortableGenericCollection<T> : BindingList<T> { IByColumnComparer GenericComparer = null; public SortableGenericCollection(IByColumnComparer SortingComparer) { GenericComparer = SortingComparer; } protected override bool SupportsSortingCore { get { return true; } } protected override bool IsSortedCore { get { for (int i = 0; i < Items.Count - 1; ++i) { T lhs = Items[i]; T rhs = Items[i + 1]; PropertyDescriptor property = SortPropertyCore; if (property != null) { object lhsValue = lhs == null ? null : property.GetValue(lhs); object rhsValue = rhs == null ? null : property.GetValue(rhs); int result; if (lhsValue == null) { result = -1; } else if (rhsValue == null) { result = 1; } else { result = GenericComparer.Compare(lhs, rhs); } if (result >= 0) { return false; } } } return true; } } private ListSortDirection sortDirection; protected override ListSortDirection SortDirectionCore { get { return sortDirection; } } private PropertyDescriptor sortProperty; protected override PropertyDescriptor SortPropertyCore { get { return sortProperty; } } protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) { sortProperty = prop; sortDirection = direction; GenericComparer.SortColumn = prop.Name; GenericComparer.SortDescending = direction == ListSortDirection.Descending ? true : false; List<T> list = (List<T>)Items; list.Sort(delegate(T lhs, T rhs) { if (sortProperty != null) { object lhsValue = lhs == null ? null : sortProperty.GetValue(lhs); object rhsValue = rhs == null ? null : sortProperty.GetValue(rhs); int result; if (lhsValue == null) { result = -1; } else if (rhsValue == null) { result = 1; } else { result = GenericComparer.Compare(lhs, rhs); } return result; } else { return 0; } }); } protected override void RemoveSortCore() { sortDirection = ListSortDirection.Ascending; sortProperty = null; } } 

EDIT . This should provide some information on how to create your own IComparer based on my interface above. The advantage of having your own IComparer based on the interface is that you can sort several columns in one direction and other columns in others (some columns may be rows and some ints, some may have special rules about what happens on top, etc. d.). Here is an example of how your IComparer might work:

 public class MyGenericComparer : IByColumnComparer { private string columnToCompare; private bool descending; public string SortColumn { get { return columnToCompare; } set { columnToCompare = value; } } public bool SortDescending { get { return descending; } set { descending = value; } } public MyGenericComparer(string column, bool descend) { columnToCompare = column; descending = descend; } public int Compare(object x, object y) { MyGenericObject firstObj = (MyGenericObject )x; MyGenericObject secondObj = (MyGenericObject )y; if (descending) { MyGenericObject tmp = secondObj ; secondObj = firstObj ; firstObj = tmp; } if (columnToCompare == "StringColumn") { //Run code to compare strings, return the appropriate int //eg, "1" if firstObj was greater, "-1" is secondObj, "0" if equal } if (columnToCompare == "IntColumn") { //Run code to compare ints, return the appropriate int //eg, "1" if firstObj was greater, "-1" is secondObj, "0" if equal } } } 

Then all you have to do is create a list with an instance of your comparator!

 public static MyGenericComparer GridComparer = new MyGenericComparer(); public static SortableGenericCollection<GenericObject> GridList = new SortableGenericCollection<GenericObject>(GridComparer); 
+5
source

Perhaps you want to look at this question: Sorting DataGridView and, for example, BindingList <T> in .NET

The basic idea is that you need to extend the BindingList<T> and override ApplySortCore to work with sorting columns.

+1
source

All Articles