2009-06-30 1 views
20

Я пытаюсь написать SortableBindingList, который я могу использовать для своего приложения. Я нашел много дискуссий о том, как осуществить базовую поддержку сортировки, так что BindingList сортируют при использовании в контексте DataGridView или какое-либо другое связанного управления, включая это сообщение StackOverflow:
DataGridView sort and e.g. BindingList<T> in .NETBindingList .Sort() вести себя как список <T> .Sort()

Все это очень полезно и я реализовал код, протестировал и т. д., и все это работает, но в моей конкретной ситуации мне нужно иметь возможность поддерживать простой вызов 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(), но то, что держит срыве я утверждаю, что ApplicationSortCore ожидает, что PropertyDescriptor будет выполнять свою работу, и я не могу понять, как это сделать, чтобы использовать логику IComparable.CompareTo().

Может кто-нибудь указать мне в правильном направлении?

Большое спасибо.


EDIT: Это окончательный код, основанный на ответе Марка для дальнейшего использования.

/// <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(); 
    } 

    } 

ответ

16

Эмулировать недвижимость, чтобы сделать вид, вероятно, перебор. Первое, что нужно посмотреть - 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(); 
    }  
} 
+2

Nice, Марк. Спасибо. Я продолжал думать, что я что-то упустил и что где-то будет какая-то поддержка, а не просто выполнение простого решения. Хорошая точка в уведомлениях. Я закончил использование списка внутренне, а не массивом, чтобы я мог поддерживать гибкую сортировку на основе делегатов (например, класс List ). Сообщение обновляется с окончательным кодом. –

9

У меня была та же проблема, и эта почта помогла мне решить ее!

Как я реализовал это решение (на основе Марка и коде Павла) в качестве расширения и добавлены два простых методов сортировки, я хотел бы поделиться с вами:

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); 
     } 
    } 

Надежда это полезно.

+1

Очень красивый, чистый и простой в использовании. Лично я предпочел вернуть BindingList из метода расширения. – PhilHoy

 Смежные вопросы

  • Нет связанных вопросов^_^