As you may have noticed, it is not possible to modify the contents of an ObservableCollection on a separate thread if a view is bound to this collection : the CollectionView raises a NotSupportedException :
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread
To illustrate this, let’s take a simple example : a ListBox bound to a collection of strings in the ViewModel :
private ObservableCollection<string> _strings = new ObservableCollection<string>();
public ObservableCollection<string> Strings
{
get { return _strings; }
set
{
_strings = value;
OnPropertyChanged("Strings");
}
}
<ListBox ItemsSource="{Binding Strings}"/>
If we add items to this collection out of the main thread, we get the exception mentioned above. A possible solution would be to create a new collection, and assign it to the Strings property when it is filled, but in this case the UI won’t reflect progress : all items will appear in the ListBox at the same time after the collection is filled, instead of appearing as they are added to the collection. It can be annoying in some cases : for instance, if the ListBox is used to display search results, the user expects to see the results as they are found, like in Windows Search.
A simple way to achieve the desired behavior is to inherit ObservableCollection and override OnCollectionChanged and OnPropertyChanged so that the events are raised on the main thread (actually, the thread that created the collection). The AsyncOperation class is perfectly suited for this need : it allows to “post” a method call on the thread that created it. It is used, for instance, in the BackgroundWorker component, and in many asynchronous methods in the framework (PictureBox.LoadAsync, WebClient.DownloadAsync, etc…).
So, here’s the code of an AsyncObservableCollection class, that can be modified from any thread, and still notify the UI when it is modified :
public class AsyncObservableCollection<T> : ObservableCollection<T>
{
private AsyncOperation asyncOp = null;
public AsyncObservableCollection()
{
CreateAsyncOp();
}
public AsyncObservableCollection(IEnumerable<T> list)
: base(list)
{
CreateAsyncOp();
}
private void CreateAsyncOp()
{
// Create the AsyncOperation to post events on the creator thread
asyncOp = AsyncOperationManager.CreateOperation(null);
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
// Post the CollectionChanged event on the creator thread
asyncOp.Post(RaiseCollectionChanged, e);
}
private void RaiseCollectionChanged(object param)
{
// We are in the creator thread, call the base implementation directly
base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
// Post the PropertyChanged event on the creator thread
asyncOp.Post(RaisePropertyChanged, e);
}
private void RaisePropertyChanged(object param)
{
// We are in the creator thread, call the base implementation directly
base.OnPropertyChanged((PropertyChangedEventArgs)param);
}
}
The only constraint when using this class is that instances of the collection must be created on the UI thread, so that events are raised on that thread.
In the previous example, the only thing to change to make the collection modifiable across threads is the instantiation of the collection in the ViewModel :
private ObservableCollection<string> _strings = new AsyncObservableCollection<string>();
The ListBox can now reflect in real-time the changes made on the collection.
Enjoy
Update : I just found a bug in my implementation : in some cases, using Post to raise the event when the collection is modified from the main thread can cause unpredictable behavior. In that case, the event should of course be raised directly on the main thread, after checking that the current SynchronizationContext is the one in which the collection was created. This also made me realize that the AsyncOperation actually doesn’t bring any benefit : we can use the SynchronizationContext directly instead. So here’s the new implementation :
public class AsyncObservableCollection<T> : ObservableCollection<T>
{
private SynchronizationContext _synchronizationContext = SynchronizationContext.Current;
public AsyncObservableCollection()
{
}
public AsyncObservableCollection(IEnumerable<T> list)
: base(list)
{
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (SynchronizationContext.Current == _synchronizationContext)
{
// Execute the CollectionChanged event on the current thread
RaiseCollectionChanged(e);
}
else
{
// Post the CollectionChanged event on the creator thread
_synchronizationContext.Post(RaiseCollectionChanged, e);
}
}
private void RaiseCollectionChanged(object param)
{
// We are in the creator thread, call the base implementation directly
base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (SynchronizationContext.Current == _synchronizationContext)
{
// Execute the PropertyChanged event on the current thread
RaisePropertyChanged(e);
}
else
{
// Post the PropertyChanged event on the creator thread
_synchronizationContext.Post(RaisePropertyChanged, e);
}
}
private void RaisePropertyChanged(object param)
{
// We are in the creator thread, call the base implementation directly
base.OnPropertyChanged((PropertyChangedEventArgs)param);
}
}





Just what I needed. Thanks Thomas.
Great article. This one of few good solutions I found online. Keeps us updated with modifications to the class. MS should have included this in the framework.
Awesome post!
This is one of the easier (and better) work-arounds I have seen. I have actively been trying to use the MVVM pattern in any wpf app I create but have become extremely frustrated at times while using multi-threading. This solves all of my problems!
Thanks!
Thank you!
It is the worst limitation of WPF i”ve encountered.
Hi John,
Hopefully it will be fixed in WPF vNext. See Rob Relyea”s session at PDC for details: http://player.microsoftpdc.com/Session/c1533143-2bab-43e0-a3ce-114dcdd1143e
I extracted the functionality so that it could be used as a base class or be used externally via an interface. The interface allows me to code a global dispatcher that will always make call on the creator thread.
public interface IAsyncContext { /// /// Get the context of the creator thread /// SynchronizationContext AsynchronizationContext { get; } /// /// Test if the current executing thread is the creator thread /// bool IsAsyncCreatorThread { get; } /// /// Post a call to the specified method on the creator thread /// /// Method that is to be called /// Method parameter/state void AsyncPost(SendOrPostCallback callback, object state); } public class AsyncContext : IAsyncContext { private readonly SynchronizationContext _asynchronizationContext; /// /// Constructor - Save the context of the creator/current thread /// public AsyncContext() { _asynchronizationContext = SynchronizationContext.Current; } /// /// Get the context of the creator thread /// public SynchronizationContext AsynchronizationContext { get { return _asynchronizationContext; } } /// /// Test if the current executing thread is the creator thread /// public bool IsAsyncCreatorThread { get { return SynchronizationContext.Current == AsynchronizationContext; } } /// /// Post a call to the specified method on the creator thread /// /// Method that is to be called /// Method parameter/state public void AsyncPost(SendOrPostCallback callback, object state) { if (IsAsyncCreatorThread) callback(state); // Call the method directly else AsynchronizationContext.Post(callback, state); // Post on creator thread } } public class AsyncObservableCollection : ObservableCollection, IAsyncContext { private readonly AsyncContext _asyncContext = new AsyncContext(); #region IAsyncContext Members public SynchronizationContext AsynchronizationContext { get { return _asyncContext.AsynchronizationContext; } } public bool IsAsyncCreatorThread { get { return _asyncContext.IsAsyncCreatorThread; } } public void AsyncPost(SendOrPostCallback callback, object state) { _asyncContext.AsyncPost(callback, state); } #endregion public AsyncObservableCollection() { } public AsyncObservableCollection(IEnumerable list) : base(list) {} protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { AsyncPost(RaiseCollectionChanged, e); } private void RaiseCollectionChanged(object param) { base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param); } protected override void OnPropertyChanged(PropertyChangedEventArgs e) { AsyncPost(RaisePropertyChanged, e); } private void RaisePropertyChanged(object param) { base.OnPropertyChanged((PropertyChangedEventArgs)param); } }Not working for me.
After I created a new class with above code and changed my code for new instance of ObservableCollection, I got same error. no clue……
This is snapshot of my code:
if (_MyLanguages == null) _MyLanguages = new AsyncObservableCollection();
if (_SelectedLanguage.Length > 0 && !_MyLanguages.Contains(_SelectedLanguage))
{
MyLanguages.Add(_SelectedLanguage);
OnPropertyChanged(“MyLanguages”);
OnPropertyChanged(“SelectedMyLanguage”);
}
I tried both of your classes above, but not working for me.
any idea?
Thanks in advance,
Make sure the collection is instantiated on the UI thread. Subsequent modifications to the collection can be done from any thread.
BTW, this is a ViewModel and Xaml includes ComboBox instead Listbox.
Doesnt work for me either. _synchronisaztionContext *always* seems to be null in OnPropertyChanged. Do you have a working example of this?
When do you create the collection? I think SynchronizationContext.Current is initialized when the first WPF window is loaded, so if you create the collection too early, it will be null. But that”s just a possibility, I”m not sure what”s causing the problem in you case
Billion thanks to you!
For Mik2 :
http://blogs.msdn.com/b/kaelr/archive/2007/09/05/synchronizationcallback.aspx
(at least it may help someone else in the future :p )
Sometimes i get the error that the collection don´t support changes to a thread different from the dispatcher thread at this line: base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param); in the RaiseCollectionChanged funktion. But my collections is the asyncobservablecollection, why does this happen then?
Hi Diana,
On which thread did you create the collection? It has to be created on the dispatcher thread (i.e. the UI thread), so that the notifications are raised on that thread
I create it on the main thread i think. It works most of the time but for one collection i sometimes get this error.
Thanks very much for this – very simple to implement and makes a huge difference!
Thanks for posting this! Nice solution.
Very useful, thank you very much!
If I subscribe to the CollectionChanged event of this derived collection, I am not getting the event handler”s breakpoint hit when I add/remove from the collection. Does your collection need to be modified in some way to support subscribing to CollectionChanged event?
Hi Vijay,
The breakpoint should be reached… the event is raised on the UI thread instead of the current thread, but it is raised nonetheless. Perhaps it has something to do with your debug settings ?
I am actually using an underlying collection of ICollection which is wrapped to make your AsyncObservableCollection object. Is that the reason that the CollectionChanged event on the wrapped AsyncCollectionChanged object is not received.
Please suggest a solution in this scenario to get the event with the underlying collection as ICollection.
Are you adding the items to your underlying ICollection? It won”t work; ObservableCollection (and AsyncObservableCollection as well) doesn”t wrap the collection passed as a parameter, it makes a copy of it. You need to add items directly to the AsyncObservableCollection.
I put a breakpoint in AsyncObservableCollection.OnCollectionChanged() method and it does hit there and raises base.OnCollectionChanged(), not sure why it doesn”t hit the subscribed CollectionChanged event for the wrapped AsyncObservableCollection based property?
Do you have any idea for this issue to be resolved properly?
Sorry, I have no idea what could be causing the issue…
nice! thanks for this great solution
When I use the AsyncObservableCollection as a source to a CollectionViewSource on a ListBox, my list box ends up with copies of every item. The original collection still shows the correct number of items. Using the same code with a regular ObservableCollection works fine. It looks like the ListBox is getting notified twice and creating two UI containers?
Also, if I manually add to or refresh the list, it appears to fix itself?
That”s weird… the events are still raised only once, so I don”t know why it”s doing that. If you can send a short but complete program that exhibits the issue, I”ll have a look at it.
Hi,
So, if you create a new project and just add a ”MyListBox” named Listbox in the default grid xaml and add the following code:
CollectionViewSource cvs;
public MainWindow()
{
InitializeComponent();
ObservableCollection o = new AsyncObservableCollection();
o.Add(“test”);
o.Add(“test2″);
o.Add(“test3″);
cvs = new CollectionViewSource();
cvs.Source = o;
MyListBox.ItemsSource = cvs.View;
new Task(() =>
{
o.Add(“test4″);
}).Start();
}
private void MyListBox_PreviewMouseDown_1(object sender, MouseButtonEventArgs e)
{
cvs.View.Refresh();
}
You”ll see the listbox have 1 of the first 3 items, and a two test4s. If you attach with snoop or something, you”ll see the ListBox ItemSource count to still be 4, so it”s purely the listbox creating an extra container for the same item.
If I add a PreviewMouseDown handler and refresh the view, it”ll fix itself. It”s a really weird issue.
If you spawn a second task:
new Task(() =>
{
o.Add(“test5″);
}).Start();
It”ll duplicate both the test4 and test5. However, if you add another item outside of a test (like just o.Add(“test5″)) it fixes itself again as if I had clicked (with my handler).
If I use the regular ObservableCollection, everything works as expected, but I”ll run into the NotSupportedException when actually running this through my DataBinding.
Thanks for the quick reply!
I reproduced the bug on my PC. I think it”s because when “test4″ is added from the task, the ListBox hasn”t finished loading the items yet (actually it”s a race condition). In this case, the sequence of events is as follows:
So I”m not sure it”s really a bug in the collection itself, but rather in the way it”s used. Since the CollectionChanged event isn”t going to be handled immediately when an item is added, you should avoid adding items from another thread before the list has been loaded. If you do it in the Loaded event instead of the constructor, it works fine.