使用linq对可观察集合进行排序

使用linq对可观察集合进行排序,linq,silverlight,observablecollection,Linq,Silverlight,Observablecollection,我有一个可观察的集合,并使用linq对其进行排序。一切都很好,但我的问题是如何对实际的可观察集合进行排序?取而代之的是,我最终得到了一些IEnumerable的东西,我最终清理了集合,并将这些东西添加回了。这对性能不好。有人知道更好的方法吗?请注意,在Linq中,查询中会给您一个IEnumerable,而该查询尚未执行。因此,以下代码只运行一次查询,以将其添加到ObservableCollection: var query = from x in Data where x

我有一个可观察的集合,并使用linq对其进行排序。一切都很好,但我的问题是如何对实际的可观察集合进行排序?取而代之的是,我最终得到了一些IEnumerable的东西,我最终清理了集合,并将这些东西添加回了。这对性能不好。有人知道更好的方法吗?

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

var query = from x in Data
            where x.Tag == "Something"
            select x;

foreach(var item in query)
    MyObservableCollection.Add(item);
请看IEnumerable上的“”扩展:

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

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

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

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

有趣的是,如果这是
BindingList
,您可以使用
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();
    }

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


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


对于ListBox或任何ItemsControl派生控件,我遵循了本文中提到的链接

但在Silverlight中运行时遇到问题

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


有人能告诉我出了什么问题吗。谢谢

我在CodePlex上找到了这个:

不过我还没用过


Rick

我用它作为我代码中类似内容的基础。我开始觉得Linq非常棒:)我不确定如果你从WCF服务获得可观的收集,这会有多好,有什么建议吗?我是否需要在客户端上创建新的ObservableCollection并对其应用“OrderBy”谢谢。@VoodooChild:如果您已经有了一个ObservableCollection而不仅仅是一个IEnumerable,那么请看SO问题:您必须在术语property上引发一个属性更改事件。如果您要走这条路,为了性能,我会使用
var ordered=list.OrderBy(x=>x.SomeProp);list.Clear();list.AddRange(已排序)您将避免不必要的ToArray()迭代和执行,并且在AddRange()期间只执行一次。(我必须进行反编译以验证这一点,因为AddRange接受IEnumerable,它甚至可能只存储IEnumerable而不执行它,然后在调用任何特定于列表的操作之前执行并存储展开的集合。最终的性能相同,但只是将循环命中延迟到以后。)的可能重复
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;
ItemsSource="{Binding}"