为什么ObservableCollection不支持批量更改?

13
< p >ObservableCollection支持AddRangeRemoveRange等操作可能导致的潜在问题是什么?微软为什么没有提供它们,现在ObservableCollection在WPF中被如此频繁地使用,一定有原因。

您可以实现自己的集合,支持批量操作并实现INotifyCollectionChanged。如果我将这样的控件绑定到ItemsControl会发生什么?

是否有人知道不支持批量更改的ItemsControls?


7
Microsoft.VisualStudio.Language.Intellisense.BulkObservableCollection<T> 中有一个 BulkObservableCollection 类。http://msdn.microsoft.com/en-us/library/dd867973.aspx - tofutim
4个回答

4
有很多扩展可以在互联网上找到,为ObservableCollection添加了add/remove range的概念,或者允许您延迟更新并手动触发它们。例如,请参见此Stack Overflow问题:ObservableCollection不支持AddRange方法,因此我会收到每个添加的项目的通知,那么INotifyCollectionChanging怎么办? 您还可以实现一个批量添加,从而触发重置事件,这将导致UI重新呈现集合中的所有项:http://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/ 这些扩展可以更有效地管理UI更新。一个ItemsControl如何处理详细说明更改项列表的集合更改事件取决于WPF框架本身。我假设它会智能地处理!
我的建议是,如果性能对您很重要,并且您有包含大量正在更新的项的集合,并且遇到性能问题,则子类化ObservableCollection以按最适合您应用程序需求的方式管理集合更改通知。

1
快速浏览链接问题的实现就会发现它是一种低效的实现方式。基本上,每添加一个项目都会引发“CollectionChanged”事件,然后再重置集合! - Kent Boogaart
1
@KentBoogaart 你好,Kent,你是指SO的答案吗?我认为没问题。 AddRange方法遍历添加的项,然后触发一个单一的CollectionChanged事件,其中包含“add”类型的更改和添加的项目列表。但代码格式不太好;-) - ColinE
1
由于RangeObservableCollection扩展了ObservableCollection,对每个项目调用Add会导致为添加的每个项目引发CollectionChangedEvent。然后,在添加所有项目后重置集合会使所有这些努力付之东流。 - Kent Boogaart
3
除了这一点,因为链接的代码还覆盖了 OnCollectionChanged 方法以抑制 CollectionChangedEvent(如果设置了标志);AddRange 方法设置此标志,循环遍历并为每个项调用 Add 方法,然后取消设置该标志。 - Chris

4

我认为这并不是存在任何潜在的缺点或问题,只是它不存在。实际上,您会发现 'System.Collections.Generic' 中的大多数类型也没有提供 'AddRange' 功能。

与此同时,许多人已经创建了自己版本的 'ObservableCollection' 来提供您想要的功能。INotifyCollectionChanged 包含足够的信息,使其处理程序可以注意到是否有一系列项目受到影响,可能是出于这个原因。

最后但并非最不重要的,如果您绑定具有这些“范围”类型操作的集合,您会发现它们将按您预期的方式与 UI 一起工作。


2

NotifyCollectionChangedEventArgs 包含索引信息。删除项目会导致索引重排,插入项目也是如此。因此,虽然不完全不可能,但提供处理范围的能力可能会非常困难,而且可能效率低下。


唯一的索引信息是“发生更改的索引”。这个信息可以通过添加和删除范围操作轻松提供。 - A.R.
@A.R.:不对,如果我移除集合的第一个和最后一个项会怎样?事件参数中只有一个索引,但是需要两个索引。 - Kent Boogaart
有两个索引。一个是“NewStartingIndex”,另一个是“OldStartingIndex”。后者的描述为“获取移动、删除或替换操作发生的索引位置。”此外,除非您要删除集合中的所有项,否则您所描述的情况是不可能发生的,因为范围内的元素是连续的。 - A.R.
1
我的错 - 我误读了 OP。我以为问题是关于为什么没有 RemoveAll,就像 List<T> 一样。你是对的:提供 AddRange/RemoveRange 将非常容易。 - Kent Boogaart

1
微软没有提供它们的原因肯定是有的。 他们并不提供所有可能的功能,这也是成本和需求的权衡。 你可以实现自己的集合,支持批量操作,并实现 INotifyCollectionChanged 接口。 是的。当你这样做时,你会发现集合将不得不在如何/何时传播这些更改方面做出选择。我从未尝试过,但我想象视图或 ViewModel 可以做出比可重用集合更好的决策。

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