在不冻结GUI的情况下,向大型数据绑定的ObservableCollection中添加/删除许多项目 [英] Add/Remove many items to/from a large databound ObservableCollection without freezing the GUI

查看:79
本文介绍了在不冻结GUI的情况下,向大型数据绑定的ObservableCollection中添加/删除许多项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我和我的团队正在开发一个WPF应用程序,该应用程序显示几个并发的XamDataChart控件(通过Infragistics).每个图表都绑定到一个不同的ObservableCollection,后者最多可以包含200万个点.对于每个图表,DispatcherTimer都会定期检索要追加到集合中的新项目(每100毫秒最多1000个).每次有新商品出现时,都会将它们添加到集合的尾部",并从头部"中删除相同数量的商品,以使该集合中的商品数量在整个时间范围内保持恒定.

My team and I are developing a WPF application that displays several concurrent XamDataChart controls (by Infragistics). Each chart is bound to a different ObservableCollection that can contain up to 2 million points. For each chart, a DispatcherTimer periodically retrieves new items (up to 1000 every 100 ms) that are to be appended to the collection. Every time new items come, they are added to the "tail" of a collection and the same amount is removed from the "head", so that the amount of items in the collection remains constant across time.

我们面临的问题是添加/删除操作冻结了GUI,因为该集合只能由主线程修改.我们尝试了许多方法(BackgroundWorker,Application.Current.Dispatcher和DispatcherPriority.Background,Task.Factory等),但似乎都无法解决问题,并且GUI一直处于冻结状态.

The problem we are facing is that the add/remove operations are freezing the GUI, because the collection can only be modified by the main thread. We have tried many approaches (BackgroundWorker, Application.Current.Dispatcher with DispatcherPriority.Background, Task.Factory, etc.) but none of them seems to solve the problem and the GUI keeps freezing.

能否请您提供有关在保持GUI响应能力的同时处理大量绑定数据的最佳方法的建议?

Could you please advise us on the best approach for handing large amount of bound data while keeping the GUI responsive?

更新:

1)如下面我的评论所示,我们已经在抑制OnCollectionChanged的同时尝试添加和删除项目.即使它似乎对少量数据有影响,但在我们的方案中,这种解决方案的优势实际上是无法观察到的.

1) As indicated in my comment below, we have already tried to add and remove items while suppressing the OnCollectionChanged. Even if it seems to have effect with a small amount of data, in our scenario the advantages of this solution are really not observable.

2)数据是在单独的线程中准备和收集的.这是一个长期运行的操作,但没有明显的缓慢或无响应.当数据传递到图表组件以进行渲染时,应用程序将冻结.

2) Data are prepared and collected in a separate thread. This is a long-running operation, yet no slowness or unresponsiveness is evident. The application freezes when data are passed on to the chart component for rendering.

3)以下是生成数据(在单独的线程中)并在UI上显示数据的方法:

3) Here are the methods that generate data (in a separate thread) and display data on the UI:

private void GenerateDataButtonClick(object sender, RoutedEventArgs e)
{
   Task<List<RealTimeDataPoint>> task = Task.Factory.StartNew(() =>           this.RealTimeDataPointGenerator.GenerateData(2000000));
   Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>  {                                                                                                    this.DataPoints.Clear();
                                                                                            this.DataPoints.AddRange(task.Result);
                                                                                                 if (!this.StartDataFeedButton.IsEnabled)
                                                                                                     this.StartDataFeedButton.IsEnabled = true;
                                                                                             }));
}

public void DispatcherTimerTick(object sender, EventArgs e)
{
   Task<List<RealTimeDataPoint>> task = Task.Factory.StartNew(() => this.RealTimeDataPointGenerator.GenerateData(1000));
   Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => {                                                                                                  this.DataPoints.RemoveRange(0, task.Result.Count);                                                                                                  this.DataPoints.AddRange(task.Result);                                                                                              }));
}

预先感谢, 詹卢卡

推荐答案

在不了解您的情况的情况下很难知道正确的建议,因此,如果您愿意,建议您在Infragistics论坛上发布示例并寻求帮助还没有这样做,如果有的话,请回复该帖子的链接,我将进行研究.

Its difficult to know the correct suggestion without knowing more about your scenario, so I'd recommend posting a sample to the Infragistics forums and asking for assistance, if you have not already done so, and if you have, please respond with a link to the post, and I'll take a look at it.

如果作为单独的操作一次更新许多点,则有助于使集合仅引发一个事件,而不是引发每个事件.例如,如果要通过重复调用添加"来更新集合的全部内容,则最好发送一个重置"事件,而不是发送所有单个事件.但是似乎您已经在调用AddRange,我相信它只会向图表发送一个通知.

If you are updating many many points at once as separate operations it can be helpful to make your collection raise just one event rather than each individual event. For example, if you were updating the entire contents of the collection by calling Add repeatedly, it would be best to send one Reset event, rather than all the individual events. But it seems as if you are already calling AddRange, which I believe only sends one notification to the chart.

如果您只有两个系列,并且每100ms仅更新一次,那么我认为这不会导致UI冻结,但是如果您有多个单独的系列,则要通过单独的调度程序交互来分别更新数据,实际上,刷新图表会超出您的预期.

If you have just two series and are only updating them once every 100ms, I don't believe this should be causing UI freezing, but if you have many separate series that you are updating the data for individually with separate dispatcher interactions you will actually cause many more refreshes to the chart, than perhaps you intend.

该图表将分批修改并限制刷新次数,但是它使用分派器执行此操作,因此,如果您有15个不同的系列以不同的时间间隔进行更新,并且全部作为单独的分派器thunk,那么您将与通过在同一调度程序实体中更新多个系列数据源来限制更新数量相比,对图表的更新要多得多.

The chart will batch up modifications and limit the number of refreshes, but it does this using the dispatcher, so if you have 15 different series that you are updating on different intervals, and all as separate dispatcher thunks then you are going to cause many more updates to the chart than if you throttled the number of updates by updating multiple series data sources in the same dispatcher thunk.

此外,如果您使用的是上面的代码中的CategoryDateTimeXAxis,则可能会遇到限制,即它当前在修改时对日期列进行排序,这会破坏该范围的性能.在这种情况下,建议您针对该轴类型提交功能请求,以支持预先排序的数据.

Additionally, if you are using the CategoryDateTimeXAxis, in your above code, you are likely hitting the limitation that it currently sorts the date column upon modification, which will murder your performance at that scale. In this instance, I'd recommend submitting a feature request for that axis type to support pre-sorted data.

如果您的数据项支持INotifyPropertyChanged,但您没有使用它来通知图表值更改,则最好使用不实现INotifyPropertyChanged的项类型.如果您提交实现此接口的项目,则图表会假定它需要订阅此项目才能收到有关更改的通知(您可能从未打算进行此更改).这听起来似乎不成问题,但是如果您有200万条记录正在频繁更新,那么很多事件订阅都是无缘无故的.

If your data items support INotifyPropertyChanged, but you are not using this to notify the chart of value changes, it would be far better to use an item type that does not implement INotifyPropertyChanged. If you submit items that implements this interface the chart assumes it needs to subscribe to this in order to be notified of changes (that you may never be intending to make). This may not sound like a problem, but if you have 2 million records that you are updating with high frequency, that is a lot of event subscriptions to incur for no purpose.

据我所知,该图表从属性绑定中检索值要比字符串索引器快得多,因此请确保它是一个简单的属性,而不是MemberPath中的点状属性路径.

The chart, to my knowledge, is far faster at retrieving values from a property binding than a string indexer, so make sure its a simple property, and also not a dotted property path in your MemberPath.

希望此信息对您有用.但是,使用可运行的样本来诊断问题会容易得多,该样本提供了可能导致问题的原因的所有上下文.

Hopefully this information will be useful to you. But it would be far easier to diagnose the issue with a runnable sample that provides all the context for what could be causing the issue.

这篇关于在不冻结GUI的情况下,向大型数据绑定的ObservableCollection中添加/删除许多项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆