Synchronization mechanism for an observable object

前端 未结 3 2177
情深已故
情深已故 2021-02-18 16:59

Let\'s imagine we have to synchronize read/write access to shared resources. Multiple threads will access that resource both in read and writing (most of times for reading, some

3条回答
  •  [愿得一人]
    2021-02-18 17:47

    I'm not sure if this is exactly the same issue but when dealing with relatively small amounts of data (2k-3k entries), I have used the below code to facilitate cross thread read/write access to collections bound to UI. This code originally found here.

    public class BaseObservableCollection : ObservableCollection
    {
      // Constructors
      public BaseObservableCollection() : base() { }
      public BaseObservableCollection(IEnumerable items) : base(items) { }
      public BaseObservableCollection(List items) : base(items) { }
    
      // Evnet
      public override event NotifyCollectionChangedEventHandler CollectionChanged;
    
      // Event Handler
      protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
      {
        // Be nice - use BlockReentrancy like MSDN said
        using (BlockReentrancy())
        {
          if (CollectionChanged != null)
          {
            // Walk thru invocation list
            foreach (NotifyCollectionChangedEventHandler handler in CollectionChanged.GetInvocationList())
            {
              DispatcherObject dispatcherObject = handler.Target as DispatcherObject;
    
              // If the subscriber is a DispatcherObject and different thread
              if (dispatcherObject != null && dispatcherObject.CheckAccess() == false)
              {
                // Invoke handler in the target dispatcher's thread
                dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, this, e);
              }
              else
              {
                // Execute handler as is
                handler(this, e);
              }
            }
          }
        }
      }
    }
    

    I have also used the code below (which inherits from the above code) to support raising the CollectionChanged event when items inside the collection raise the PropertyChanged.

    public class BaseViewableCollection : BaseObservableCollection
      where T : INotifyPropertyChanged
    {
      // Constructors
      public BaseViewableCollection() : base() { }
      public BaseViewableCollection(IEnumerable items) : base(items) { }
      public BaseViewableCollection(List items) : base(items) { }
    
      // Event Handlers
      private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
      {
        var arg = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender);
        base.OnCollectionChanged(arg);
      }
    
      protected override void ClearItems()
      {
        foreach (T item in Items) { if (item != null) { item.PropertyChanged -= ItemPropertyChanged; } }
        base.ClearItems();
      }
    
      protected override void InsertItem(int index, T item)
      {
        if (item != null) { item.PropertyChanged += ItemPropertyChanged; }
        base.InsertItem(index, item);
      }
    
      protected override void RemoveItem(int index)
      {
        if (Items[index] != null) { Items[index].PropertyChanged -= ItemPropertyChanged; }
        base.RemoveItem(index);
      }
    
      protected override void SetItem(int index, T item)
      {
        if (item != null) { item.PropertyChanged += ItemPropertyChanged; }
        base.SetItem(index, item);
      }
    }
    

提交回复
热议问题