【发布时间】:2010-11-03 00:37:30
【问题描述】:
我有一个可观察的集合,我使用 linq 对其进行排序。一切都很好,但我遇到的问题是如何对实际的 observable 集合进行排序?相反,我只是得到了一些 IEnumerable 的东西,我最终清除了集合并重新添加了这些东西。这对性能没有好处。有谁知道更好的方法吗?
【问题讨论】:
标签: linq silverlight observablecollection
我有一个可观察的集合,我使用 linq 对其进行排序。一切都很好,但我遇到的问题是如何对实际的 observable 集合进行排序?相反,我只是得到了一些 IEnumerable 的东西,我最终清除了集合并重新添加了这些东西。这对性能没有好处。有谁知道更好的方法吗?
【问题讨论】:
标签: linq silverlight observablecollection
如果您使用的是 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 派生控件
【讨论】:
由于该集合不提供任何Sort 机制,这可能是最实用的选择。您可以使用Move 等手动实现排序,但它可能会比这种方式慢。
var arr = list.OrderBy(x => x.SomeProp).ToArray();
list.Clear();
foreach (var item in arr) {
list.Add(item);
}
此外,您可以考虑在排序时取消绑定任何 UI 元素(通过任何一种方法),您只需支付重新绑定一次的费用:
有趣的是,如果这是BindingList<T>,您可以使用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 => x.SomeProp); list.Clear(); list.AddRange(ordered); 你将避免 ToArray() 不必要的迭代和执行,并且只在 AddRange() 期间这样做一次. (我必须反编译来验证这一点,因为 AddRange 需要一个 IEnumerable,它甚至可能只存储它而不执行它,然后在调用任何特定于 List 的操作之前执行并存储展平的集合。最终相同的性能,但它只是将周期推迟到以后。)
请注意,在 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);
【讨论】:
ObservableCollections 并非设计为可排序的。 List 是可排序的,这是引用 List.Sort() 的答案所使用的底层机制,但 ObservableCollection 不是从 List 派生的,所以你在那里不走运。 Imo,“正确”的解决方案不是尝试对 ObservableCollection 进行排序,而是实现 ICollectionView 并将其实例绑定到您的控件。该接口添加了排序方法,并具有 Silverlight 控件(好吧,无论如何都支持它的控件,例如 DataGrid)识别的额外好处,因此您的排序可以直接从 UI 层使用。这个问题可能会有所帮助:
【讨论】:
我点击了这篇文章中提到的链接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 上
能否提出一些问题。谢谢
【讨论】:
【讨论】: