33

I have an ObservableCollection in my class. And further into my class I have a thread. From this thread I would like to add to my ObservableCollection. But I can't do this:

This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

Note that this is not happening from the UI thread, so i don't have access to the dispatcher.

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
ErikTJ
  • 2,001
  • 3
  • 21
  • 38

3 Answers3

16

The best way to solve this is to pass the Dispatcher object to the start method of the background thread.

void DoBackgroundOperation(ObservableCollection<SomeType> col) {
  var dispatcher = Dispatcher.CurrentDispatcher;
  ThreadStart start = () => BackgroundStart(dispatcher, col);
  var t = new Thread(start);
  t.Start();
}

private static void BackgroundStart(
    Dispatcher dispatcher, 
    ObservableCollection<SomeType> col) {
  ...
  SomeType t = GetSomeTypeObject();
  Action del = () => col.Add(t);
  dispatcher.Invoke(del);
}

Now later on when you need to add to the collection you can use the UI Dispatcher object.

As @Reed pointed out, a more general solution is achieved by using SynchronizationContext. Here's a functional style sample using SynchronizationContext to create a delegate responsible for adding new values. This has the advantage of hiding both the collection and the threading model from the code creating the object.

void DoBackgroundOperation(ObservableCollection<SomeType> col) {
  var context = SynchronizationContext.Current;
  Action<SomeType> addFunc = (SomeType st) => context.Send(() => col.Add(st), null);
  ThreadStart start = () => BackgroundStart(addFunc);
  var t = new Thread(start);
  t.Start();
}

private static void BackgroundStart(Action<SomeType> addFunc) {
  ...
  SomeType t = GetSomeTypeObject();
  addFunc(t);
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 4
    +1: Also, the same approach can be done using SynchronizationContext.Current instead of the dispatcher, if you don't want to take a WPF dependency (ie: you want to also use this code in Windows Forms). – Reed Copsey Feb 19 '10 at 00:21
  • @Reed, added a solution with `SynchronizationContext` that has a functional flavor. – JaredPar Feb 19 '10 at 00:28
  • Thank you for your answer. I will look at this tomorrow as it is 01:30AM here. – ErikTJ Feb 19 '10 at 00:32
  • @JaredPar: If a collection will be used for a view-only WPF control and its backing store will be thread-safe for multiple readers, what are the pros and cons of having the UI thread process updates individually, versus having a collection raise a IObservableCollection "reset" event on the UI thread if the collection has been modified since the last such event was raised? By my understanding, a "collection reset" event should cause any consumers of the collection to assume all items may have changed and act accordingly. – supercat Feb 11 '13 at 19:01
16

JaredPar's approach is a valid one. Another approach which is worth considering is using a thread safe ObservableCollection instead of the built-in ObservableCollection. There's a few implementations out there, but Sasha Barber's implementation and the CLinq Continuous Collection class are some of the better ones in my opinion. Internally, these classes essentially use the approach outlined by JaredPar, but encapsulate it inside the collection class.

Joel B Fant
  • 24,406
  • 4
  • 66
  • 67
Szymon Rozga
  • 17,971
  • 7
  • 53
  • 66
  • Personally I was not able to make it works with provided links. I needed to user JaredPas'a approach you mentioned. – Krzysztof Morcinek Mar 03 '14 at 12:48
  • Try the following link which provides a thread-safe solution that works from any thread and can be bound to via multiple UI threads : http://www.codeproject.com/Articles/64936/Multithreaded-ObservableImmutableCollection – Anthony Apr 15 '14 at 19:20
  • 1
    The article you reference by AnthonyPaulO requires the Immutable Collections NuGet package and only works with .NET4.5. Is there anything similar around for .NET4.0? – Dave Jul 30 '14 at 10:29
  • This is the best one I found so far and it synchronizes external event handling. Still you have to pass the GUI thread's SynchronizationContext (ie. Dispatcher) https://github.com/CoryCharlton/CCSWE.Core/blob/master/src/Core/Collections/ObjectModel/SynchronizedObservableCollection%601.cs – ed22 Apr 12 '19 at 07:24
  • 1
    Both of these links appear to be spam when I click on them. – Russ J Nov 19 '19 at 23:37
6

In.Net 4.5, you can use the Thread-safe collections, ConcurrentDictionary, ConcurrentBag etc, whichever suits your needs : http://msdn.microsoft.com/en-us/library/dd997305.aspx

Please consider reading also : http://www.codeproject.com/Articles/208361/Concurrent-Observable-Collection-Dictionary-and-So

Cornel Marian
  • 2,443
  • 23
  • 28