如何对BindingList<T>进行排序?

9
我有几千个MyClass对象存储在BindingList<MyClass>中。我想通过日期属性MyClass.dt对它们进行排序。
但是,类BindingList不支持直接排序。我该如何在不制作所有对象的重复副本的情况下对BindingList<T>进行排序?请按升序或降序对它们进行排序。
我不需要像BindingList.Sort() to behave like a List.Sort()中描述的那样特殊的类SortableBindingList。 我正在寻找一行或两行代码的简短解决方案。

你的意思是它不能直接支持排序吗? - David L
我的意思是list.Sort()不可行。 - Alexander Borochkin
https://dev59.com/yHNA5IYBdhLWcg3wKam3 - MindingData
使用 SortableBindingList<T>,DataGridView 在更改时不会排序 - Reza Aghaei
3个回答

13

Linq可以胜任。

var sortedListInstance = new BindingList<MyClass>(unsortedListInstance.OrderBy(x => x.dt).ToList());

请记住,您得到的是已排序列表的浅拷贝,而不是MyClass的重复实例。

不要忘记在代码文件顶部包含命名空间System.Linq


5
请注意,这是在第一次创建列表时的一个很好的解决方案。当后续插入项目时,您可能希望确保首先将它们插入正确的索引位置。请参阅插入以获取更多信息。 - CompuChip
我绑定到这个列表的事件会消失吗? - user11910061

6

实现BindingList的排序的一种快速方法是使用以支持IList<T>的构造函数为参数。您可以使用List<T>作为支持并获得其Sort功能。

根据文档

使用此BindingList创建由列表支持的BindingList,这确保了对列表的更改会反映在BindingList中。

如果您的MyClass定义如下:

internal class MyClass
{
    public MyClass(string name, Int32 num)
    {
        this.Name = name;
        this.Num = num;
    }
    public string Name {get; set;}
    public Int32 Num {get; set;}
}

那么你可以像这样按照Num字段对其进行排序。

private List<MyClass> backing;
private BindingList<MyClass> bl;

    private void InitializeBindingList()
        {
            backing = new List<MyClass>();
            bl = new BindingList<MyClass>(backing);
            bl.Add(new MyClass("a", 32));
            bl.Add(new MyClass("b", 23));
            bl.Add(new MyClass("c", 11));
            bl.Add(new MyClass("d", 34));
            bl.Add(new MyClass("e", 53));
        }

    private void SortBindingList()
        {
            backing.Sort((MyClass X, MyClass Y) => X.Num.CompareTo(Y.Num));
            // tell the bindinglist to raise a list change event so that 
            // bound controls reflect the new item order
            bl.ResetBindings();
        }
    }

在对支持列表进行排序后,您需要调用BindingList.ResetBindings方法,以通知任何绑定的控件BindingList已更改并更新控件。


向后备列表添加项目的问题在于,BindingList.ResetBindings 不会为 TItemPropertyChanged 事件添加事件处理程序。令人沮丧的是,只有 BindingList(IList<T>) 构造函数才能实现这一点。 - Dai
@Dai,我不明白你的意思。如果我在MyClass上实现INotifyPropertyChanged并修改上面的示例,那么对底层项目的更改将自动响应到DGV中,无需任何其他操作。你能提供一些关于你使用情况的详细信息吗? - TnTinMn
1
如果您调用 backing.Add( new MyClass(..) ) 而不是 bl.Add( new MyClass(...) ),那么即使在将它们添加到 backing 后调用 ResetBindings,属性更改事件处理也不会起作用。 - Dai
1
@dai,感谢您的澄清,我没有想到除了排序技巧之外还可以返回原始列表。 - TnTinMn

-1
//Convert it to a data table, then the Automatic will work.
DataGridView.DataSource = ConvertToDataTable(MyList).DefaultView;

public DataTable ConvertToDataTable(IBindingList list)
{
   DataTable dt = new DataTable();

   if (list.Count > 0)
   {
      Type typ = list[0].GetType();

      PropertyInfo[] arrProps = typ.GetProperties();

      foreach (PropertyInfo pi in arrProps)
      {

         Type colType = pi.PropertyType;
         if (colType.IsGenericType)
         {
            colType = colType.GetGenericArguments()[0];
         }

         dt.Columns.Add(pi.Name, colType);
      }

      foreach (object obj in list)
      {
         DataRow dr = dt.NewRow();

         foreach (PropertyInfo pi in arrProps)
         {
            if (pi.GetValue(obj, null) == null)
               dr[pi.Name] = DBNull.Value;
            else
               dr[pi.Name] = pi.GetValue(obj, null);
         }

         dt.Rows.Add(dr);
      }
   }
   return dt;
}

排序在哪里? - nawfal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接