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.
Solution 1:
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);
}
Solution 2:
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.
Solution 3:
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