BindingList<T>.Sort() 表现得像 List<T>.Sort()
Posted
技术标签:
【中文标题】BindingList<T>.Sort() 表现得像 List<T>.Sort()【英文标题】:BindingList<T>.Sort() to behave like a List<T>.Sort() 【发布时间】:2010-11-07 00:39:45 【问题描述】:我正在尝试编写一个可用于我的应用程序的 SortableBindingList。我发现很多关于如何实现基本排序支持的讨论,以便 BindingList 在 DataGridView 或其他一些绑定控件的上下文中使用时进行排序,包括来自 *** 的这篇文章:DataGridView sort and e.g. BindingList<T> in .NET
这一切都非常有帮助,我已经实现了代码,经过测试等,一切正常,但在我的特殊情况下,我需要能够支持对 Sort() 的简单调用,并让该调用使用默认 IComparable.CompareTo() 进行排序,而不是调用 ApplySortCore(PropertyDescriptor, ListSortDirection)。
原因是因为我有相当多的代码依赖于 Sort() 调用,因为这个特定的类最初继承自 List,最近被更改为 BindingList。
具体来说,我有一个名为 VariableCode 的类和一个名为 VariableCodeList 的集合类。 VariableCode 实现了 IComparable 并且其中的逻辑基于几个属性等......
public class VariableCode : ... IComparable ...
public int CompareTo(object p_Target)
int output = 0;
//some interesting stuff here
return output;
public class VariableCodeList : SortableBindingList<VariableCode>
public void Sort()
//This is where I need help
// How do I sort this list using the IComparable
// logic from the class above?
我在 Sort() 中重新利用 ApplySortCore 方法进行了几次失败的尝试,但一直阻碍我的是 ApplySortCore 期望 PropertyDescriptor 进行排序,我不知道如何让它使用 IComparable.CompareTo() 逻辑。
有人能指出正确的方向吗?
非常感谢。
编辑:这是基于 Marc 的响应的最终代码,以供将来参考。
/// <summary>
/// Sorts using the default IComparer of T
/// </summary>
public void Sort()
sort(null, null);
public void Sort(IComparer<T> p_Comparer)
sort(p_Comparer, null);
public void Sort(Comparison<T> p_Comparison)
sort(null, p_Comparison);
private void sort(IComparer<T> p_Comparer, Comparison<T> p_Comparison)
m_SortProperty = null;
m_SortDirection = ListSortDirection.Ascending;
//Extract items and sort separately
List<T> sortList = new List<T>();
this.ForEach(item => sortList.Add(item));//Extension method for this call
if (p_Comparison == null)
sortList.Sort(p_Comparer);
//if
else
sortList.Sort(p_Comparison);
//else
//Disable notifications, rebuild, and re-enable notifications
bool oldRaise = RaiseListChangedEvents;
RaiseListChangedEvents = false;
try
ClearItems();
sortList.ForEach(item => this.Add(item));
finally
RaiseListChangedEvents = oldRaise;
ResetBindings();
【问题讨论】:
【参考方案1】:模拟一个属性只是为了进行排序可能是矫枉过正。
首先要看的是Comparer<T>.Default
。然而,事实证明,最简单的做法是:
List<T>
或类似文件中
对提取的数据进行排序
禁用通知
重新加载数据
重新启用通知
发送“重置”消息
顺便说一句,您也应该在现有排序期间禁用通知。
public void Sort()
// TODO: clear your "sort" variables (prop/order)
T[] arr = new T[Count];
CopyTo(arr, 0);
Array.Sort(arr);
bool oldRaise = RaiseListChangedEvents;
RaiseListChangedEvents = false; // <=== oops, added!
try
ClearItems();
foreach (T item in arr)
Add(item);
finally
RaiseListChangedEvents = oldRaise;
ResetBindings();
【讨论】:
很好,马克。谢谢你。我一直在想我错过了一些东西,并且在某处会有一些内置的支持,而不仅仅是执行简单的解决方案。通知的好点,以及。我最终在内部使用 List我遇到了同样的问题,这篇文章帮我解决了!
由于我将这个解决方案(基于 Marc 和 Paul 的代码)实现为扩展并添加了两个简单的排序方法,因此我想与您分享:
public static void SortAscending<T, P>(this BindingList<T> bindingList, Func<T, P> sortProperty)
bindingList.Sort(null, (a, b) => ((IComparable<P>)sortProperty(a)).CompareTo(sortProperty(b)));
public static void SortDescending<T, P>(this BindingList<T> bindingList, Func<T, P> sortProperty)
bindingList.Sort(null, (a, b) => ((IComparable<P>)sortProperty(b)).CompareTo(sortProperty(a)));
public static void Sort<T>(this BindingList<T> bindingList)
bindingList.Sort(null, null);
public static void Sort<T>(this BindingList<T> bindingList, IComparer<T> comparer)
bindingList.Sort(comparer, null);
public static void Sort<T>(this BindingList<T> bindingList, Comparison<T> comparison)
bindingList.Sort(null, comparison);
private static void Sort<T>(this BindingList<T> bindingList, IComparer<T> p_Comparer, Comparison<T> p_Comparison)
//Extract items and sort separately
List<T> sortList = new List<T>();
bindingList.ForEach(item => sortList.Add(item));//Extension method for this call
if (p_Comparison == null)
sortList.Sort(p_Comparer);
//if
else
sortList.Sort(p_Comparison);
//else
//Disable notifications, rebuild, and re-enable notifications
bool oldRaise = bindingList.RaiseListChangedEvents;
bindingList.RaiseListChangedEvents = false;
try
bindingList.Clear();
sortList.ForEach(item => bindingList.Add(item));
finally
bindingList.RaiseListChangedEvents = oldRaise;
bindingList.ResetBindings();
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
if (source == null) throw new ArgumentNullException("source");
if (action == null) throw new ArgumentNullException("action");
foreach (T item in source)
action(item);
希望这有帮助。
【讨论】:
非常好,干净且易于使用。我个人更喜欢从扩展方法返回 BindingList。以上是关于BindingList<T>.Sort() 表现得像 List<T>.Sort()的主要内容,如果未能解决你的问题,请参考以下文章
是啥导致 BindingList<T> 中的 ListChangedType.ItemMoved ListChange 事件?
List<T> vs BindingList<T> 优点/缺点