Click here to Skip to main content
Click here to Skip to main content

Thread Safe Improvement for ObservableCollection

By , 2 Jul 2012
 

Introduction

I was working on a WPF project where I had the ViewModel mirroring the Model displaying a hierarchical view of the data (like a tree view, but using XamDataGrid). I wanted to have an event in the Model that triggered when a record was added or removed to reduce coupling (probably when changes are made in the Model in the future). This was because I expected to be using the Model side with many different ViewModels, although at this point not sure since I am being given the requirements piece-meal. When I did this in a case where I had a BackgroundWorker, I started having problems with being on the wrong thread. Of course I expected that, and I immediately implemented a Dispatcher on the receiving class using code like the following:

Dispatcher.CurrentDispatcher.Invoke(new Action<StagedBlotterOrderAggViewModel>(Add), adding);

This did not work so I attempted to use DispatcherPriority. Nothing looked right to me, but I tried several options and none worked.

I could go back to a design of trying to ensure that the record updates were done in the BackgroundWorkerCompleted handler, but that would complicate the code.

Of course I know that you can get the Dispatcher from the control, but that was not very elegant. Therefore I started to search the web, and found something interesting at “Have worker thread update ObservableCollection that is bound to a ListCollectionView” (http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/have-worker-thread-update-observablecollection-that-is-bound-to-a.aspx). I was not sure it would work, but I tried it, and it did. Of course I guess eventually I would have come up with inheriting from ObservableCollection<T> since I knew that I could get the Dispatcher from the control and then would not have had to do anything special in the ViewModel, but I am sure this is better than what I would have come up with. I did make a small number of improvements of adding the other constructors.

Here is my slightly improved version of this code that worked so well for me:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows.Threading;
 
namespace Custom.Collections
{
  public class ObservableCollectionEx<t> : ObservableCollection<t>
  {
    // Override the event so this class can access it
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
 
    public ObservableCollectionEx(IEnumerable<t> collection) : base(collection) { }
    public ObservableCollectionEx(List<t> collection) : base(collection) { }
 
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
      // Be nice - use BlockReentrancy like MSDN said
      using (BlockReentrancy())
      {
        var eventHandler = CollectionChanged;
        if (eventHandler != null)
        {
          Delegate[] delegates = eventHandler.GetInvocationList();
          // Walk thru invocation list
          foreach (NotifyCollectionChangedEventHandler handler in delegates)
          {
            var 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);
          }
        }
      }
    }
  }
}</t></t></t></t>

Now my big question is: Why didn’t Microsoft provide this in the original ObservableCollection?

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Clifford Nelson
Software Developer (Senior) ETeam/Delloitte
United States United States
Member
Has been working as a C# developer on contract for the last several years, including 3 years at Microsoft. Previously worked with Visual Basic and Microsoft Access VBA, and have developed code for Word, Excel and Outlook. Started working with WPF in 2007 when part of the Microsoft WPF team. For the last three years has been working primarily as a senior WPF/C# and Silverlight/C# developer. Currently working as WPF developer with PIMCO in Newport Beach, CA.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionNot thread-safe PinmemberMichael Bendtsen4 Dec '12 - 2:25 
QuestionNice try PinmemberJasper4C#3 Jul '12 - 2:54 
QuestionReponse to your question PinmemberNicolas Dorier3 Jul '12 - 1:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 2 Jul 2012
Article Copyright 2012 by Clifford Nelson
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid