【问题标题】:how to sort a datagridview by 2 columns如何按 2 列对 datagridview 进行排序
【发布时间】:2012-02-12 01:34:57
【问题描述】:

如何按两列(升序)对 DataGridView 进行排序?我有两列:daystatus

如果我需要按一列排序,我会这样做:

this.dataGridView1.Sort (this.dataGridView1.Columns["day"], ListSortDirection.Ascending);

但是两个人呢?

【问题讨论】:

标签: c# winforms datagridview


【解决方案1】:

如果您的DataGridView 是数据绑定的,您可以对您的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
}

【讨论】:

  • dataGridView1.DataSource = ds.Tables[0];
  • @user1112847 我不明白..如果您问是否代替 bindingSource1 您的 ds.Tables[0] 代码可以正常工作,那么是的,我认为应该可以正常工作..
【解决方案2】:

添加一个将两者结合起来的隐藏列并按此排序。

【讨论】:

  • 这是一个好主意,但如果您想对一列 asc 和另一列进行 desc 排序,则不会工作。
【解决方案3】:

您可以使用 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 为“Programmatic”的列中调用它:

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 有助于跟踪进入的顺序。可以进一步增强这一点,以记住最后点击的两列并按所需顺序对它们进行排序。

【讨论】:

  • 这应该是答案
  • 再想一想...我无法让它工作。我第一次点击一列时它会排序,(升序)但如果我再次点击它就不会降序
  • 这个答案让我如此接近!我添加了一个基于此答案的新答案,并解决了单击列时无法在升序和降序之间切换的问题。
  • 看起来很有希望,但不幸的是,这似乎不适用于数据绑定的 datagridview 控件。
【解决方案4】:

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);

这应该能够按天显示您的结果,其状态字段也已排序。

【讨论】:

  • 如果您的示例中有值 testimg2.css 似乎它不会工作
  • 这不起作用。结果是网格将按最后一次排序操作进行排序。第一次排序操作被第二次完全抹杀。
【解决方案5】:

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>();

然后,在进行排序的方法中,我会

  1. 检查正在排序的列索引是否已存在于 _columnSortingList 中。如果没有,请添加它。
  2. 如果已经存在,则交换排序顺序

鲍勃是你的叔叔。

【讨论】:

    【解决方案6】:

    你可以试试this,或者使用自定义排序:

    private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
            {
                if (dataGridView1.Columns[e.ColumnIndex].HeaderText =="day")
                {
                   myBindingSource.Sort = "day, hour";
                }
            }
    

    【讨论】:

    • dataGridView1.DataSource = ds.Tables[0];
    • ds.Tables[0].DefaultView.Sort = "天,小时";
    【解决方案7】:

    我在处理绑定数据时使用此解决方案。这适用于我们的用户,并显示当前的排序标准。所有排序仅按升序排列。

    添加一个 CheckBox、一个 TextBox、一个 ColumnHeaderMouseClick 事件和代码,如图所示。 CheckBox 将切换 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;
            }
    
    

    【讨论】:

      【解决方案8】:

      这是对来自@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);
      

      【讨论】:

        猜你喜欢
        • 2016-04-08
        • 1970-01-01
        • 2012-05-10
        • 1970-01-01
        • 1970-01-01
        • 2012-04-27
        • 1970-01-01
        • 1970-01-01
        • 2015-12-03
        相关资源
        最近更新 更多