Click here to Skip to main content
15,867,330 members
Articles / Desktop Programming / Windows Forms
Article

DataGridView Multi-column Sort

Rate me:
Please Sign up or sign in to vote.
4.78/5 (16 votes)
17 Apr 2007CPOL4 min read 294.8K   10.9K   92   34
An article presenting a method of sorting a DataGridView by many columns

Screenshot - SortedGrid.gif

Introduction

Out of the box, the DataGridView only allows sorting by a single column. This article presents code that enables users to sort their data in a DataGridView by multiple columns. The DataGridView derived class may be used for any data types that support the IComparable interface (which includes all the basic .NET types).

This project was built using Visual C# 2005 Express Edition.

Using the code

Normal Code Use

Add a sorted DataGrid view to your project:

  1. Download the library using the link above and unzip the SortedDataGridView.dll somewhere convenient.
  2. Add a reference to SortedDataGridView.dll that you have just extracted to your toolbox by right-clicking the toolbox and selecting "Choose Items..." then "Browse..."
  3. The Toolbox should now show the SortedDataGridView as a new component which you can directly add to your forms and configured in the same manner as a normal DataGridView.

There is an extra property the SortedDataGridView exposes: MaxSortColumns. This is set to the maximum number of columns you allow users to sort the grid by, or 0 for no limit. I have found that sorting by more than 3 columns confusing, and tend to limit the number of columns to 3 or 4, depending on the data displayed. I find it easy to get confused when using the advanced user interface and lose track of the order of sorting.

Advanced Code Use

If you are converting an existing project to use this code then you will probably want to use this method.

Add a reference to the library SortedDataGridView.dll to your project.

Manually edit the Designer.cs or Designer.vb for your form to change the definition of your DataGridView from System.Windows.Forms.DataGridView to Mobius.Utility.SortedDataGridView. Change the instantiation of the variable in the same manner.

C#
private void InitializeComponent()
{
    this.PersonGrid = new Mobius.Utility.SortedDataGridView();
}

private Mobius.Utility.SortedDataGridView PersonGrid;

That's it, you now have a DataGridView sorted by multiple columns.

User Interface

Normal Use

To sort by columns A, B and C click on the header of the columns in reverse order, C then B then A.

Advanced Use

When using the grid I found that it was useful to be able to reverse the sort order of one of the columns without changing it's priority, so I added code to do this. It is accessible by holding down the control key.

Having sorted by A, B, C, to reverse the sort order of one of the columns click the column header while holding down the control key.

A side effect of this is that you can order by A, B, C by clicking the columns in that order while pressing the control key, because if a column is not so far sorted, it is added to the sort list.

If you have chosen to limit the number of columns that you sort by, when you click a column that is not in the sort and you are currently sorting by the maximum number of columns, the last column is replaced by the one just clicked.

Points of Interest

Interface to DataGridView

The code overrides the OnColumnHeaderMouseClick function to start the sort and the DataGridView.Sort function with a custom sort class that implements the IComparer interface.

I put as much of the functionality into the sort class as possible for two reasons:

  1. It fit better there.
  2. It keeps the DataGridView class clean.

Reason 2 means that it is a lot easier to add the functionality here to another existing DataGridView derived class.

Sort Order Description

The grid exposes a property named SortOrderDescription which returns a description of the columns sorted which is suitable for use as a tooltip for the column headers or in a status bar. The demo project shows it's use in a status bar.

Sorting

The sorting uses an IComparer derived class, DataGridComparer, that sorts by each column in turn.

The code is quite simple. Firstly I cast the object parameters from the IComparer interface, then do the comparison in a separate function:

C#
public int Compare(object x, object y)
{
    DataGridViewRow lhs = x as DataGridViewRow;
    DataGridViewRow rhs = y as DataGridViewRow;

    return Compare(lhs.Cells, rhs.Cells);
}

public int Compare(DataGridViewCellCollection lhs, DataGridViewCellCollection rhs)
{
    foreach (SortColDefn colDefn in _sortedColumns)
    {
            int retval = Comparer.Default.Compare(
            lhs[colDefn.colNum].Value,
            rhs[colDefn.colNum].Value);

        if (retval != 0)
            return (colDefn.ascending ? retval : -retval);
    }

    // These two rows are indistinguishable.
    return 0;
}

Anonymous delegate

When a column is requested by the user to be sorted, the code needs to determine if that column is already being sorted. If it is then it is promoted to be the primary sort column (in basic user interface or order swapped if using the Control key).

The structure which holds the sort order is a SortColDefn:

C#
private struct SortColDefn
{
    internal Int16 colNum;
    internal bool ascending;

    internal SortColDefn(int columnNum, SortOrder sortOrder)
    {
        colNum = Convert.ToInt16(columnNum);
        ascending = (sortOrder != SortOrder.Descending);
    }
}

The columns that are currently sorted are stored in a simple array:

C#
List<SortColDefn> _sortedColumns;

When you come to find out if a supplied column index is in the array, you could simply loop through the array and check if the SortColDefn.colNum was equal to the passed column index.

However, it's more fun to use the List.FindIndex function and an anonymous delegate:

C#
int sortPriority = _sortedColumns.FindIndex(
        delegate(SortColDefn cd) { return cd.colNum == columnIndex; });

On return, sortPriority will be -1 if the columnIndex is not found or set equal to the index into the _sortedColumns array of the SortColDefn with the same columnIndex.

History

Version 0.8 - 11 April 2007 - first release, half way there!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionNot Showing in Toolbox Pin
Member 150619931-Feb-21 11:50
Member 150619931-Feb-21 11:50 
QuestionDataGridView with VirtualMode 'TRUE' and unbounded Colums. Pin
syynapse26-Oct-12 1:52
syynapse26-Oct-12 1:52 
GeneralMy vote of 5 Pin
ProEnggSoft29-Feb-12 19:23
ProEnggSoft29-Feb-12 19:23 
GeneralThanks Pin
YZK29-Mar-11 23:56
YZK29-Mar-11 23:56 
QuestionDate Col sort not work Pin
ackid3225-Feb-11 19:57
ackid3225-Feb-11 19:57 
AnswerRe: Date Col sort not work Pin
PTA_UK26-Feb-11 2:35
PTA_UK26-Feb-11 2:35 
GeneralRe: Date Col sort not work Pin
ackid3227-Feb-11 18:02
ackid3227-Feb-11 18:02 
GeneralGreat tool Pin
bujal28-Oct-10 22:44
bujal28-Oct-10 22:44 
QuestionSort Column As Integer / Decimal Pin
daneasaur26-Apr-10 1:05
daneasaur26-Apr-10 1:05 
AnswerRe: Sort Column As Integer / Decimal Pin
PTA_UK30-Apr-10 4:30
PTA_UK30-Apr-10 4:30 
QuestionErro in Sort(_columnSorter) Pin
BenneDSant14-Apr-10 9:20
BenneDSant14-Apr-10 9:20 
AnswerRe: Erro in Sort(_columnSorter) Pin
PTA_UK30-Apr-10 4:32
PTA_UK30-Apr-10 4:32 
Generalremove all sort Pin
BenneDSant14-Apr-10 6:48
BenneDSant14-Apr-10 6:48 
GeneralRe: remove all sort Pin
PTA_UK30-Apr-10 4:09
PTA_UK30-Apr-10 4:09 
GeneralShow Sort Glyph on each sorted column Pin
general.jesiu2-Oct-09 2:53
general.jesiu2-Oct-09 2:53 
GeneralRe: Show Sort Glyph on each sorted column Pin
softboy993-Jan-11 19:10
softboy993-Jan-11 19:10 
GeneralRe: Show Sort Glyph on each sorted column Pin
PTA_UK26-Feb-11 2:31
PTA_UK26-Feb-11 2:31 
QuestionCall simple method to sort multiple columns? Pin
jwittock8427-Jul-09 3:13
jwittock8427-Jul-09 3:13 
AnswerRe: Call simple method to sort multiple columns? Pin
PTA_UK27-Jul-09 7:14
PTA_UK27-Jul-09 7:14 
GeneralRe: Call simple method to sort multiple columns? Pin
Zaav27-Jan-14 3:32
Zaav27-Jan-14 3:32 
Questionselected value Pin
pra g30-Jan-09 1:39
pra g30-Jan-09 1:39 
GeneralNot sortable columns Pin
123kadda10-Nov-08 21:48
123kadda10-Nov-08 21:48 
As it is today applications fail if we try to sort a column thats set to NotSortable, eg. ImageColumn. I fixed this by inserting this code in SortedDataGridView and the MouseClick event:

protected override void OnColumnHeaderMouseClick(DataGridViewCellMouseEventArgs e)
{
if (Columns[e.ColumnIndex].SortMode != DataGridViewColumnSortMode.NotSortable)
{
_columnSorter.SetSortColumn(e.ColumnIndex, ModifierKeys);
Sort(_columnSorter);
Columns[e.ColumnIndex].SortMode = DataGridViewColumnSortMode.Programmatic;
}
base.OnColumnHeaderMouseClick(e);
}
GeneralDatabound Grid Pin
MarcCodeMan23-Jun-08 13:03
MarcCodeMan23-Jun-08 13:03 
GeneralRe: Databound Grid Pin
MarcCodeMan23-Jun-08 13:22
MarcCodeMan23-Jun-08 13:22 
GeneralMaxSortColumns Pin
Red Flying Pig5-Jun-08 6:39
Red Flying Pig5-Jun-08 6:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.