C# 如何按 2 列对 datagridview 进行排序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8891390/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 04:59:18  来源:igfitidea点击:

how to sort a datagridview by 2 columns

c#winformsdatagridview

提问by user1112847

How do I sort a DataGridView by two columns (ascending)? I have two columns: dayand status.

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

If I need to sort by one column, I do:

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

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

But for two?

但是两个人呢?

采纳答案by VS1

If your DataGridViewis databound, you can sort your Datatableview and rebind to datatable as below:

如果您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, without using bindingsource and binding directly to DataView:

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

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

回答by pistipanko

You can try this, or use custom sorting:

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

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

回答by linkerro

Add a hidden column that combines the two and sort by that.

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

回答by susieloo_

TLDR; I have a two-line solution.

TLDR;我有一个两行解决方案。

I had to do the same thing, but after researching all these complicated ways to do this by either including a separate .dll or writing my own class/methods, I knew there had to be an easier way. It turns out I was right because I figured out how to accomplish this with using only two lines of code. This worked for me.

我不得不做同样的事情,但在研究了所有这些复杂的方法来做到这一点后,要么包含一个单独的 .dll,要么编写我自己的类/方法,我知道必须有一个更简单的方法。事实证明我是对的,因为我想出了如何仅使用两行代码来完成此任务。这对我有用。

Luckily, it turns out for us that the .NET Framework Sort() method does help us with this. The idea is that you want to sort the columns individually, but the order in which you sort them in is what will produce the desired output.

幸运的是,事实证明 .NET Framework Sort() 方法确实可以帮助我们解决这个问题。这个想法是您想要单独对列进行排序,但是您对它们进行排序的顺序将产生所需的输出。

So, as an example, I have a column for file type and a column for a file name. Whenever I want to sort the data by the types, I want to make sure that the names are also sorted within each type shown.

因此,作为示例,我有一个文件类型列和一个文件名列。每当我想按类型对数据进行排序时,我都想确保名称也在显示的每种类型中排序。

GOAL:Sorting by type will also sort the file names alphabetically.

目标:按类型排序还将按字母顺序对文件名进行排序。

Data:

数据:

zxcv.css

testimg3.jpg

asdf.html

testimg2.jpg

testimg1.jpg

zxcv.css

testimg3.jpg

asdf.html

testimg2.jpg

testimg1.jpg

Sorting data by name:

按名称排序数据:

mConflictsDataGridView.Sort(mConflictsDataGridView.Columns[mNameLabel.Index], ListSortDirection.Ascending);

asdf.html

testimg1.jpg

testimg2.jpg

testimg3.jpg

zxcv.css

asdf.html

testimg1.jpg

testimg2.jpg

testimg3.jpg

zxcv.css

As you can see, this will name sure that the names will be sorted accordingly, such that when I now sort by the file types, both requirements will satisfy.

如您所见,这将确保名称将相应地排序,这样当我现在按文件类型排序时,这两个要求都将满足。

Sorting data by file type:

按文件类型对数据进行排序:

mConflictsDataGridView.Sort(mConflictsDataGridView.Columns[mFileExtensionLabel.Index], ListSortDirection.Ascending);

zxcv.css

asdf.html

testimg1.jpg

testimg2.jpg

testimg3.jpg

zxcv.css

asdf.html

testimg1.jpg

testimg2.jpg

testimg3.jpg

Voila! It's sorted!

瞧!整理好了!

SOLUTION:In your case, you may want to try something like the following, and you may need to tweak it some more to have it cater to your own code.

解决方案:在您的情况下,您可能想要尝试类似以下内容,并且您可能需要对其进行更多调整以使其适合您自己的代码。

DataGridView1.Sort(DataGridView1.Columns["status"], ListSortDirection.Ascending);
DataGridView1.Sort(DataGridView1.Columns["day"], ListSortDirection.Asscending);

This should be able to display your results by the day with its status field sorted as well.

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

回答by John Kurtz

You can use the DataGridView's Sort method, but specify an argument that is an instance of a class that implements IComparer.

您可以使用 DataGridView 的 Sort 方法,但指定一个参数,该参数是实现 IComparer 的类的实例。

Here is an example of such a class:

下面是一个这样的类的例子:

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

Now, we might call this from a column whose SortMode is 'Programmatic' on a mouse click:

现在,我们可以在单击鼠标时从 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);
    }
}

The class level variable _SortOrder helps keep track of which order to go in. One can enhance this more to remember the last two columns clicked and sort on them in the desired order.

类级别变量 _SortOrder 有助于跟踪进入的顺序。可以进一步增强这一点,以记住单击的最后两列并按所需顺序对它们进行排序。

回答by Casey Crookston

The answer that John Kurtz provided got me close. But what I found was the when I clicked on a column once, it did indeed sort by the two columns ... In his example: dgvcClicked.Name, "LastName". So, good!!

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

But, if I clicked on the column again, then it would NOT sort by the opposite direction. So the column became stuck in Ascending.

但是,如果我再次单击该列,则它不会按相反的方向排序。因此,该列卡在 Ascending 中。

To overcome this, I had to track the sort order manually. Started with this class:

为了克服这个问题,我不得不手动跟踪排序顺序。从这个类开始:

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

Then, I added this globally scoped List:

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

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

Then, in the method that does the Sort, I would

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

  1. Check to see if the column index being sorted already exists in _columnSortingList. If not, add it.
  2. If it already exists, then swap the sort order
  1. 检查要排序的列索引是否已存在于 _columnSortingList 中。如果没有,请添加它。
  2. 如果已经存在,则交换排序顺序

And Bob's your uncle.

而鲍勃是你的叔叔。

回答by Scotjo

I use this solution when working with bound data. This works for our users, and displays the current sort criteria. All sorts are only in ascending order.

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

Add a CheckBox, a TextBox, a ColumnHeaderMouseClick event, and code as shown. The CheckBox will toggle the TextBox's visibility, and clicking on any column header will add the sort criteria to the TextBox. To clear the TextBox, just double click in it.

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