web-dev-qa-db-ja.com

BindingList <T> .Sort()は、List <T> .Sort()のように動作します

アプリケーションに使用できるSortableBindingListを作成しようとしています。 DataGridViewまたはStackOverflowからのこの投稿を含む他のバインドされたコントロールのコンテキストで使用されたときにBindingListがソートされるように、基本的なソートサポートを実装する方法について多くの議論を見つけました:
DataGridViewの並べ替えと例:.NETのBindingList <T>

これはすべて非常に役立ち、コードを実装したり、テストしたりして、すべて機能していますが、特定の状況では、Sort()の単純な呼び出しをサポートし、その呼び出しでデフォルトのIComparableを使用できるようにする必要があります。 CompareTo()を使用して、ApplySortCore(PropertyDescriptor、ListSortDirection)を呼び出すのではなく、並べ替えを行います。

その理由は、この特定のクラスが元々Listから継承され、最近BindingListに変更されたため、Sort()呼び出しに依存するコードが非常に多いためです。

具体的には、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()ロジック。

誰かが私を正しい方向に向けることができますか?

どうもありがとう。


編集:これは、将来の参照のためにマークの応答に基づく最終的なコードです。

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

  }
21
Paul Prewett

ソートを行うためだけにプロパティをエミュレートするのは、おそらくやり過ぎです。最初に確認するのは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();
    }    
}
16
Marc Gravell

私は同じ問題を抱えていました、そしてこの投稿は私がそれを解決するのを助けました!

このソリューション(MarcとPaulのコードに基づく)を拡張機能として実装し、2つの簡単な並べ替え方法を追加したので、それを皆さんと共有したいと思います。

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

これがお役に立てば幸いです。

10
SolarX