2009-06-30 17 views
20

我正在嘗試編寫一個SortableBindingList,可以用於我的應用程序。我發現很多討論如何實現基本排序支持,以便在一個DataGridView或其他一些綁定控件,包括這篇文章從StackOverflow上的上下文中使用時的BindingList將整理:
DataGridView sort and e.g. BindingList<T> in .NETBindingList <T> .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()失敗的嘗試,但什麼使挫敗我是ApplySortCore期望一個PropertyDescriptor做它的排序,我不知道如何得到它使用IComparable.CompareTo()邏輯。

有人能指出我正確的方向嗎?

非常感謝。


編輯:這是基於馬克的反應爲未來參考的最終代碼。

/// <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

尼斯,馬克。謝謝。我一直認爲我錯過了一些東西,並且會有一些內置的支持,而不僅僅是執行簡單的解決方案。通知的優點也是如此。我在內部使用列表而不是Array,這樣我就可以支持靈活的基於委託的排序(如列表類支持)。帖子用最終的代碼更新。 – 2009-06-30 15:25:41

9

我有同樣的問題,這篇文章幫我解決了它!

正如我實現這個解決方案(基於Marc的和保羅的代碼)作爲擴展和增加了兩個簡單的排序方法,我想與你分享:

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 2012-01-19 09:50:28