【问题标题】:Sorting an observable collection with linq使用 linq 对 observable 集合进行排序
【发布时间】:2010-11-03 00:37:30
【问题描述】:

我有一个可观察的集合,我使用 linq 对其进行排序。一切都很好,但我遇到的问题是如何对实际的 observable 集合进行排序?相反,我只是得到了一些 IEnumerable 的东西,我最终清除了集合并重新添加了这些东西。这对性能没有好处。有谁知道更好的方法吗?

【问题讨论】:

标签: linq silverlight observablecollection


【解决方案1】:

如果您使用的是 Silverlight 3.0,那么使用 CollectionViewSource 是最简洁的方式。请参考以下示例:(也可以通过 xaml 完成)

ObservableCollection<DateTime> ecAll = new ObservableCollection<DateTime>();
CollectionViewSource sortedcvs = new CollectionViewSource();
sortedcvs.SortDescriptions.Add(new System.ComponentModel.SortDescription("Date", 
    System.ComponentModel.ListSortDirection.Ascending));
sortedcvs.Source = ecAll;
ListBoxContainer.DataContext = sortedcvs;

并在对应的xaml集合中

ItemsSource="{Binding}"

对于 ListBox 或任何 ItemsControl 派生控件

【讨论】:

    【解决方案2】:

    由于该集合不提供任何Sort 机制,这可能是最实用的选择。您可以使用Move 等手动实现排序,但它可能会比这种方式慢。

        var arr = list.OrderBy(x => x.SomeProp).ToArray();
        list.Clear();
        foreach (var item in arr) {
            list.Add(item);
        }
    

    此外,您可以考虑在排序时取消绑定任何 UI 元素(通过任何一种方法),您只需支付重新绑定一次的费用:

    有趣的是,如果这是BindingList&lt;T&gt;,您可以使用RaiseListChangedEvents 来最小化通知数量:

        var arr = list.OrderBy(x => x).ToArray();
        bool oldRaise = list.RaiseListChangedEvents;
        list.RaiseListChangedEvents = false;
        try {
            list.Clear();
            foreach (var item in arr) {
                list.Add(item);
            }
        } finally {
            list.RaiseListChangedEvents = oldRaise;
            if (oldRaise) list.ResetBindings();
        }
    

    【讨论】:

    • 如果你要走这条路,为了性能,我会使用var ordered = list.OrderBy(x =&gt; x.SomeProp); list.Clear(); list.AddRange(ordered); 你将避免 ToArray() 不必要的迭代和执行,并且只在 AddRange() 期间这样做一次. (我必须反编译来验证这一点,因为 AddRange 需要一个 IEnumerable,它甚至可能只存储它而不执行它,然后在调用任何特定于 List 的操作之前执行并存储展平的集合。最终相同的性能,但它只是将周期推迟到以后。)
    【解决方案3】:

    请注意,在 Linq 中,您会从查询中获得一个 IEnumerable,并且该查询尚未执行。因此,以下代码只运行一次查询,将其添加到 ObservableCollection:

    var query = from x in Data
                where x.Tag == "Something"
                select x;
    
    foreach(var item in query)
        MyObservableCollection.Add(item);
    

    看看 IEnumerable 上的“OrderBy”扩展:

    foreach(var item in query.OrderBy(x => x.Name))
        MyObservableCollection.Add(item);
    

    【讨论】:

    • 我用它作为我的代码类似的东西的基础。我开始认为 Linq 很牛逼 :)
    • 我不确定如果您从 WCF 服务获取 ObservableCollection 会有多好,有什么建议吗?我是否需要在客户端上创建一个新的 ObservableCollection 并对其应用“OrderBy”? - 谢谢。
    • @VoodooChild:如果您已经有一个 ObservableCollection 而不仅仅是一个 IEnumerable,那么请查看 SO 问题:stackoverflow.com/questions/996126/…
    【解决方案4】:

    ObservableCollections 并非设计为可排序的。 List 是可排序的,这是引用 List.Sort() 的答案所使用的底层机制,但 ObservableCollection 不是从 List 派生的,所以你在那里不走运。 Imo,“正确”的解决方案不是尝试对 ObservableCollection 进行排序,而是实现 ICollectionView 并将其实例绑定到您的控件。该接口添加了排序方法,并具有 Silverlight 控件(好吧,无论如何都支持它的控件,例如 DataGrid)识别的额外好处,因此您的排序可以直接从 UI 层使用。这个问题可能会有所帮助:

    Silverlight and icollectionview

    【讨论】:

      【解决方案5】:

      我点击了这篇文章中提到的链接http://mokosh.co.uk/post/2009/08/04/how-to-sort-observablecollection/comment-page-1/#comment-75

      但在 Silverlight 中运行时遇到问题

      我创建了一个属性 public SortableObservableCollection 条款 当我调用 Terms.Sort(new TermComparer()) 时,记录仍然未排序地显示在 UI 上

      能否提出一些问题。谢谢

      【讨论】:

      • 您必须在条款属性上引发属性更改事件
      【解决方案6】:

      我在 CodePlex 上找到了这个:

      Sorted Collections

      还没用过。

      瑞克

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-31
        • 2012-01-21
        • 1970-01-01
        • 2012-11-03
        • 1970-01-01
        相关资源
        最近更新 更多