如何按2列对datagridview进行排序

时间:2012-01-17 08:05:03

标签: c# winforms datagridview

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

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

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

但两个人呢?

8 个答案:

答案 0 :(得分:9)

如果您的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
}

OR,不使用bindingsource并直接绑定到DataView

private void SortDataByMultiColumns()
{
    DataView view = ds.Tables[0].DefaultView;
    view.Sort = "day ASC, status DESC"; 
    dataGridView1.DataSource = view; //rebind the data source
}

答案 1 :(得分:6)

添加一个隐藏列,它将两者结合起来并按其排序。

答案 2 :(得分:6)

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

这应该能够在当天显示您的结果,并且其状态字段也会被排序。

答案 3 :(得分:2)

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

答案 4 :(得分:0)

您可以尝试this,或使用自定义排序:

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

答案 5 :(得分:0)

John Kurtz提供的答案让我很接近。但我发现的是当我点击一次列时,确实按两列排序......在他的例子中:dgvcClicked.Name,“LastName”。好吧!!

但是,如果我再次点击该列,那么它就不会按相反的方向排序。因此该专栏陷入了升序。

为了解决这个问题,我必须手动跟踪排序顺序。从这门课开始:

public class ColumnSorting
{
    public int ColumnIndex { get; set; }
    public ListSortDirection Direction { get; set; }
}

然后,我添加了这个全局范围的List:

List<ColumnSorting> _columnSortingList = new List<ColumnSorting>();

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

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

答案 6 :(得分:0)

在处理绑定数据时,我使用此解决方案。这对我们的用户有效,并显示当前的排序标准。所有种类都只能以升序排列。

添加一个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;
        }

答案 7 :(得分:0)

这里是@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);