C#:DataGridView 的自定义排序

发布于 2024-07-10 20:19:12 字数 763 浏览 7 评论 0原文

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

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

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

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

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.

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.

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...

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

爱人如己 2024-07-17 20:19:13

查看此 MSDN 页面 和 < a href="http://2000mph.blogspot.com/2008/11/sorting-and-paging-gridview-with-custom.html" rel="nofollow noreferrer">这篇博文。 原则上,您需要在数据源(无论是 ObjectDataSource 还是 SqlDataSource)而不是 GridView 处配置排序。

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

  1. 将数据加载到列表而不是 DataTable 中,调用传入比较方法的 Sort 方法,然后绑定到该列表。
  2. 在您的 aspx 代码中创建一个直接从类获取数据的 ObjectDataSource,并将该 ObjectDataSource 配置为使用您的 IComparer。

Take a look at this MSDN page and 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.

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:

  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.
掐死时间 2024-07-17 20:19:13

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

要使用:

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

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

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

To use:

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

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
娇纵 2024-07-17 20:19:13

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

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

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

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

来世叙缘 2024-07-17 20:19:13

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

这样,您可以保留原始列以供显示和显示之用。 有 2 个隐藏列用于排序。

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

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

抱着落日 2024-07-17 20:19:13

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

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

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

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文