Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ObservableCollection and threading

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.

like image 274
ErikTJ Avatar asked Feb 19 '10 00:02

ErikTJ


3 Answers

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);
}
like image 160
JaredPar Avatar answered Oct 22 '22 02:10

JaredPar


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.

like image 15
Szymon Rozga Avatar answered Oct 22 '22 02:10

Szymon Rozga


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

like image 6
Cornel Marian Avatar answered Oct 22 '22 02:10

Cornel Marian