我有一个数据绑定到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中拥有对象的一个属性时,事情很有用。但是为了对我的一个自定义列进行排序,我将不得不完全避免这一行,并找到一些其他方法来根据该列对数据网格进行排序。这是否意味着必须构建自己的排序功能?这似乎可能是一种巨大的痛苦。
答案 0 :(得分:1)
最终编辑/答案:我仍然无法想到在使用DataGridView内置的排序机制时执行此操作的方法。如果我在你的鞋子里,我可能只是将每列的SortMode更改为“Programmatic”,然后自己处理“ColumnHeaderMouseClick”。此时,您应该在修改后的BindingList类中调用sort方法,该方法将根据单击的列执行必要的排序。这避免了使用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;
}
}
现在,正如你在ApplySortCore方法中看到的那样,我直接从DataGridView接收列和方向 - 这意味着我没有以编程方式调用它。这听起来不像你想要的那样,但如果你需要以编程方式调用它并传递适当的IByColumnComparer,你可以很容易地修改这段代码。我向大家展示这一点是为了让你能够理解如何修改排序算法,这非常有用。
特别感谢@MartinhoFernandes关于使这个课程更通用的建议。