【问题标题】:BindingList<T>.Sort() to behave like a List<T>.Sort()BindingList<T>.Sort() 表现得像 List<T>.Sort()
【发布时间】:2010-11-07 00:39:45
【问题描述】:

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

这一切都非常有帮助,我已经实现了代码,经过测试等,一切正常,但在我的特殊情况下,我需要能够支持对 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?
    }
}

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

  }

【问题讨论】:

    标签: c# .net winforms sorting bindinglist


    【解决方案1】:

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

    • 将数据提取到List&lt;T&gt; 或类似文件中
    • 对提取的数据进行排序
    • 禁用通知
    • 重新加载数据
    • 重新启用通知
    • 发送“重置”消息

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

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

    【讨论】:

    • 很好,马克。谢谢你。我一直在想我错过了一些东西,并且在某处会有一些内置的支持,而不仅仅是执行简单的解决方案。通知的好点,以及。我最终在内部使用 List 而不是 Array,这样我也可以支持灵活的基于委托的排序(就像 List 类支持的那样)。使用最终代码更新帖子。
    【解决方案2】:

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

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

    希望这有帮助。

    【讨论】:

    • 非常好,干净且易于使用。我个人更喜欢从扩展方法返回 BindingList。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2010-10-20
    • 2011-01-15
    • 2011-02-17
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多