【问题标题】:How do I sort a DataBound column in a DataGridView on a column header click?如何在列标题单击时对 DataGridView 中的 DataBound 列进行排序?
【发布时间】:2011-06-03 14:26:43
【问题描述】:

我相信这应该自动处理。我将DataGridView 绑定到对象数组:

public class Entity {    
    public string Name { get; set; }     
    public int PrimaryKey { get; set; }
}

绑定网格:

public void BindGrid(Entity[] entities) {
    grdEntities.DataSource = entities;
}

当我单击“名称”列中的列标题时,没有任何反应,即使 SortMode 设置为自动。列标题中也缺少排序字形。

我尝试绑定到IBindingListIList,但这不起作用。

我希望有一个简单、优雅的解决方案,可以在DataGridViewDataGridViewColumn 上设置属性,而不必创建一个新类来支持排序。我应该怎么做才能通过单击 DataBound DataGridView 上的标题来支持对列进行排序?

【问题讨论】:

    标签: c# .net datagridview


    【解决方案1】:

    我创建了一个新的基于 IComparer 的界面,允许您指定列和方向。我这样做只是因为我需要我的排序代码尽可能通用——我有两个需要像这样排序的网格,我不想维护两次代码。这是界面,很简单:

       public interface IByColumnComparer : IComparer
       {
          string SortColumn { get; set; }
          bool SortDescending { get; set; }
       }
    

    显然,如果您不担心保持通用性(您可能应该),那么这并不是绝对必要的。然后,我构建了一个基于 BindingList 的新类。这使我能够覆盖排序代码并逐列提供我自己的 IByColumnComparer,这是我需要的灵活性。看看这个:

    public class SortableGenericCollection<T> : BindingList<T>
    {
      IByColumnComparer GenericComparer = null; 
    
      public SortableGenericCollection(IByColumnComparer SortingComparer)
      {
         GenericComparer = SortingComparer;
      }
    
    
      protected override bool SupportsSortingCore
      {
         get
         {
            return true;
         }
      }
    
      protected override bool IsSortedCore
      {
         get
         {
            for (int i = 0; i < Items.Count - 1; ++i)
            {
               T lhs = Items[i];
               T rhs = Items[i + 1];
               PropertyDescriptor property = SortPropertyCore;
               if (property != null)
               {
                  object lhsValue = lhs == null ? null :
                  property.GetValue(lhs);
                  object rhsValue = rhs == null ? null :
                  property.GetValue(rhs);
                  int result;
                  if (lhsValue == null)
                  {
                     result = -1;
                  }
                  else if (rhsValue == null)
                  {
                     result = 1;
                  }
                  else
                  {
                     result = GenericComparer.Compare(lhs, rhs); 
                  }
                  if (result >= 0)
                  {
                     return false;
                  }
               }
            }
            return true;
         }
      }
    
      private ListSortDirection sortDirection;
      protected override ListSortDirection SortDirectionCore
      {
         get
         {
            return sortDirection;
         }
      }
    
      private PropertyDescriptor sortProperty;
      protected override PropertyDescriptor SortPropertyCore
      {
         get
         {
            return sortProperty;
         }
      }
    
      protected override void ApplySortCore(PropertyDescriptor prop,
      ListSortDirection direction)
      {
         sortProperty = prop;
         sortDirection = direction;
    
         GenericComparer.SortColumn = prop.Name;
         GenericComparer.SortDescending = direction == ListSortDirection.Descending ? true : false;
    
         List<T> list = (List<T>)Items;
         list.Sort(delegate(T lhs, T rhs)
         {
            if (sortProperty != null)
            {
               object lhsValue = lhs == null ? null :
               sortProperty.GetValue(lhs);
               object rhsValue = rhs == null ? null :
               sortProperty.GetValue(rhs);
               int result;
               if (lhsValue == null)
               {
                  result = -1;
               }
               else if (rhsValue == null)
               {
                  result = 1;
               }
               else
               {
                  result = GenericComparer.Compare(lhs, rhs);
               }
               return result;
            }
            else
            {
               return 0;
            }
         });
      }
    
      protected override void RemoveSortCore()
      {
         sortDirection = ListSortDirection.Ascending;
         sortProperty = null;
      }
    }
    

    EDIT 这应该提供一些关于如何根据我上面的界面创建自己的 IComparer 的信息。 拥有自己的基于接口的 IComparer 的优点是您可以以一种方式对某些列进行排序,而对其他列进行另一种排序(有些列可能是字符串,有些可能是整数,有些可能对顶部的内容有特殊规则,等)。以下是您的 IComparer 可能如何工作的示例:

    public class MyGenericComparer : IByColumnComparer
    {
      private string columnToCompare;
      private bool descending;
    
      public string SortColumn
      {
         get { return columnToCompare; }
         set { columnToCompare = value; }
      }
    
      public bool SortDescending
      {
         get { return descending; }
         set { descending = value; }
      }
    
      public MyGenericComparer(string column, bool descend)
      {
         columnToCompare = column;
         descending = descend;
      }
    
      public int Compare(object x, object y)
      {
         MyGenericObject firstObj = (MyGenericObject )x;
         MyGenericObject secondObj = (MyGenericObject )y;
    
         if (descending) 
         {
            MyGenericObject tmp = secondObj ;
            secondObj = firstObj ;
            firstObj = tmp;
         }
    
         if (columnToCompare == "StringColumn")
         {
            //Run code to compare strings, return the appropriate int
            //eg, "1" if firstObj was greater, "-1" is secondObj, "0" if equal
         }
    
         if (columnToCompare == "IntColumn")
         {
            //Run code to compare ints, return the appropriate int
            //eg, "1" if firstObj was greater, "-1" is secondObj, "0" if equal
         }
      }
    }
    

    那么您所要做的就是使用您的比较器实例创建您的列表!

    public static MyGenericComparer GridComparer = new MyGenericComparer();
    public static SortableGenericCollection<GenericObject> GridList = new SortableGenericCollection<GenericObject>(GridComparer);
    

    【讨论】:

    • 您能否提供一个示例来说明如何填充 SortableGenericCollection 集合?我试过了,但不确定为 SortingComparer 参数传递什么。
    【解决方案2】:

    可能想看看这个问题:DataGridView sort and e.g. BindingList<T> in .NET

    基本思想是您必须扩展 BindingList&lt;T&gt; 并覆盖 ApplySortCore 才能使列排序正常工作。

    【讨论】:

    • 所以基本上这不是在 .NET 中自动完成的事情吗?我只是好奇那个 SortMode 枚举是用来做什么的;是针对非绑定网格,还是您总是必须添加自己的实现?
    • 如果您提供扩展 BindingList 并支持排序操作的数据源(此处有更详细的文章:msdn.microsoft.com/en-us/library/ms993236.aspx),那么它会自动完成。
    猜你喜欢
    • 2011-10-10
    • 1970-01-01
    • 2015-12-17
    • 1970-01-01
    • 2016-10-26
    • 2012-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多