在哪里可以获得线程安全的集合视图?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (17)

在更新后台线程上的业务对象集合时,我得到以下错误消息:

这种类型的Collection View不支持与Dispatcher线程不同的线程对其SourceCollection的更改。

好吧,这是有道理的。但是它也回避了一个问题,什么版本的Collection View支持多线程,以及如何让我的对象使用它?

提问于
用户回答回答于

首先,它在与其关联的调度程序上运行每个事件处理程序,而不是假设它们都在同一个(UI)Dispatcher上。其次,它使用BeginInvoke允许继续处理,而我们则等待调度程序可用。这使得解决方案在后台线程在每个线程之间执行大量更新的情况下速度要快得多。也许更重要的是,它克服了等待调用时阻塞所造成的问题(例如,在使用WCF和ConcurrencyMode.Single时可能会出现死锁)。

public class MTObservableCollection<T> : ObservableCollection<T>
{
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged;
        if (CollectionChanged != null)
            foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList())
            {
                DispatcherObject dispObj = nh.Target as DispatcherObject;
                if (dispObj != null)
                {
                    Dispatcher dispatcher = dispObj.Dispatcher;
                    if (dispatcher != null && !dispatcher.CheckAccess())
                    {
                        dispatcher.BeginInvoke(
                            (Action)(() => nh.Invoke(this,
                                new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
                            DispatcherPriority.DataBind);
                        continue;
                    }
                }
                nh.Invoke(this, e);
            }
    }
}

因为我们使用的是BeginInvoke,所以有可能在调用处理程序之前取消所通知的更改。这通常会导致“索引超出了范围”。当事件参数被选中时,会根据列表的新(更改)状态抛出异常。为了避免这种情况,所有延迟事件都被重置事件替换。在某些情况下,这可能导致过度重绘。

用户回答回答于

用:

System.Windows.Application.Current.Dispatcher.Invoke(
    System.Windows.Threading.DispatcherPriority.Normal,
    (Action)delegate() 
    {
         // Your Action Code
    });

扫码关注云+社区