对绑定到BindingList的DataGridView中的自定义列进行排序

时间:2011-05-16 17:48:21

标签: c# sorting datagridview bindinglist

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

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

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

修改

我目前所做的是按照此处显示的说明处理列标题上的点击:http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.columnheadermouseclick.aspx

问题就出现了:

dataGridView1.Sort(newColumn, direction);

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

1 个答案:

答案 0 :(得分:1)

最终编辑/答案:我仍然无法想到在使用DataGridView内置的排序机制时执行此操作的方法。如果我在你的鞋子里,我可能只是将每列的SortMode更改为“Programmatic”,然后自己处理“ColumnHeaderMouseClick”。此时,您应该在修改后的BindingList类中调用sort方法,该方法将根据单击的列执行必要的排序。这避免了使用DGV的Sort方法并直接对基础列表进行排序。

Full Discourse位于评论部分。原始答案紧接着:

编辑:由于对该问题的一些混淆以及随后的讨论,我在本答案的评论中提出了新的建议。我要留下我发布的原始答案,以便我们可以参考。

我最近不得不这样做 - 我不会说这是一个真正的痛苦。我确实提出了一个解决方案(在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;
  }
}

现在,正如你在ApplySortCore方法中看到的那样,我直接从DataGridView接收列和方向 - 这意味着我没有以编程方式调用它。这听起来不像你想要的那样,但如果你需要以编程方式调用它并传递适当的IByColumnComparer,你可以很容易地修改这段代码。我向大家展示这一点是为了让你能够理解如何修改排序算法,这非常有用。

特别感谢@MartinhoFernandes关于使这个课程更通用的建议。