C# BindingList<T>.Sort() 表现得像 List<T>.Sort()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1063917/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 07:21:35  来源:igfitidea点击:

BindingList<T>.Sort() to behave like a List<T>.Sort()

c#.netwinformssortingbindinglist

提问by Paul Prewett

I am attempting to write a SortableBindingList that I can use for my application. I have found lots of discussion about how to implement basic sorting support so that the BindingList will sort when used in the context of a DataGridView or some other bound control including this post from StackOverflow:
DataGridView sort and e.g. BindingList<T> in .NET

我正在尝试编写一个可用于我的应用程序的 SortableBindingList。我发现了很多关于如何实现基本排序支持的讨论,以便在 DataGridView 或其他绑定控件的上下文中使用 BindingList 时进行排序,包括 StackOverflow 中的这篇文章:
DataGridView sort and eg BindingList<T> in .NET

This is all very helpful and I have implemented the code, tested, etc. and it's all working, but in my particular situation, I need to be able to support a simple call to Sort() and have that call use the default IComparable.CompareTo() to do the sorting, rather than making a call to ApplySortCore(PropertyDescriptor, ListSortDirection).

这一切都非常有帮助,我已经实现了代码、测试等,并且一切正常,但在我的特定情况下,我需要能够支持对 Sort() 的简单调用,并让该调用使用默认的 IComparable。 CompareTo() 进行排序,而不是调用 ApplySortCore(PropertyDescriptor, ListSortDirection)。

The reason is because I have quite a great deal of code that's depending on the Sort() call because this particular class originally inherited from List and was recently changed to be a BindingList.

原因是因为我有相当多的代码依赖于 Sort() 调用,因为这个特定的类最初是从 List 继承的,最近被更改为 BindingList。

So specifically, I have a class called VariableCode and a collection class called VariableCodeList. VariableCode implements IComparable and the logic in there is moderately complex based on several properties, etc...

具体来说,我有一个名为 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?
    }
}

I've made a few failed attempts at repurposing the ApplySortCore method in the Sort(), but what keeps thwarting me is that the ApplySortCore expects a PropertyDescriptor to do its sort and I can't figure out how to get that to use the IComparable.CompareTo() logic.

我已经在 Sort() 中重新利用 ApplySortCore 方法做了一些失败的尝试,但一直阻碍我的是 ApplySortCore 期望 PropertyDescriptor 进行排序,我不知道如何使用 IComparable .CompareTo() 逻辑。

Can someone point me in the right direction?

有人可以指出我正确的方向吗?

Many thanks.

非常感谢。



EDIT: This is the final code based on Marc's response for future reference.

编辑:这是基于 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();
     }

  }

采纳答案by Marc Gravell

Emulating a property just to do the sort is probably overkill. The first thing to look at is Comparer<T>.Default. It might, however, turn out that the easiest thing to do is to:

模拟一个属性只是为了进行排序可能是矫枉过正。首先要看的是Comparer<T>.Default。然而,事实证明,最简单的做法是:

  • extract the data into List<T>or similar
  • sort the extracted data
  • disable notifications
  • reload the data
  • re-enable notifications
  • send a "reset" message
  • 将数据提取到List<T>或类似
  • 对提取的数据进行排序
  • 禁用通知
  • 重新加载数据
  • 重新启用通知
  • 发送“重置”消息

btw, you should be disabling notifications during your existing sort, too.

顺便说一句,您也应该在现有排序期间禁用通知。

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

回答by SolarX

I had the same problem and this post helped me solve it!

我遇到了同样的问题,这篇文章帮助我解决了它!

As I implemented this solution (based on Marc's and Paul's code) as an extension and added two simple sort methods, I would like to share it with you:

当我将此解决方案(基于 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);
        }
    }

Hope this is helpful.

希望这是有帮助的。