21

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

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

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

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

4

5 回答 5

5

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

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

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

这段代码应该可以工作。它类似于 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
于 2012-01-03T23:10:02.223 回答
1

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

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

于 2010-11-17T10:18:36.797 回答
0

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

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

于 2009-01-12T16:28:26.097 回答
0

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

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

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

于 2012-03-16T12:45:31.510 回答