BindingList <T>.Sort() ведет себя как List <T>.Sort()
Я пытаюсь написать SortableBindingList, который я могу использовать для своего приложения. Я нашел много дискуссий о том, как реализовать базовую поддержку сортировки, чтобы BindingList сортировал, когда используется в контексте DataGridView или какого-либо другого связанного элемента управления, включая этот пост из StackOverflow:
Сортировка DataGridView и, например, BindingList < Т > в .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?
}
}
Я сделал несколько неудачных попыток повторного использования метода ApplySortCore в Sort(), но то, что меня мешает, заключается в том, что приложение ApplySortCore ожидает, что PropertyDescriptor будет выполнять свою работу, и я не могу понять, как это сделать используйте логику IComparable.CompareTo().
Может ли кто-нибудь указать мне в правильном направлении?
Большое спасибо.
EDIT: это окончательный код, основанный на ответе 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>
или аналогичные
- сортировать извлеченные данные
- отключить уведомления
- перезагрузить данные
- повторно включить уведомления
- отправить сообщение reset
btw, вы также должны отключать уведомления во время существующего сортировки.
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();
}
}
Ответ 2
У меня была та же проблема, и этот пост помог мне решить эту проблему!
Поскольку я реализовал это решение (на основе кода 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);
}
}
Надеюсь, что это будет полезно.