It seems the ObservableCollection only support add, remove, clear operation from the UI thread, It throw Not Support Exception if it is operated by a NO UI thread. I tried to override methods of ObservableCollection, unfortunatly, I met lots of problems. Any one can provide me a ObservableCollection sample which can be operated by multi-threads? Many thanks!
-
1Check out [this post](http://kentb.blogspot.com/2008/01/cross-thread-collection-binding-in-wpf_19.html) on my blog. – Kent Boogaart Oct 09 '08 at 12:42
-
The following link has a solution that allows you to bind to the collection from any UI thread and modify it from any thread : http://www.codeproject.com/Articles/64936/Multithreaded-ObservableImmutableCollection – Anthony Apr 14 '14 at 21:25
4 Answers
Using the link provided by Kent, you could use the following code to modify a collection across threads:
while (!Monitor.TryEnter(_lock, 10))
{
DoEvents();
}
try
{
//modify collection
}
finally
{
Monitor.Exit(_lock);
}
If however you're just looking to modify the collection on your original thread you can try using a callback to your UI thread. I normally do something like this:
this.Dispatcher.Invoke(new MyDelegate((myParam) =>
{
this.MyCollection.Add(myParam);
}), state);

- 1
- 1

- 71,849
- 51
- 176
- 230
-
By the sounds of the original post, (s)he wants an implementation of ObservableCollection that can be used from any thread without regard for marshalling to the UI thread. Can be very useful in your business layer, for example. Of course, I could have misunderstood the intent of the question... – Kent Boogaart Oct 09 '08 at 12:47
-
Also, Mark, I don't necessarily know if using BeginInvoke is the best idea, because you won't absolutely guarantee the order of items. Invoke() is the way to go. – Bob King Oct 09 '08 at 12:51
-
-
@Bob King, I've updated the code. That was a copy + paste from Silverlight which doesn't have an Invoke method. – Mark Ingram Oct 09 '08 at 13:46
Personally, I find Bob's style of answer easier to use than Mark's style of answer. Here are the C# WPF snippets for doing this:
in your class's constructor, get the current dispatcher as you create your observable collections. Because, as you pointed out, modifications need to be done on the original thread, which may not be the main GUI thread. So Application.Current.Dispatcher isn't alwasys right, and not all classes have a this.Dispatcher.
_dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher; _data = new ObservableCollection<MyDataItemClass>();
Use the dispatcher to Invoke your code sections that need the original thread.
_dispatcher.Invoke(new Action(() => { _data.Add(dataItem); }));
That should do the trick for you. Though there are situations you might prefer .BeginInvoke instead of .Invoke.

- 3,857
- 1
- 35
- 29
You've basically got to Invoke or BeginInvoke over to the UI thread to do those operations.
Public Delegate Sub AddItemDelegate(ByVal item As T)
Public Sub AddItem(ByVal item As T)
If Application.Current.Dispatcher.CheckAccess() Then
Me.Add(item)
Else
Application.Current.Dispatcher.Invoke(Threading.DispatcherPriority.Normal, New AddItemDelegate(AddressOf AddItem), item)
End If
End Sub

- 25,372
- 6
- 54
- 66
You might want to investigate my answer to this perhaps -but please note
that the code came from here and cannot be credited to me. Though I tried to implement it in VB. : Original Site
I've used this to populate a WPF listbox from a class that has an ObservableCollectionEx populated asynchronously from an access database. It does work.
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
// Override the event so this class can access it
public override event System.Collections.Specialized.NotifyCollectionChangedEventHandler
CollectionChanged;
protected override void OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
// Be nice - use BlockReentrancy like MSDN said
using (BlockReentrancy())
{
System.Collections.Specialized.NotifyCollectionChangedEventHandler eventHandler = CollectionChanged;
if (eventHandler == null)
return;
Delegate[] delegates = eventHandler.GetInvocationList();
// Walk thru invocation list
foreach (System.Collections.Specialized.NotifyCollectionChangedEventHandler handler in delegates)
{
DispatcherObject dispatcherObject = handler.Target as DispatcherObject;
// If the subscriber is a DispatcherObject and different thread
if (dispatcherObject != null && dispatcherObject.CheckAccess() == false)
{
// Invoke handler in the target dispatcher's thread
dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, this, e);
}
else // Execute handler as is
handler(this, e);
}
}
}
}

- 758
- 1
- 11
- 23