[英]how to sort a datagridview by 2 columns
如何按兩列(升序)對 DataGridView 進行排序? 我有兩列: day
和status
。
如果我需要按一列排序,我會這樣做:
this.dataGridView1.Sort (this.dataGridView1.Columns["day"], ListSortDirection.Ascending);
但是兩個人呢?
如果您的DataGridView
是數據綁定的,您可以對您的Datatable
視圖進行排序並重新綁定到Datatable
,如下所示:
private DataGridView dataGridView1 = new DataGridView();
private BindingSource bindingSource1 = new BindingSource();
private void Form1_Load(object sender, System.EventArgs e)
{
// Bind the DataGridView to the BindingSource
dataGridView1.DataSource = bindingSource1;
SortDataByMultiColumns(); //Sort the Data
}
private void SortDataByMultiColumns()
{
DataView view = dataTable1.DefaultView;
view.Sort = "day ASC, status DESC";
bindingSource1.DataSource = view; //rebind the data source
}
或者,不使用 bindingsource 並直接綁定到DataView
:
private void SortDataByMultiColumns()
{
DataView view = ds.Tables[0].DefaultView;
view.Sort = "day ASC, status DESC";
dataGridView1.DataSource = view; //rebind the data source
}
添加一個隱藏列,將兩者結合起來並按此排序。
您可以使用 DataGridView 的 Sort 方法,但指定一個參數,該參數是實現 IComparer 的類的實例。
下面是一個這樣的類的例子:
public class MyTwoColumnComparer : System.Collections.IComparer
{
private string _SortColumnName1;
private int _SortOrderMultiplier1;
private string _SortColumnName2;
private int _SortOrderMultiplier2;
public MyTwoColumnComparer(string pSortColumnName1, SortOrder pSortOrder1, string pSortColumnName2, SortOrder pSortOrder2)
{
_SortColumnName1 = pSortColumnName1;
_SortOrderMultiplier1 = (pSortOrder1 == SortOrder.Ascending) ? 1 : -1;
_SortColumnName2 = pSortColumnName2;
_SortOrderMultiplier2 = (pSortOrder2 == SortOrder.Ascending) ? 1 : -1;
}
public int Compare(object x, object y)
{
DataGridViewRow r1 = (DataGridViewRow)x;
DataGridViewRow r2 = (DataGridViewRow)y;
int iCompareResult = _SortOrderMultiplier1 * String.Compare(r1.Cells[_SortColumnName1].Value.ToString(), r2.Cells[_SortColumnName1].Value.ToString());
if (iCompareResult == 0) iCompareResult = _SortOrderMultiplier2 * String.Compare(r1.Cells[_SortColumnName2].Value.ToString(), r2.Cells[_SortColumnName2].Value.ToString());
return iCompareResult;
}
}
現在,我們可以在單擊鼠標時從 SortMode 為“程序化”的列中調用它:
private void dgvAllMyEmployees_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
DataGridViewColumn dgvcClicked = dgvAllEmployees.Columns[e.ColumnIndex];
if (dgvcClicked.SortMode == DataGridViewColumnSortMode.Programmatic)
{
_SortOrder = (_SortOrder == SortOrder.Ascending) ? SortOrder.Descending : SortOrder.Ascending;
MyTwoColumnComparer Sort2C = new MyTwoColumnComparer(dgvcClicked.Name, _SortOrder, "LastName", SortOrder.Ascending);
dgvAllEmployees.Sort(Sort2C);
}
}
類級別變量 _SortOrder 有助於跟蹤進入的順序。可以進一步增強這一點,以記住單擊的最后兩列並按所需順序對它們進行排序。
TLDR; 我有一個兩行解決方案。
我不得不做同樣的事情,但在研究了所有這些復雜的方法來做到這一點后,要么包含一個單獨的 .dll,要么編寫我自己的類/方法,我知道必須有一個更簡單的方法。 事實證明我是對的,因為我想出了如何僅使用兩行代碼來完成此任務。 這對我有用。
幸運的是,事實證明 .NET Framework Sort() 方法確實可以幫助我們解決這個問題。 這個想法是您想要單獨對列進行排序,但是您對它們進行排序的順序將產生所需的輸出。
因此,作為示例,我有一個文件類型列和一個文件名列。 每當我想按類型對數據進行排序時,我想確保名稱也在顯示的每種類型中排序。
目標:按類型排序還將按字母順序對文件名進行排序。
數據:
zxcv.css
testimg3.jpg
asdf.html
testimg2.jpg
testimg1.jpg
按名稱排序數據:
mConflictsDataGridView.Sort(mConflictsDataGridView.Columns[mNameLabel.Index], ListSortDirection.Ascending);
asdf.html
testimg1.jpg
testimg2.jpg
testimg3.jpg
zxcv.css
如您所見,這將確保名稱將相應地排序,這樣當我現在按文件類型排序時,這兩個要求都將滿足。
按文件類型對數據進行排序:
mConflictsDataGridView.Sort(mConflictsDataGridView.Columns[mFileExtensionLabel.Index], ListSortDirection.Ascending);
zxcv.css
asdf.html
testimg1.jpg
testimg2.jpg
testimg3.jpg
瞧! 整理好了!
解決方案:在您的情況下,您可能想要嘗試類似以下內容,並且您可能需要對其進行更多調整以使其適合您自己的代碼。
DataGridView1.Sort(DataGridView1.Columns["status"], ListSortDirection.Ascending);
DataGridView1.Sort(DataGridView1.Columns["day"], ListSortDirection.Asscending);
這應該能夠按天顯示您的結果,其狀態字段也已排序。
John Kurtz 提供的答案讓我很接近。 但我發現當我點擊一列時,它確實按兩列排序......在他的例子中:dgvcClicked.Name,“LastName”。 這么好!!
但是,如果我再次單擊該列,則它不會按相反的方向排序。 因此,該列卡在 Ascending 中。
為了克服這個問題,我不得不手動跟蹤排序順序。 從這個類開始:
public class ColumnSorting
{
public int ColumnIndex { get; set; }
public ListSortDirection Direction { get; set; }
}
然后,我添加了這個全局范圍的列表:
List<ColumnSorting> _columnSortingList = new List<ColumnSorting>();
然后,在進行排序的方法中,我會
而鮑勃是你的叔叔。
我在處理綁定數據時使用此解決方案。 這適用於我們的用戶,並顯示當前的排序標准。 所有排序僅按升序排列。
添加一個 CheckBox、一個 TextBox、一個 ColumnHeaderMouseClick 事件和代碼,如圖所示。 CheckBox 將切換 TextBox 的可見性,單擊任何列標題會將排序條件添加到 TextBox。 要清除 TextBox,只需雙擊它。
private void FooDataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if(chkMultiSort.Checked == true)
{
string columnHeader = FooDataGridView.Columns[e.ColumnIndex].DataPropertyName;
txtMultiSort.Text += (columnHeader + ", ");
try
{
FooBindingSource.Sort = txtMultiSort.Text.Remove(txtMultiSort.Text.Length - 2);
}
catch
{
MessageBox.Show("Invalid Sort Data", "Information", MessageBoxButtons.OK, MessageBoxIcon.None);
txtMultiSort.Text = String.Empty;
}
}
}
private void ChkMultiSort_CheckedChanged(object sender, EventArgs e)
{
if(chkMultiSort.Checked == true)
{
txtMultiSort.Visible = true;
}
else
{
txtMultiSort.Visible = false;
txtMultiSort.Text = String.Empty;
}
}
private void TxtMultiSort_DoubleClick(object sender, EventArgs e)
{
txtMultiSort.Text = String.Empty;
}
這是@John Kurtz 對 IComparer 類的改進,它支持多列並按數字或日期排序。
public static void SortOnMultipleColumns(DataGridView dgv, Dictionary<string /*Column Name*/, ColumnSortInfo> 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<string /*Column Name*/, ColumnSortInfo> _sortingColumns;
public MultiColumnCompararor(IDictionary<string /*Column Name*/, ColumnSortInfo> 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;
}
}
}
用法:
Dictionary<String, ColumnSortInfo> sortingColumns = new Dictionary<String, ColumnSortInfo>
{ {"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);
你可以試試這個,或者使用自定義排序:
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].HeaderText =="day")
{
myBindingSource.Sort = "day, hour";
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.