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

ste*_*g89 18 c# wpf performance observablecollection

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

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

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

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

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

Dav*_*son 8

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

  • 不要使用ObservableCollection<T>,这样做很慢,因为每次添加一个项目都会引发事件.使用更快的东西,List<T>并在添加所有项目提出属性更改通知.
  • 在后台线程中预先创建项目,然后将它们推送到您的集合中.
  • 检查所涉及的代码的其他部分,看看是否有膨胀和修剪.


que*_*atl 6

你说1000,所以我会坚持这个数字.

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

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

如果可观察集合没有AddRange,要么使用不同的集合,要么编写自己的集合,只需一个包装器即可.我们的目标是不在每一个Add()中引发Changed事件,但是在合理计算它们之后,或者 - 也许只是跳过提高在添加项目时更改并在某些固定时间间隔内提高更改?如果您的数据以恒定速率无限期地"流入",这将特别有益.

当然,在屏幕上显示的那些项目中,您也可以自己进行渲染.如果您的ItemTemplates很复杂,1000个对象乘以1000个可视图层/属性实例可能会破坏用户体验.您是否已将ItemTemplates简化为最低限度?

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

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


ste*_*g89 6

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