Jon*_*len 68 .net wpf multithreading thread-safety collectionview
在后台线程上更新业务对象的集合时,我收到以下错误消息:
这种类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection.
好的,这是有道理的.但它也引出了一个问题,什么版本的CollectionView支持多个线程,如何让我的对象使用它?
小智 87
使用:
System.Windows.Application.Current.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
(Action)delegate()
{
// Your Action Code
});
Run Code Online (Sandbox Code Playgroud)
Nat*_*ips 64
以下是对Jonathan发现的实现的改进.首先,它在与之关联的调度程序上运行每个事件处理程序,而不是假设它们都在同一个(UI)调度程序上.其次,它使用BeginInvoke来允许在我们等待调度程序可用时继续处理.这使得解决方案在后台线程通过每个更新之间进行大量更新的情况下更快.也许更重要的是,它克服了在等待Invoke时由阻塞引起的问题(例如,当使用带有ConcurrencyMode.Single的WCF时可能发生死锁).
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
因为我们使用的是BeginInvoke,所以在调用处理程序之前,通知的更改可能会被撤消.这通常会导致"指数超出范围".根据列表的新(已更改)状态检查事件参数时抛出异常.为了避免这种情况,所有延迟事件都将被重置事件替换.在某些情况下,这可能会导致过度重绘.
找到一个.
public class MTObservableCollection<T> : ObservableCollection<T>
{
public override event NotifyCollectionChangedEventHandler CollectionChanged;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
var eh = CollectionChanged;
if (eh != null)
{
Dispatcher dispatcher = (from NotifyCollectionChangedEventHandler nh in eh.GetInvocationList()
let dpo = nh.Target as DispatcherObject
where dpo != null
select dpo.Dispatcher).FirstOrDefault();
if (dispatcher != null && dispatcher.CheckAccess() == false)
{
dispatcher.Invoke(DispatcherPriority.DataBind, (Action)(() => OnCollectionChanged(e)));
}
else
{
foreach (NotifyCollectionChangedEventHandler nh in eh.GetInvocationList())
nh.Invoke(this, e);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
http://www.julmar.com/blog/mark/2009/04/01/AddingToAnObservableCollectionFromABackgroundThread.aspx
| 归档时间: |
|
| 查看次数: |
35063 次 |
| 最近记录: |