C#:自定义DataGridView

时间:2009-01-12 11:34:10

标签: c# sorting datagridview dataview

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

非常讨厌。试图在StackOverflow上阅读相关问题,并搜索谷歌的很多和很多,但我真的找不到这个。只有我真正找到的东西是使用数据视图的Sort(字符串)方法,因为它按字母顺序排序,因此无法正常工作。

有没有人知道怎么做而没有太多麻烦?它应该是别人而不是我这个?我真的不想重新实现整个datagridview或dataview类,只是为了获得自定义排序......

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

5 个答案:

答案 0 :(得分:5)

查看this MSDN pagethis blog post。原则上,您需要在GridView上配置数据源的排序(无论是ObjectDataSource还是SqlDataSource)。

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

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

答案 1 :(得分:2)

此代码应该有效。它类似于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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

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

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

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