Click here to Skip to main content
13,247,689 members (65,590 online)
Click here to Skip to main content
Add your own
alternative version

Stats

35.8K views
384 downloads
8 bookmarked
Posted 2 Jul 2012

Thread Safe Improvement for ObservableCollection

, 2 Jul 2012
Rate this:
Please Sign up or sign in to vote.
Why didn’t Microsoft provide this in the ObservableCollection?

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)

Share

About the Author

Clifford Nelson
Software Developer (Senior) Clifford Nelson Consulting
United States United States
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 eight years has been working primarily as a senior WPF/C# and Silverlight/C# developer. Currently working as WPF developer with BioNano Genomics in San Diego, CA redesigning their UI for their camera system. he can be reached at qck1@hotmail.com.

You may also be interested in...

Comments and Discussions

 
BugA race condition can result in the UI displaying each item twice Pin
Dave Mackersie4-Nov-15 7:16
memberDave Mackersie4-Nov-15 7:16 
AnswerRe: A race condition can result in the UI displaying each item twice Pin
Clifford Nelson4-Nov-15 9:54
memberClifford Nelson4-Nov-15 9:54 
Questionperformance Pin
kadzbi26-May-14 0:24
memberkadzbi26-May-14 0:24 
QuestionChange made in .Net 4.5.1 (at least) Pin
BC3Tech16-May-14 8:32
memberBC3Tech16-May-14 8:32 
AnswerRe: Change made in .Net 4.5.1 (at least) Pin
Clifford Nelson4-Nov-15 9:54
memberClifford Nelson4-Nov-15 9:54 
QuestionNot thread-safe Pin
Michael Bendtsen4-Dec-12 3:25
memberMichael Bendtsen4-Dec-12 3:25 
AnswerRe: Not thread-safe Pin
Clifford Nelson4-Dec-12 6:20
memberClifford Nelson4-Dec-12 6:20 
QuestionNice try Pin
Jasper4C#3-Jul-12 3:54
memberJasper4C#3-Jul-12 3:54 
AnswerRe: Nice try Pin
FatCatProgrammer3-Jul-12 5:11
memberFatCatProgrammer3-Jul-12 5:11 
AnswerRe: Nice try Pin
Clifford Nelson3-Jul-12 7:54
memberClifford Nelson3-Jul-12 7:54 
AnswerRe: Nice try Pin
Clifford Nelson3-Jul-12 7:50
memberClifford Nelson3-Jul-12 7:50 
QuestionReponse to your question Pin
Nicolas Dorier3-Jul-12 2:49
memberNicolas Dorier3-Jul-12 2:49 
GeneralRe: Reponse to your question Pin
Clifford Nelson3-Jul-12 7:59
memberClifford Nelson3-Jul-12 7:59 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

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