65.9K
CodeProject is changing. Read more.
Home

Multi Column Sorting in DataGridView

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.42/5 (8 votes)

May 14, 2011

CPOL
viewsIcon

50635

downloadIcon

2035

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:

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.

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

Parent Form code follows:

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.