最终编辑/答案: 我想不出一种方法来做到这一点,同时仍然使用内置在 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.