How do I sort a DataGridView by two columns (ascending)? I have two columns: day and status.
If I need to sort by one column, I do:
Here is a refinement on the IComparer class from @John Kurtz, which supports mutliple columns and sorting by numbers or dates.
public static void SortOnMultipleColumns(DataGridView dgv, Dictionary sortingColumns)
{
// Show the glyphs
foreach (DataGridViewColumn col in dgv.Columns)
{
System.Windows.Forms.SortOrder sortOrder = System.Windows.Forms.SortOrder.None;
foreach (var kvp in sortingColumns)
{
if (kvp.Key == col.Name)
{
sortOrder = kvp.Value.SortOrder;
break;
}
}
col.HeaderCell.SortGlyphDirection = sortOrder;
}
// Sort the grid
MultiColumnCompararor multiColumnCompararor = new MultiColumnCompararor(sortingColumns);
dgv.Sort(multiColumnCompararor);
}
public class ColumnSortInfo
{
public enum ValueConversion { ToString, ToNumber, ToDate}
public ColumnSortInfo(System.Windows.Forms.SortOrder sortOrder, ValueConversion valueConversion = ValueConversion.ToString)
{
SortOrder = sortOrder;
MyValueConversion = valueConversion;
SortOrderMultiplier = (SortOrder == SortOrder.Ascending) ? 1 : -1;
}
public System.Windows.Forms.SortOrder SortOrder { get; set; }
public int SortOrderMultiplier { get; }
public ValueConversion MyValueConversion { get; set; }
public static double StringToDouble(string sVal)
{
if (Double.TryParse(sVal, out double dVal))
{
return dVal;
}
return 0;
}
public static DateTime StringToDateTime(string sVal)
{
if (DateTime.TryParse(sVal, out DateTime dt))
{
return dt;
}
return DateTime.MinValue;
}
}
private class MultiColumnCompararor : System.Collections.IComparer
{
IDictionary _sortingColumns;
public MultiColumnCompararor(IDictionary sortingColumns)
{
_sortingColumns = sortingColumns;
}
public int Compare(object x, object y)
{
try
{
DataGridViewRow r1 = (DataGridViewRow)x;
DataGridViewRow r2 = (DataGridViewRow)y;
foreach (var kvp in _sortingColumns)
{
string colName = kvp.Key;
ColumnSortInfo csi = kvp.Value;
string sVal1 = r1.Cells[colName].Value?.ToString().Trim()??"";
string sVal2 = r2.Cells[colName].Value?.ToString().Trim()??"";
int iCompareResult = 0;
switch (csi.MyValueConversion)
{
case ColumnSortInfo.ValueConversion.ToString:
iCompareResult = String.Compare(sVal1, sVal2);
break;
case ColumnSortInfo.ValueConversion.ToNumber:
double d1 = ColumnSortInfo.StringToDouble(sVal1);
double d2 = ColumnSortInfo.StringToDouble(sVal2);
iCompareResult = ((d1 == d2) ? 0 : ((d1 > d2) ? 1 : -1));
break;
case ColumnSortInfo.ValueConversion.ToDate:
DateTime dt1 = ColumnSortInfo.StringToDateTime(sVal1);
DateTime dt2 = ColumnSortInfo.StringToDateTime(sVal2);
iCompareResult = ((dt1 == dt2) ? 0 : ((dt1 > dt2) ? 1 : -1));
break;
default:
break;
}
iCompareResult = csi.SortOrderMultiplier * iCompareResult;
if (iCompareResult != 0) { return iCompareResult; }
}
return 0;
}
catch (Exception ex)
{
return 0;
}
}
}
Usage:
Dictionary sortingColumns = new Dictionary
{ {"policyNumber", new ColumnSortInfo(System.Windows.Forms.SortOrder.Ascending)},
{"MessageId", new ColumnSortInfo(System.Windows.Forms.SortOrder.Descending, ColumnSortInfo.ValueConversion.ToNumber)},
{"CreationDate", new ColumnSortInfo(System.Windows.Forms.SortOrder.Ascending, ColumnSortInfo.ValueConversion.ToDate)}};
CsUtils.SortOnMultipleColumns(dgv, sortingColumns);