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

此类型的CollectionView不支持从不同于Dispatcher线程的线程更改其SourceCollection.

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

推荐答案

以下是Jonathan发现的对实现的改进.首先,它在与其关联的调度器上运行每个事件处理程序,而不是假设它们都在同一个(UI)调度器上.其次,它使用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,所以在调用处理程序之前,通知的更改可能会被undo撤消.这通常会导致"索引超出范围"根据列表的新(更改)状态判断事件参数时引发的异常.为了避免这种情况,所有延迟事件都将替换为重置事件.在某些情况下,这可能会导致过度重画.

.net相关问答推荐

将Visual Studio更新到v17.9.3后,IDE关闭,dotnet.exe命令报告致命错误.内部CLR错误.(0x80131506)

为什么Regex.Escape支持数字符号和空格?

保存时不保留 XML 格式

在 C# 中,如何使用泛型的基类将泛型接口的所有实例注入到单个构造函数中?

判断内部异常的最佳方法?

线程安全性的单元测试?

AsyncLocal 的语义与逻辑调用上下文有何不同?

为什么具有可为空值的 struct 的 HashSet 非常慢?

NonSerialized 属性

如何在 C# 中创建表达式树来表示String.Contains("term")?

获取当前方法的名称

大型 WCF Web 服务请求因 (400) HTTP 错误请求而失败

如何在可取消的异步/等待中处理 TransactionScope?

当程序员说针对接口而不是对象的代码时,他们是什么意思?

如何使用配置转换删除 ConnectionString

关闭 Visual Studio 中所有选项卡但当前选项卡的键盘快捷键?

我应该如何删除 DbSet 中的所有元素?

如何将整个字符串与正则表达式匹配?

泛型类的默认构造函数的语法是什么?

Roslyn 编译代码失败