Click here to Skip to main content
15,892,746 members
Articles / Programming Languages / C#

Multi Column Sorting in DataGridView

Rate me:
Please Sign up or sign in to vote.
4.42/5 (8 votes)
14 May 2011CPOL 49.7K   2K   18   4
Multi Column Sorting in DataGridView

Sorting_DataGridView/Image1.jpg

Image 1

Image 1 is the parent form, which has a datagridview control and a sort button, the sort button will pop up a ‘SortOrderForm’ which allows to input the required sort order as in Image 2. The sort button in image 2 performs the sort function in the parent form.

Sorting_DataGridView/Image2.jpg

Image 2

To implement this functionality, create a class file ‘GridRowComparer’ as follows:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DataGridViewMultiSort
{
    public class GridRowComparer : System.Collections.IComparer
    {
        private List<KeyValuePair<DataGridViewColumn, bool>> _columnList;

        public GridRowComparer(List<KeyValuePair<DataGridViewColumn, bool>> columnList)
        {
            _columnList = columnList;
        }

        public int Compare(object x, object y)
        {
            DataGridViewRow DataGridViewRow1 = ((DataGridViewRow)(x));
            DataGridViewRow DataGridViewRow2 = ((DataGridViewRow)(y));

            int CompareResult = compareResult(DataGridViewRow1, DataGridViewRow2, 0);

            return (CompareResult);
        }

        public int compareResult(DataGridViewRow DataGridViewRow1, 
			DataGridViewRow DataGridViewRow2, int i)
        {
            DataGridViewColumn dgvColumn = _columnList[i].Key;

            int sortOrderModifier = 0;
            if (_columnList[i].Value)
                sortOrderModifier = 1;
            else
                sortOrderModifier = -1;

            int CompareResult = 0;

            object value1 = DataGridViewRow1.Cells[dgvColumn.Index].Value;
            object value2 = DataGridViewRow2.Cells[dgvColumn.Index].Value;

            //Sort Images Together if images are in datagrid view
            if ((value1 is System.Drawing.Bitmap) && !(value2 is System.Drawing.Bitmap))
                return -1 * sortOrderModifier;
            else if (!(value1 is System.Drawing.Bitmap) && 
			(value2 is System.Drawing.Bitmap))
                return 1 * sortOrderModifier;
            else if (value1 is System.Drawing.Bitmap && value2 is System.Drawing.Bitmap)
                return 0;

            string cellValue1 = Convert.ToString
				(DataGridViewRow1.Cells[dgvColumn.Index].Value);
            string cellValue2 = Convert.ToString
				(DataGridViewRow2.Cells[dgvColumn.Index].Value);

            //When Cell value is null or empty
            if ((cellValue1 == null || cellValue1 == string.Empty) && 
			(cellValue2 != null || cellValue2 != string.Empty))
                return -1 * sortOrderModifier;
            else if ((cellValue1 != null || cellValue1 != string.Empty) && 
			(cellValue2 == null || cellValue2 == string.Empty))
                return 1 * sortOrderModifier;
            else if ((cellValue1 == null || cellValue1 == string.Empty) && 
			(cellValue2 == null || cellValue2 != string.Empty))
                return 0;

            //compare Numeric values
            if (dgvColumn.ValueType == typeof(Double))
            {
                double numVal1 = Convert.ToDouble(cellValue1);
                double numVal2 = Convert.ToDouble(cellValue2);

                if (numVal1 > numVal2)
                    CompareResult = 1;
                else if (numVal1 < numVal2)
                    CompareResult = -1;
                else
                    CompareResult = 0;
            }
            //compare date values
            else if (dgvColumn.ValueType == typeof(DateTime))
            {
                DateTime cellValueDt1;
                DateTime cellValueDt2;

                if ((DateTime.TryParse(cellValue1, out cellValueDt1)) && 
			(DateTime.TryParse(cellValue2, out cellValueDt2)))
                {
                    if (cellValueDt1 > cellValueDt2)
                        CompareResult = 1;
                    else if (cellValueDt1 < cellValueDt2)
                        CompareResult = -1;
                    else
                        CompareResult = 0;
                }
            }
            else //compare string values
            {
                CompareResult = System.String.Compare(cellValue1, cellValue2);
            }

            CompareResult = CompareResult * sortOrderModifier;

            //if same values, perform this routine again
            if (CompareResult == 0)
            {
                if (i != _columnList.Count - 1)
                {
                    i++;
                    CompareResult = compareResult(DataGridViewRow1, DataGridViewRow2, i);
                }
            }
            return CompareResult;
        }
    }
}

And the sort operation can be performed by passing the new sort order list as List<KeyValuePair<DataGridViewColumn, bool>> to GridRowComparer(…), where bool is to know IsAscending or not.

C#
internal void PerformSort(List<KeyValuePair<DataGridViewColumn, bool>> sortOrderList)
{
    GridRowComparer rowComparer = new GridRowComparer(sortOrderList);
    dataGridView1.Sort(rowComparer);
}

Parent Form code follows:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DataGridViewMultiSort
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //Populate the datagridview with users data
            PopulateDataGridView();
        }

        private void btnSort_Click(object sender, EventArgs e)
        {
            //get a List of all columns in the datagridview
            List<DataGridViewColumn> dgvColumns = new List<DataGridViewColumn>();
            foreach (DataGridViewColumn dgvCol in dataGridView1.Columns)
                dgvColumns.Add(dgvCol);

            //Pass the Column list to the sort Form
            using (SortColumnsForm form = new SortColumnsForm(this,dgvColumns))
            {
                if (form.ShowDialog() == DialogResult.OK)
                {
                    GridRowComparer rowComparer = 
				new GridRowComparer(form.SortOrderList);
                    dataGridView1.Sort(rowComparer);
                }
            }
        }

        /// <summary>
        /// Perform Sort fot the provided sort order list
        /// </summary>
        /// <param name="sortOrderList"></param>
        internal void PerformSort
	(List<KeyValuePair<DataGridViewColumn, bool>> sortOrderList)
        {
            GridRowComparer rowComparer = new GridRowComparer(sortOrderList);
            dataGridView1.Sort(rowComparer);
        }

        /// <summary>
        /// Populate the data
        /// </summary>
        public void PopulateDataGridView()
        {
            dataGridView1.ColumnCount = 6;

            dataGridView1.Columns[0].Name = "C0";
            dataGridView1.Columns[1].Name = "C1";
            dataGridView1.Columns[2].Name = "C2";
            dataGridView1.Columns[3].Name = "C3";
            dataGridView1.Columns[4].Name = "C4";
            dataGridView1.Columns[5].Name = "C5";

            dataGridView1.Columns[0].HeaderText = "C0";
            dataGridView1.Columns[1].HeaderText = "C1";
            dataGridView1.Columns[2].HeaderText = "C2";
            dataGridView1.Columns[3].HeaderText = "C3";
            dataGridView1.Columns[4].HeaderText = "C4";
            dataGridView1.Columns[5].HeaderText = "C5";

            dataGridView1.Columns[0].Width = 40;
            dataGridView1.Columns[1].Width = 40;
            dataGridView1.Columns[2].Width = 40;
            dataGridView1.Columns[3].Width = 40;
            dataGridView1.Columns[4].Width = 40;
            dataGridView1.Columns[5].Width = 40;

            dataGridView1.Rows.Add(new string[] { "1", "1", "1", "2", "2", "1" });
            dataGridView1.Rows.Add(new string[] { "1", "2", "1", "2", "2", "2" });
            dataGridView1.Rows.Add(new string[] { "1", "2", "2", "1", "1", "1" });
            dataGridView1.Rows.Add(new string[] { "1", "1", "2", "1", "1", "2" });
            dataGridView1.Rows.Add(new string[] { "2", "1", "2", "1", "2", "1" });
            dataGridView1.Rows.Add(new string[] { "2", "1", "2", "1", "2", "2" });
            dataGridView1.Rows.Add(new string[] { "2", "2", "1", "2", "1", "1" });
            dataGridView1.Rows.Add(new string[] { "3", "2", "1", "2", "1", "2" });
            dataGridView1.Rows.Add(new string[] { "3", "1", "1", "2", "2", "1" });

            dataGridView1.AutoResizeColumns();
        }
    }
}

Please refer to the source code if you require the code of SortOrderForm.

License

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


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

Comments and Discussions

 
QuestionVB.net conversion Pin
Member 148542602-Jul-20 5:43
Member 148542602-Jul-20 5:43 
QuestionGREEEEEEEEEEEEEEEEEEEEEEEEEEEAT Solution Pin
antleite200113-Aug-13 0:30
antleite200113-Aug-13 0:30 
GeneralMy vote of 5 Pin
remi2226-Jun-12 11:12
remi2226-Jun-12 11:12 
Very good code and view, I find it very useful. But you need to add in this article a notice which says, do not forget to define the valueType of all the cells in the DataGridView.
GeneralDataSource [modified] Pin
alegn16-May-11 22:19
alegn16-May-11 22:19 

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.