如何通过工作线程更新 ObservableCollection? [英] How do I update an ObservableCollection via a worker thread?

查看:71
本文介绍了如何通过工作线程更新 ObservableCollection?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 ObservableCollectiona_collection; 该集合包含n"个项目.每个项目 A 看起来像这样:

I've got an ObservableCollection<A> a_collection; The collection contains 'n' items. Each item A looks like this:

public class A : INotifyPropertyChanged
{

    public ObservableCollection<B> b_subcollection;
    Thread m_worker;
}

基本上,所有这些都连接到 WPF 列表视图 + 详细信息视图控件,该控件在单独的列表视图中显示所选项目的 b_subcollection(2 路绑定、属性更改更新等).

Basically, it's all wired up to a WPF listview + a details view control which shows the b_subcollection of the selected item in a separate listview (2-way bindings, updates on propertychanged etc.).

当我开始实现线程时,问题就出现在我身上.整个想法是让整个 a_collection 使用它的工作线程做工作",然后更新它们各自的 b_subcollections 并让 gui 实时显示结果.

The problem showed up for me when I started to implement threading. The entire idea was to have the whole a_collection use it's worker thread to "do work" and then update their respective b_subcollections and have the gui show the results in real time.

当我尝试它时,我得到一个异常,说只有 Dispatcher 线程可以修改 ObservableCollection,并且工作停止了.

When I tried it , I got an exception saying that only the Dispatcher thread can modify an ObservableCollection, and work came to a halt.

谁能解释这个问题,以及如何解决它?

Can anyone explain the problem, and how to get around it?

推荐答案

从技术上讲,问题不在于您正在从后台线程更新 ObservableCollection.问题是,当您这样做时,集合会在导致更改的同一线程上引发其 CollectionChanged 事件 - 这意味着正在从后台线程更新控件.

Technically the problem is not that you are updating the ObservableCollection from a background thread. The problem is that when you do so, the collection raises its CollectionChanged event on the same thread that caused the change - which means controls are being updated from a background thread.

为了在控件绑定到集合时从后台线程填充集合,您可能必须从头开始创建自己的集合类型以解决此问题.不过,有一个更简单的选项可能适合您.

In order to populate a collection from a background thread while controls are bound to it, you'd probably have to create your own collection type from scratch in order to address this. There is a simpler option that may work out for you though.

将 Add 调用发布到 UI 线程上.

Post the Add calls onto the UI thread.

public static void AddOnUI<T>(this ICollection<T> collection, T item) {
    Action<T> addMethod = collection.Add;
    Application.Current.Dispatcher.BeginInvoke( addMethod, item );
}

...

b_subcollection.AddOnUI(new B());

此方法将立即返回(在项目实际添加到集合之前)然后在 UI 线程上,项目将添加到集合中,每个人都应该高兴.

This method will return immediately (before the item is actually added to the collection) then on the UI thread, the item will be added to the collection and everyone should be happy.

然而,现实情况是,由于所有跨线程活动,此解决方案可能会在重负载下陷入困境.一个更有效的解决方案是将一堆项目批处理并定期将它们发布到 UI 线程,这样您就不会为每个项目跨线程调用.

The reality, however, is that this solution will likely bog down under heavy load because of all the cross-thread activity. A more efficient solution would batch up a bunch of items and post them to the UI thread periodically so that you're not calling across threads for each item.

BackgroundWorker 类实现了一种模式,允许您可以通过其 ReportProgress 方法报告进度一个后台操作.通过 ProgressChanged 事件在 UI 线程上报告进度.这可能是您的另一个选择.

The BackgroundWorker class implements a pattern that allows you to report progress via its ReportProgress method during a background operation. The progress is reported on the UI thread via the ProgressChanged event. This may be another option for you.

这篇关于如何通过工作线程更新 ObservableCollection?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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