我在哪里可以得到一个线程安全的CollectionView?我在、可以得到、线程、安全

由网友(  ╋只为你坏♂ ╋只为你乖♀)分享简介:当在后台线程更新业务对象的集合,我得到这个错误信息:When updating a collection of business objects on a background thread I get this error message:该类型的CollectionView不支持从一个线程更改其SourceCo...

当在后台线程更新业务对象的集合,我得到这个错误信息:

When updating a collection of business objects on a background thread I get this error message:

该类型的CollectionView不支持从一个线程更改其SourceCollection从调度线程不同。

This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

好吧,这是有道理的。但它也引出了一个问题,什么版本的CollectionView的不支持多线程,如何让我的对象使用它?

Ok, that makes sense. But it also begs the question, what version of CollectionView does support multiple threads and how do I make my objects use it?

推荐答案

以下是由乔纳森发现执行情况的改善。首先,它运行在与它相关的调度每个事件处理程序,而不是假定它们都在相同的(UI)的调度。其次,它使用的BeginInvoke允许加工继续在我们等待调度变得可用。这使得该解决方案更快的情况下在后台线程做大量的与每个人之间的处理更新。或许更重要的是它克服造成阻塞,同时等待调用(死锁可以使用WCF与ConcurrencyMode.Single时发生例如)的问题。

The following is an improvement on the implementation found by Jonathan. Firstly it runs each event handler on the dispatcher associated with it rather than assuming that they are all on the same (UI) dispatcher. Secondly it uses BeginInvoke to allow processing to continue while we wait for the dispatcher to become available. This makes the solution much faster in situations where the background thread is doing lots of updates with processing between each one. Perhaps more importantly it overcomes problems caused by blocking while waiting for the Invoke (deadlocks can occur for example when using WCF with 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,它有可能被通知的变化撤消的处理程序被调用之前。这通常将导致一个索引超出范围。当事件参数对列表中的新(修改)状态检查被抛出的异常。为了避免这种情况,所有的延误事件被替换为复位事件。这可能导致过度的重绘在一些情况下

Because we are using BeginInvoke, it is possible that the change being notified is undone before the handler is called. This would typically result in an "Index was out of range." exception being thrown when the event arguments are checked against the new (altered) state of the list. In order to avoid this, all delayed events are replaced with Reset events. This could cause excessive redrawing in some cases.

阅读全文

相关推荐

最新文章