C#:DataGridView的自定义排序

C#:DataGridView的自定义排序,c#,sorting,datagridview,dataview,C#,Sorting,Datagridview,Dataview,我需要使用自然排序对DataGridView进行排序(如在Explorer中),以便数字和文本(在同一列中)自然排序,而不是按字母顺序排序(以便“place 3”位于“place 20”之前,等等)。我有一个DataGridView,其中我将DataView设置为数据源。DataView包含一个DataTable,它是使用数据库中的一些值创建的。列类型为字符串。我有一个IComparer,它做它应该做的,但我不知道如何使用它,因为我不知道如何进行排序。DataGridView.SortCompa

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

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

有人知道如何不费吹灰之力地做到这一点吗?一定是我以外的其他人在为这个苦苦挣扎?我真的不想重新实现整个datagridview或dataview类,只是为了获得自定义排序

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

看看和。原则上,您需要在数据源(无论是ObjectDataSource还是SqlDataSource)而不是GridView上配置排序

据我所知,DataView类只支持简单的升序/降序排序。如果看不到加载和绑定数据的代码,很难给出具体的建议,但您可以:

  • 将数据加载到列表而不是数据表中,调用传递比较方法的排序方法,然后绑定到该列表
  • 在aspx代码中创建一个直接从类获取数据的ObjectDataSource,并将该ObjectDataSource配置为使用IComparer

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


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

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


    此代码应该可以工作。它类似于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
    

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

    然后(按照@True C Sharp的答案),您可以有一个包含此值的隐藏列,并按此而不是按显示列进行排序


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

    是的,我有点这样想。但是如何配置DataView的排序?我在DataView上看到的唯一排序方法是Sort方法,它接受一个带有列和方向的字符串。我找不到一种方法来指定一个IComparer或类似的东西。但是,除非数据是非常规范化和可预测的,否则这不会很好地工作……我也在寻找解决方案。我得出了与您相同的结论,尽管我在许多地方都需要这样做,而且我无法将所有数据表都提供给中间表来提供此功能,特别是因为用户可以决定对哪一列进行排序。到目前为止没有运气,但我会继续努力,并希望看到一个答案。我无法想象为什么没有其他人在网上询问甚至评论这个问题。从那以后你发现了什么吗?@m_ogin-没有,不幸的是没有。但后来我转到了另一个项目,所以我再也没有找它了。尽管这是一个很老的问题,但我最近发现自己与@Svish(数据绑定的GridView控件,无法访问SortCompare事件,并且需要对某些列进行自定义排序,而不仅仅是基本的字母顺序)处于同样的困境。经过一段时间的研究,我认为您在更新中提出的解决方案至今仍然是最好、最优雅的。毫无用处,因为原始海报已经提到这种方法不适合数据绑定gridsEven,如果有效,它肯定缺乏解释,无法作为合理的好答案