Dot-Net

我在哪裡可以獲得執行緒安全的 CollectionView?

  • January 26, 2010

在後台執行緒上更新業務對象集合時,我收到以下錯誤消息:

這種類型的 CollectionView 不支持從不同於 Dispatcher 執行緒的執行緒更改其 SourceCollection。

好的,這是有道理的。但它也引出了一個問題,什麼版本的 CollectionView 支持多執行緒以及如何讓我的對象使用它?

以下是對 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);
           }
   }
}

因為我們使用的是 BeginInvoke,所以通知的更改可能在呼叫處理程序之前被撤消。這通常會導致“索引超出範圍”。根據列表的新(更改)狀態檢查事件參數時引發異常。為了避免這種情況,所有延遲事件都替換為重置事件。在某些情況下,這可能會導致過度重繪。

採用:

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

引用自:https://stackoverflow.com/questions/2137769