ObservableCollection and threading

ErikTJ picture ErikTJ · Feb 19, 2010 · Viewed 29.6k times · Source

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.

Answer

JaredPar picture JaredPar · Feb 19, 2010

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);
}