在后台线程上更新业务对象集合时,我收到以下错误消息:
此类型的CollectionView不支持从不同于Dispatcher线程的线程更改其SourceCollection.
好吧,这是有道理的.但它也回避了一个问题,什么版本的CollectionView支持多线程,以及如何让我的对象使用它?
在后台线程上更新业务对象集合时,我收到以下错误消息:
此类型的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撤消.这通常会导致"索引超出范围"根据列表的新(更改)状态判断事件参数时引发的异常.为了避免这种情况,所有延迟事件都将替换为重置事件.在某些情况下,这可能会导致过度重画.