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

Pau*_*ett 21 .net c# sorting bindinglist winforms

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

这一切都非常有用,我已经实现了代码,经过测试等等,并且一切正常,但在我的特殊情况下,我需要能够支持对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?
    }
}
Run Code Online (Sandbox Code Playgroud)

我在Sort()中重新调整了ApplySortCore方法的尝试失败了,但是阻止我的是,ApplySortCore期望PropertyDescriptor进行排序,我无法弄清楚如何使用IComparable .CompareTo()逻辑.

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

非常感谢.


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

  }
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 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();
    }    
}
Run Code Online (Sandbox Code Playgroud)

  • 很好,马克.谢谢.我一直以为我错过了一些东西,并且某处会有一些内置的支持,而不仅仅是执行简单的解决方案.通知也很好.我内部使用List <T>而不是数组,这样我就可以支持灵活的基于委托的排序(比如List <T>类支持).使用最终代码更新帖子. (2认同)

Sol*_*arX 10

我有同样的问题,这篇文章帮我解决了!

当我实现这个解决方案(基于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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

希望这是有帮助的.