views:

67

answers:

1

My DataGridView control currently sorts using the Sort property of the bound data, but it isn't doing what I want it to do.

I have a column called Employee that is displayed as "Firstname Lastname".

When I sort by Employee, Amy Z_Lastname is listed before John A_Lastname, meaning I would prefer to sort by last names.

I could break the Employee string up into 3 parts, include those in the DataTable, and set the sort to "Lastname, Firstname", then hide the Lastname and Firstname columns.

I'd rather learn how to override the default IComparer (or whatever it uses) to provide instructions on how to sort the way I want (the answer I'd prefer).

+3  A: 

Custom sorting in the DataGridView

The DataGridView knows nothing of this ranking, of course. The default sorting scenario (automatic sorting for a data-bound column) of invoking DataGridView.Sort() via a column header mouse click simply delegates to the IBindingList implementation of ApplySort() in the list you've bound to the grid. Normally, this list would be a DataView. Using my ObjectListView implementation, this would be a view of a list of arbitrary business objects. Either way, you end up comparing the properties of the items in the list using the IComparable implementation of the property type.

Details

The PropertyComparers property exposes a PropertyComparersCollection, which is a dictionary of property name keys and IComparer values. You can replace the IComparer for a property by using the PropertyComparersCollection.Add() method or the indexer (e.g. view.PropertyComparers["PropName"] = myComparer). To revert to the default IComparable sorting, use the PropertyComparersCollection.Remove() method or set the IComparer value to null via the indexer.

If an IComparer is added to the PropertyComparers collection, it will be used for all subsequent sorts until it is removed from the collection or it is replaced with another IComparer. If the ObjectListView is already sorted when an IComparer is added to or removed from PropertyComparers, the view will automatically be re-sorted.

If you want to change multiple property comparers after the view is sorted, you can use the ObjectListView BeginUpdate() and EndUpdate() methods to suppress the ListChanged and Sort events until all of the IComparers have been changed. This prevents multiple refreshes of the DataGridView. If the ObjectListView is not sorted at the time IComparers are added or removed, no automatic re-sorting is done.

Note that when sorting on multiple columns, a custom IComparer can be used with one sort property, and the default IComparable sort on another.

e.g:

private void radioButtonSortProgram_CheckedChanged(object sender, EventArgs e)

{

    if (this.radioButtonSortProgramAlpha.Checked)

        this.view.PropertyComparers["Program"] = new CustomerProgramComparerAlpha();

    else if (this.radioButtonSortProgramRank.Checked)

        this.view.PropertyComparers["Program"] = new CustomerProgramComparerRank();

    else

        this.view.PropertyComparers.Remove("Program");

}
0A0D
Please write a brief digest of the article, with code, in case of link rot. Looks like you implement IComparable, and either living with virtual mode, or using a custom list view implementation.
Merlyn Morgan-Graham
I've sent the author a question. His solution was to use the ObjectListView, but he never defines it.
jp2code
+1 w/ the digest
Merlyn Morgan-Graham
@jp2code: You may want to look at sorting before it reaches the client instead. I imagine you'll only display a certain size of results at a time (paging) so the cost really isn't that high.
0A0D
I've marked this as the answer, but I won't be able to modify my application to use this ObjectListView control for a while. If a better answer comes along before I've had a chance to implement OLV, I will change my answer. Thanks.
jp2code