猿问

如何通过工作线程更新观察者集合?

如何通过工作线程更新观察者集合?

我有一个ObservableCollection<A> a_collection;集合包含“n”项。每一项A如下所示:

public class A : INotifyPropertyChanged{

    public ObservableCollection<B> b_subcollection;
    Thread m_worker;}

基本上,它都连接到一个WPF列表视图+一个细节视图控件,该控件在单独的listview(双向绑定、属性更改更新等)中显示所选项的b_子集合。当我开始实现线程时,问题就出现了。整个想法是让整个a_集合使用它的辅助线程“做工作”,然后更新它们各自的b_子集合,让gui实时显示结果。

当我尝试它时,我得到了一个异常,它说只有Dispatcher线程才能修改一个观测者集合,然后工作就停止了。

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

干杯


月关宝盒
浏览 430回答 3
3回答

慕容708150

从技术上讲,问题不是要从后台线程中更新观测者集合。问题是,当您这样做时,集合会在导致更改的同一线程上引发它的Collection Changed事件-这意味着正在从后台线程更新控件。为了在控件绑定到后台线程时从后台线程填充集合,您可能需要从头创建自己的集合类型来解决这个问题。不过,有一个更简单的选择可能适合你。将添加调用发布到UI线程。public&nbsp;static&nbsp;void&nbsp;AddOnUI<T>(this&nbsp;ICollection<T>&nbsp;collection,&nbsp;T&nbsp;item)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;Action<T>&nbsp;addMethod&nbsp;=&nbsp;collection.Add; &nbsp;&nbsp;&nbsp;&nbsp;Application.Current.Dispatcher.BeginInvoke(&nbsp;addMethod,&nbsp;item&nbsp;);}...b_subcollection.AddOnUI(new&nbsp;B());此方法将立即返回(在项目实际添加到集合之前),然后在UI线程上,项目将被添加到集合中,每个人都应该很高兴。然而,现实情况是,由于所有的跨线程活动,这种解决方案很可能会在沉重的负荷下陷入困境。一个更有效的解决方案是对一组项目进行批处理,并定期将它们发布到UI线程中,这样您就不会为每个项目跨线程进行调用。这个背景工作者类实现了允许您通过其报告进度方法在后台操作期间。进度通过ProgressChanged事件报告在UI线程上。这可能是你的另一个选择。

HUWWW

.NET 4.5的新选项从.NET 4.5开始,有一个内置机制来自动同步对集合和分派的访问CollectionChanged事件到UI线程。要启用此功能,需要调用BindingOperations.EnableCollectionSynchronization&nbsp;在您的UI线程中.EnableCollectionSynchronization做两件事:记住调用它的线程,并导致数据绑定管道封送处理。CollectionChanged线程上的事件。在处理封送事件之前获取集合上的锁,以便运行UI线程的事件处理程序在从后台线程修改集合时不会尝试读取集合。非常重要的是,这并不能解决所有的问题。*确保线程安全访问固有的非线程安全集合。你必须合作通过从后台线程获取相同的锁来使用框架,当集合即将被修改时。因此,正确操作所需的步骤如下:1.决定使用哪种锁这将确定EnableCollectionSynchronization一定要用。大多数时候很简单lock这样的话就足够了这种过载是标准的选择,但是如果您使用的是一些花哨的同步机制,那么支持自定义锁.2.创建集合并启用同步根据选择的锁机制,调用适当的重载。在UI线程上..如果使用标准lock语句,则需要将LOCK对象作为参数提供。如果使用自定义同步,则需要提供CollectionSynchronizationCallback委托和上下文对象(可以是null)。调用时,此委托必须获取自定义锁,然后调用Action传递给它并在返回前释放锁。3.合作,在修改之前锁定集合您还必须在自己修改集合时使用相同的机制锁定集合;lock()在传递给EnableCollectionSynchronization在简单场景中,或者在自定义场景中使用相同的自定义同步机制。

梦里花落0921

使用.NET 4.0,您可以使用以下一行程序:.AddApplication.Current.Dispatcher.BeginInvoke(new&nbsp;Action(()&nbsp;=>&nbsp;this.MyObservableCollection.Add(myItem)));.RemoveApplication.Current.Dispatcher.BeginInvoke(new&nbsp;Func<bool>(()&nbsp;=>&nbsp;this.MyObservableCollection.Remove(myItem)));
随时随地看视频慕课网APP
我要回答