如何在不锁定GUI的情况下将数千个项目添加到绑定集合中

时间:2012-08-14 18:18:57

标签: c# wpf performance observablecollection

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

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

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

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

Edit3:所以答案在一个地方 - 我通过创建一个继承自ObservableCollection的类来解决这个问题(在下面的帮助下)。这个类做了两件事 - 公开了一次添加集合的方法,并添加了抑制CollectionChanged事件的能力。通过这些更改,添加3000个项目所需的时间大约为.4秒(97%的改进)。 This链接详细说明了这些更改的实施情况。

5 个答案:

答案 0 :(得分:8)

WPF Binding支持并发性。尝试将Binding.IsAsync设置为true。另外。

  • 不要使用ObservableCollection<T>,这样做很慢,因为每次添加一个项目都会引发事件。使用更快的内容,例如List<T>,并在添加所有商品后提高您的房产更改通知
  • 在后台主题中预先创建项目,然后将它们推送到您的收藏中。
  • 检查所涉及的代码的其他部分,看是否有膨胀,并修剪。

答案 1 :(得分:6)

你已经说了1000,所以我只是坚持这个数字。

IIRC,可观察的集合有一个小缺点 - 如果你逐个添加项目,它会每个项目提醒一次。这意味着您有1000个项目的1000个通知,并且UI线程将以致命的速度运行,以便跟上重绘屏幕。

你需要尽快重绘吗?也许你可以批量添加?将1000件物品分成几件100件装,或多件50件或20件装。然后,不要将所有项目逐个放入,而是将它们放入数据包中。但要注意:你必须使用像自己的集合实现的AddRange之类的方法,而不是LINQ,否则你将再次逐个插入。如果你找到这样的方法,它应该显着减少事件的数量,因为集合应该每次AddRange调用只提升一次Changed事件。

如果可观察集合没有AddRange,要么使用不同的集合,要么编写自己的集合,只需一个包装器即可。目标是不在每一个Add()中提出Changed事件,但是在合理计算它们之后,或者 - 可能只是跳过提高添加项目时更改并提高在某些固定时间间隔更改?如果您的数据流入&#34;这将特别有益。无限期地保持不变。

当然,在屏幕上显示的那些项目中,您可能也会自己进行渲染。如果您的ItemTemplates很复杂,1000个对象乘以1000个可视图层/属性实例可能会破坏用户体验。你有没有简化ItemTemplates?

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

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

答案 2 :(得分:4)

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

答案 3 :(得分:4)

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

答案 4 :(得分:0)

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