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