1

我有一个数据绑定到 BindingList 的 DataGridView。我的 DataGridView 还添加了几个自定义列。这些不是数据绑定的,而是基于我的 BindingList 中的项目生成的(即:我的 BindingList 中类型 A 的项目具有类型 B 的属性;我的自定义列显示 B.Name (编辑:在这种情况下,“ Name”是类 B 的属性,因此该列表示的属性不能直接在 BindingList 中的项目中找到))。

我需要能够对我的 DataGridView 中的所有列进行排序。DataGridView 有两种排序方法:Sort(IComparer) 和 Sort(DataGridViewColumn, ListSortDirection)。我使用第二个对我的数据绑定列进行排序,但在非数据绑定列上使用时它当然会引发异常。如果 DataSource 不为 null,则第一种方法将引发异常。

因此,据我所知,DataGridView 的内置排序方法都不起作用。我还能如何根据我的自定义列对网格进行排序?

编辑:

我现在做的是处理点击列标题,按照这里看到的说明:http: //msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.columnheadermouseclick.aspx

问题就出现了:

dataGridView1.Sort(newColumn, direction);

当 newColumn 在我的 BindingList 中保存对象的属性之一时,事情就很好了。但是为了对我的一个自定义列进行排序,我将不得不完全避开这一行,并找到其他方法来根据该列对数据网格进行排序。这是否意味着必须构建自己的排序功能?这似乎是一种巨大的痛苦。

4

1 回答 1

1

最终编辑/答案: 我想不出一种方法来做到这一点,同时仍然使用内置在 DataGridView 中的排序机制。如果我站在你的立场上,我可能会将每列的 SortMode 更改为“Programmatic”,然后自己处理“ColumnHeaderMouseClick”。此时,您应该在修改后的 BindingList 类中调用排序方法,该方法将根据单击的列执行必要的排序。这避免了使用 DGV 的 Sort 方法并直接对底层列表进行排序。

完整的话语位于评论部分。原始答案立即如下:

编辑:由于对问题和随后的讨论有些混淆,我在这个答案的评论中有一个新的建议。我将留下我发布的原始答案,以便我们参考。

我最近不得不这样做——我不会说谎,这真的很痛苦。我确实想出了一个解决方案(在 SO 的一些朋友的帮助下),所以就这样吧。我创建了一个新的基于 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;
  }
}

Now, as you can see in the ApplySortCore method, I am receiving the column and the direction directly from the DataGridView - meaning that I am not calling this programmatically. That doesn't sound like what you want to do, but you could easily modify this code if you need to call it programmatically and pass the appropriate IByColumnComparer. My point in showing you all this is so you can understand how to modify the sorting algorithm, which is quite useful.

Special thanks to @MartinhoFernandes for the suggestions concerning making this class more generic.

于 2011-05-16T18:14:13.433 回答