如何以高效的方式向数据绑定的ObservableCollection添加大量项目

问题描述 投票:2回答:3

许多先前的问题已经出现了相关问题(见下文),但所讨论的解决方案似乎都不适用于这种情况。有问题的应用程序使用ObservableCollection<T>通过数据绑定驱动常规WPF ListBox(带有一些自定义样式)。 ObservableCollection可能包含大量项目,但由于ListBox默认以虚拟方式运行,因此这不是问题。 (具有数十万件物品的“静态”表现非常值得尊敬。)

但是,如果集合已经包含大量项目,然后添加了更多的项目(通过ObservableCollection<T>.Add()),由于所有NotifyCollectionChanged事件被触发,UI不可避免地暂停一段时间。这里推荐的解决方法是对ObservableCollection进行子类化并实现一个AddRange()方法,该方法将新元素添加到(protected)Items集合中,然后使用NotifyCollectionChanged调用NotifyCollectionChangedAction.Reset

根据我的经验,这解决了一个问题,但创造了另一个问题。虽然不再有大量的Add事件被引发,但Reset通知会导致ListBox重新评估整个集合,如果它包含数万个项目,则可能需要相当长的时间。这与在目标应用程序中可能经常添加大量项目的事实相结合,意味着应用程序长时间咀嚼大量CPU,同时ListBox消化所有新信息。

事后可以说,ObservableCollection<T>不是向用户提供这么大的数据集的正确工具,但是到目前为止,很难看到一种简单的方法来重新架构应用程序来处理这个问题。

感谢收到的建议;提前谢谢了。

相关问题:

.net wpf listbox observablecollection
3个回答
0
投票

尽量不要直接绑定到你的ObservableCollection,而是绑定到ICollectionView

这样,在向OC添加项目时,您的UI不会受到影响,因为您的Items Control未绑定到您的OC,当您完成向OC添加项目时,您只需通过调用ICollectionView更新您的CollectionViewSource.GetDefatultView(),并使用新的UI更新您的UI OC州......

这是我如何做到这一点,我从来没有注意到任何UI问题(授予我从未尝试过数十万项,但我确实尝试了数千项,并没有注意到任何UI问题所以我很确定这将解决你的问题问题:

Task.Factory.StartNew(() => SessionList = serviceAgent.GetSessions(someId, someStartDate)).
ContinueWith(t => Sessions.Add(SessionList), TaskScheduler.FromCurrentSynchronizationContext()).
ContinueWith(t => SessionsView = CollectionViewSource.GetDefaultView(Sessions),
                TaskScheduler.FromCurrentSynchronizationContext());

qazxsw poi是OC和qazxsw poi是qazxsw poi ...

这也带来了额外的好处。这将使用Sessions在后台线程上获取记录,它将允许您以多种方式操作View,而不会影响实际的底层集合或必须对集合运行LINQ查询并显示生成的集合...


0
投票

虽然这只是字符串,但我没有看到ListBox花费很长时间来消化新信息。不能只使用Notify或集合将脱离sych

此单击在大约0.4秒内添加100万行到100万行。 不只是添加行的时间 - UI在0.4秒内刷新。

如果在添加之前向下滚动,甚至可以将正确的项目放入视图中。

SessionsView

0
投票

进一步的研究以及对启动行为的一些思考为这个问题找到了答案。

在启动时,应用程序能够在几秒钟内将200,000个项目读入ListBox,因此它应该能够轻松维持每秒100个附加项的更新速率。根本问题是Dispatcher的参与,因为新项目的创建是在一个单独的线程中进行的。所以改变这个代码:

ICollectionView

对此:

TPL

即迭代在调度程序中添加的项目而不是外部对性能产生巨大差异,这意味着我根本不需要调用重置操作。

© www.soinside.com 2019 - 2024. All rights reserved.