22

我有一个设置,其中可能会将数千个项目(想想 3000-5000)添加到ObservableCollection绑定到某个可视界面的项目中。目前,添加它们的过程非常缓慢(大约 4 秒/1000 个项目),当然 GUI 在此期间没有响应。有什么好方法可以一次将这么多项目移动到一个集合中而不用担心系统锁定?我看过DispatcherTimer但我不确定它是否能提供我需要的一切。

另一个问题 - 我可以做些什么来加快这些对象的创建,以便将它们添加到集合中不需要很长时间?目前我像这样使用它们:Collection.Add(new Item(<params>))在后台线程中预先生成项目是否会显着减少添加它们所需的时间?

编辑:虚拟化是不可能的。要求指定WrapPanel外观,因此显示实际上是ListBox具有模板化 ItemsPanel 的

Edit2:根据秒表,瓶颈实际上是将物品放入我的ObservableCollection. 我将尝试更改该集合类型并做我自己的通知,看看是否会大大加快它的速度。

Edit3:所以答案在一个地方 - 我通过创建一个继承自ObservableCollection. 这个类做了两件事——暴露一个方法来一次添加集合,并添加了抑制CollectionChanged事件的能力。通过这些更改,添加 3000 个项目所需的时间大约为 0.4 秒(改进了 97%)。链接详细说明了这些更改的实施。

4

5 回答 5

9

你说的是 1000,所以我会以这个数字为例。

IIRC,可观察集合有一个小缺点——如果你一个一个地添加项目,它会为每个项目引发一次通知。这意味着您有 1000 条通知针对 1000 个项目,并且 UI 线程将以致命的速度运行,以跟上重新绘制屏幕的速度。

你需要尽快重绘吗?也许你可以批量添加?将 1000 件物品分成几包 100 件物品,或者多包 50 或 20 件物品。然后,不要将所有物品一件一件地放入,而是将它们放入包中。但请注意:您必须使用一些方法,例如由集合本身实现的 AddRange,而不是通过 LINQ,否则您将再次进行一对一的插入。如果您找到这样的方法,它应该会显着减少事件的数量,因为集合应该在每次 AddRange 调用时只引发一次 Changed 事件。

如果 observable 集合没有 AddRange,要么使用不同的集合,要么编写自己的集合,只需要一个包装器就足够了。目标是不要在每个 Add() 中引发 Changed 事件,而是在对它们进行合理计数之后,或者 - 可能只是在添加项目时跳过引发 Changed 并在某些固定时间间隔引发 Changed?如果您的数据以恒定速率无限期地“流入”,这将是特别有益的。

当然,在屏幕上出现这么多项目时,您也可以自己进行渲染。如果您的 ItemTemplates 很复杂,那么 1000 个对象乘以 1000 个可视层/属性实例可能只会扼杀用户体验。您是否已将 ItemTemplates 简化到最低限度?

最后一件事:考虑使用虚拟化 StackPanel 作为 ItemsControl/ListBoxes 中的 ItemPanel。它可以大大减少内存占用和单个时间点绘制的项目数。这不一定有助于提高引发的数量或事件,但当您拥有复杂的项目模板时,它可能会有很大帮助!

编辑:您正在使用 ObservableCollection,所以我假设 WPF/Silverlight .. 如果这不正确,请更新问题

于 2012-08-14T18:33:48.833 回答
8

Binding出于这个原因,WPF支持并发。尝试设置Binding.IsAsync为真。此外。

  • 不要使用ObservableCollection<T>,这样做很慢,因为每次添加项目时都会引发事件。添加所有项目,使用更快的方法List<T>并提高属性更改通知。
  • 在后台线程中预先创建您的项目,然后将它们推送到您的收藏中。
  • 检查涉及的代码的其他部分,看看是否有膨胀和修剪。
于 2012-08-14T18:24:33.903 回答
5

根据要求,这是我解决此问题的方法。我首先创建了一个继承自ObservableCollection. 这个类做了两件事——公开一个方法来一次添加整个集合,并添加了抑制CollectionChanged事件的能力。通过这些更改,添加 3000 个项目所需的时间大约为 0.4 秒(改进了 97%)。链接详细说明了这些更改的实施。

于 2016-09-12T14:08:17.303 回答
4

您可以尝试的另一件事:子类 ObservableCollection 并使其支持批量加载 (AddRange)。这是一篇文章: AddRange 和 ObservableCollection

于 2012-08-14T19:19:47.133 回答
0

对于第二个问题,如果在您的 GUI 中使用 WPF 技术,您可以使用 VirualizingStackPanel 提高性能,允许您仅创建可见项目

于 2012-08-14T18:30:35.387 回答