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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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