C#:自定义排序的 DataGridView

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/435177/
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-04 03:16:22  来源:igfitidea点击:

C#: Custom sort of DataGridView

c#sortingdatagridviewdataview

提问by Svish

I need to sort a DataGridView with Natural Sorting (Like in Explorer) so that numbers and text (in the same column) are sorted naturally, and not alphabetically (so that "place 3" comes before "place 20", etc.). I have a DataGridView, where I have set a DataView as DataSource. The DataView contains a DataTable which is created with some values from a database. The column types are string. I have an IComparer, which does what it should, but I can't figure out how to use it, cause I can't find out how to do the sorting. The DataGridView.SortCompare event, which would be perfect, doesn't work since it is databound. The DataView.Sort, only accept strings with column names and sort orders.

我需要使用自然排序(如在资源管理器中)对 DataGridView 进行排序,以便数字和文本(在同一列中)自然排序,而不是按字母顺序排序(因此“位置 3”在“位置 20”之前,等等)。我有一个 DataGridView,我在其中将 DataView 设置为 DataSource。DataView 包含一个 DataTable,它是用数据库中的一些值创建的。列类型是字符串。我有一个 IComparer,它可以做它应该做的事情,但我不知道如何使用它,因为我无法找到如何进行排序。完美的 DataGridView.SortCompare 事件不起作用,因为它是数据绑定的。DataView.Sort,只接受带有列名和排序顺序的字符串。

Very annoying. Tried to read related issues here on StackOverflow, and searched google lots and lots, but I can't really find much about this. Only stuff I really find is using that Sort(string) method of the dataview, which wont work, since it sorts alphabetically.

很烦人。试图在 StackOverflow 上阅读相关问题,并在谷歌上搜索了很多,但我真的找不到太多关于这个的信息。我真正找到的唯一东西是使用数据视图的 Sort(string) 方法,该方法不起作用,因为它按字母顺序排序。

Does anyone know how to do this without too much trouble? It got to be others than me struggeling with this? I really don't want to re-implement the whole datagridview or dataview classes, just to get custom sorting...

有谁知道如何在没有太多麻烦的情况下做到这一点?一定是除了我之外的其他人在为此苦苦挣扎吗?我真的不想重新实现整个 datagridview 或 dataview 类,只是为了获得自定义排序...

Update: In case someone were wondering, I'm still looking for a good answer to this problem. Although in the mean time, I ended up creating my own simple table class, and then feed that into a datagridview manually. Overriding the SortCompare method. Bit annoying, but wasn't too hard, since I only need to show values (no editing or anything) and therefore could convert everything to strings.

更新:万一有人想知道,我仍在寻找这个问题的好答案。虽然与此同时,我最终创建了自己的简单表类,然后手动将其输入到 datagridview 中。覆盖 SortCompare 方法。有点烦人,但并不太难,因为我只需要显示值(无需编辑或任何内容),因此可以将所有内容转换为字符串。

回答by d4nt

Take a look at this MSDN pageand this blog post. In principle, you need to configure the sorting at the data source (whether its an ObjectDataSource or a SqlDataSource) not at the GridView.

看看这个 MSDN 页面这个博客文章。原则上,您需要在数据源(无论是ObjectDataSource还是SqlDataSource)而不是GridView配置排序。

As far as I can tell the DataView class doesn't support anything other than a simple ascending/decending sort. Without seeing the code where you load and bind the data it's hard to make a specific recommendation, but you could either:

据我所知,除了简单的升序/降序排序之外,DataView 类不支持任何其他内容。如果没有看到加载和绑定数据的代码,就很难提出具体建议,但您可以:

  1. Load your data into a List instead of a DataTable, call the Sort method passing in your comparison method and then bind to that list.
  2. Create an ObjectDataSource in your aspx code that gets the data directly from a class, and configure that ObjectDataSource to use your IComparer.
  1. 将数据加载到 List 而不是 DataTable 中,调用传入比较方法的 Sort 方法,然后绑定到该列表。
  2. 在直接从类中获取数据的 aspx 代码中创建一个 ObjectDataSource,并将该 ObjectDataSource 配置为使用您的 IComparer。

回答by d4nt

You can create 2 hidden columns. Assign the text part to the 1st hidden column and the number part to the 2nd hidden column. Now sort by these hidden columns (alpha sort for 1st column & numeric sort for the 2nd column).

您可以创建 2 个隐藏列。将文本部分分配给第一个隐藏列,将数字部分分配给第二个隐藏列。现在按这些隐藏列排序(第一列的 alpha 排序和第二列的数字排序)。

In this way, you can retain the original column for display purposes & have the 2 hidden columns for sorting.

通过这种方式,您可以保留原始列用于显示目的并使用 2 个隐藏列进行排序。

回答by Kalgonti

Here there is some solution "Custom Sorting Using the SortCompare Event" and "Custom Sorting Using the IComparer Interface":

这里有一些解决方案“使用 SortCompare 事件进行自定义排序”和“使用 IComparer 接口进行自定义排序”:

http://msdn.microsoft.com/en-us/library/ms171608.aspx

http://msdn.microsoft.com/en-us/library/ms171608.aspx

回答by Jeson Martajaya

This code should work. It is similar to ListView's ListViewItemSorter. Using IComparer.

这段代码应该可以工作。它类似于 ListView 的 ListViewItemSorter。使用 IComparer。

To use:

使用:

private void dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
    MyDataGridHelper.DataGridSort(dgv, e.ColumnIndex);
}

MyDataGridHelper.cs:

MyDataGridHelper.cs:

public class MyDataGridHelper
{
    public static void DataGridSort(DataGridView dgv, int column)
    {
        DataGridViewCustomSorter dgvSorter = null;
        if (dgv.Tag == null || !(dgv.Tag is IComparer))
        {
            dgvSorter = new DataGridViewCustomSorter(dgv);
            dgv.Tag = dgvSorter;
        }
        else
        {
            dgvSorter = (DataGridViewCustomSorter)dgv.Tag;
        }
        dgvSorter.SortColumn = column;
        dgv.Sort(dgvSorter);
    }

    private class DataGridViewCustomSorter : IComparer
    {
        private int ColumnIndex;
        private SortOrder OrderOfSort;
        private DataGridView myDataGridView;
        private TypeCode mySortTypeCode;

        public DataGridViewCustomSorter(DataGridView dgv)
        {
            myDataGridView = dgv;
            mySortTypeCode = Type.GetTypeCode(Type.GetType("System.String"));
            ColumnIndex = 0;
            OrderOfSort = SortOrder.None;
        }

        public int Compare(object x, object y)
        {
            int result;
            DataGridViewRow dgvX, dgvY;

            dgvX = (DataGridViewRow)x;
            dgvY = (DataGridViewRow)y;
            string sx = dgvX.Cells[ColumnIndex].Value.ToString();
            string sy = dgvY.Cells[ColumnIndex].Value.ToString();

            //null handling
            if (sx == String.Empty && sy == String.Empty)
                result = 0;
            else if (sx == String.Empty && sy != String.Empty)
                result = -1;
            else if (sx != String.Empty && sy == String.Empty)
                result = 1;
            else
            {
                switch (mySortTypeCode)
                {
                    case TypeCode.Decimal:
                        Decimal nx = Convert.ToDecimal(sx);
                        Decimal ny = Convert.ToDecimal(sy);
                        result = nx.CompareTo(ny);
                        break;
                    case TypeCode.DateTime:
                        DateTime dx = Convert.ToDateTime(sx);
                        DateTime dy = Convert.ToDateTime(sy);
                        result = dx.CompareTo(dy);
                        break;
                    case TypeCode.String:
                        result = (new CaseInsensitiveComparer()).Compare(sx, sy);
                        break;
                    default:
                        result = (new CaseInsensitiveComparer()).Compare(sx, sy);
                        break;
                }
            }
            if (OrderOfSort == SortOrder.Descending)
                result = (-result);

            return result;
        }

        public int SortColumn
        {
            set
            {
                if (ColumnIndex == value)
                {
                    OrderOfSort = (OrderOfSort == SortOrder.Descending ? SortOrder.Ascending : SortOrder.Descending);
                }
                ColumnIndex = value;
                try
                {
                    mySortTypeCode = Type.GetTypeCode(Type.GetType((myDataGridView.Columns[ColumnIndex]).Tag.ToString()));
                }
                catch
                {
                    mySortTypeCode = TypeCode.String;
                }
            }
            get { return ColumnIndex; }
        }

        public SortOrder Order
        {
            set { OrderOfSort = value; }
            get { return OrderOfSort; }
        }
    } //end class DataGridViewCustomSorter
} //end class MyDataGridHelper

回答by Warren Blumenow

You could move the sort logic into your database query and have it return an additional column which had the correct sort order.

您可以将排序逻辑移到您的数据库查询中,并让它返回一个具有正确排序顺序的附加列。

Then (along the lines of @True C Sharp's answer) you could have a hidden column containing this value and sort by this rather than by the display column.

然后(沿着@True C Sharp 的回答)你可以有一个包含这个值的隐藏列,并按这个而不是按显示列排序。

This assumes that the logic for determining the sort order can be performed in SQL. This may not work if the algorithm for determining the sort order is complex.

这假设确定排序顺序的逻辑可以在 SQL 中执行。如果用于确定排序顺序的算法很复杂,这可能不起作用。