views:

361

answers:

3

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.

+2  A: 

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
+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
@Reed, added a solution with `SynchronizationContext` that has a functional flavor.
JaredPar
Thank you for your answer. I will look at this tomorrow as it is 01:30AM here.
Erik
A: 

JaredPar's approach is a valid one. Another approach, which is worth considering, is using a thread safe observable collection, instead of the built-in observable collection. 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 colleciton class.

siz
A: 

(sorry, my answer was wrong, I've deleted it)

Vlad
ObservableCollection does not inherit from DispatcherObject nor expose a property called Dispatcher. http://msdn.microsoft.com/en-us/library/ms668613.aspx
siz
oh, indeed :-( I'll remove the answer
Vlad