WPF Cross-Thread Collection Binding – Part 1
Update: The final solution has been posted.
WPF supports binding to properties that change from any thread, but does it not support collection binding from any thread that is not the UI. Many people have faced the need to be able to bind to some collection that is being operated on by a worker thread. Since WPF does not support this feature out of the box, several people have attempted to come up with a solution. Most of these solutions try to solve the problem by posting the change events to the UI thread so that WPF is notified from the UI thread and not the worker. Unfortunately there is one major flaw that exists with this solution, and it has to do with two threads (UI and worker) sharing the same collection. Here is a diagram of the solution many have come up with:

To initialize this solution, the software developer binds their UI ItemsControl (such as a ListView or ListBox) to their special collection, then they hand off that same collection to their worker thread. Now the solution is set up, and here is what happens:
1. The worker adds or removes an item from the list.
2. This special list internally detects an item is being added from the worker thread, so instead of raising the CollectionChanged event externally, it posts the event internally to itself (to the UI thread).
3. When the event is received internally on the UI thread, the special collection then detects that it can safely raise the CollectionChanged event externally to notify WPF.
WPF then does what it needs to do, such as reading the updated list. Looks great right? This is the flaw:
The moment an item is being added to the collection from the worker thread, the UI thread could be reading/enumerating the same collection at the same time.
This will cause an exception that will cause a crash. The fundamental problem is that the collection is shared between two threads. When data is shared between two threads, the threads need to be synchronized (using locks for example). Since WPF does not lock the UI thread when it reads the collection, there is no way to synchronize the UI thread and the worker thread to prevent both from accessing the collection at the same time.
Let’s step back for a moment and study what is really needed:
A worker thread to be able to modify/update a collection
A UI control to display the collection
Do we need to modify the collection from the UI thread? If not, our requirements just became much easier. This is the direction we will be going.
Disclaimer: Although I came up with my solution on my own, Miral was the first to post a fantastic write-up on the implications of cross-thread collection binding, and I believe his is the first implementation that actually works correctly. However, the solution posted here is more simple and does not require locks.
The Solution
I believe the following solution is the first simple, rock-solid, lock-free, cross-thread collection binding implementation. Given that all we need to do is display the data on the UI thread, we can choose to utilize two collections. The worker thread can work with one collection while the UI thread can bind to the other. Any time the worker changes its collection, the change will be posted to the UI thread where the UI collection will be updated. Here is the diagram:

This special collection will be called an ObservableBackgroundList. It is a list that is only accessible by one thread only (a non UI thread). It is also observable, because it has a property called ObservableCollection that exposes the internal ObservableCollection<T>. The ObservableBackgroundList contains a list for the worker thread to utilize, an ObservableCollection for the UI thread, and a Dispatcher to post change notifications and items to the UI thread.
public class ObservableBackgroundList<T> : IList<T>
{
private Dispatcher _dispatcher;
private List<T> _list;
private ObservableCollection<T> _observableCollection;
…
}
Here is the ObservableCollection property that is exposed for WPF’s binding:
public ObservableCollection<T> ObservableCollection
{
get
{
return this._observableCollection;
}
}
WPF’s items controls bind to this property for their items source. Since this ObservableCollection will always only be updated from the UI thread, no locks are needed. To demonstrate how the ObservableBackgroundList updates its own list as well as updates the UI’s ObservableCollection, we will take a look at the Add method.
public void Add(T item)
{
this._list.Add(item);
this._dispatcher.BeginInvoke(DispatcherPriority.Send,
new AddCallback(AddFromDispatcherThread),
item
);
}
First the ObservableBackgroundList adds the item to its own list. Then, using a constructor supplied Dispatcher, the item is posted to the UI thread where the following method is executed:
private void AddFromDispatcherThread(T item)
{
this._observableCollection.Add(item);
}
Again, since the AddFromDispatcherThread is executing on the UI thread, WPF’s binding to the observable collection will work perfectly.
So, is this solution the grand solution to solve all cross-thread collection binding requirements? Absolutely not. Every design has its tradeoffs, and though this design has its downsides, it will probably be a solution that will work for the majority of people that need cross-thread collection binding. Intelligent readers probably already thought of one potential problem: what if there are so many changes to the collection from the worker thread that all of the posts flood the UI thread? This can happen for sure, but the counter argument is that this is true for any background operation that notifies the UI. Fortunately, this problem will be addressed in Part 2 of this series. Here are the pros and cons of the current design:
Pros
-Simple
-No locks
-Non-blocking
-Easy to use (just like any other list)
-Fast
-Works!
Cons
-It is NOT threadsafe (only 1 thread can work with the list at a time)
-The UI control must not modify its ObservableCollection source (it just displays the collection)
-Disposable or Dependency objects should not be used
-Too many changes too quickly on the worker will flood/block the UI thread
-The UI collection will lag behind the worker collection by an extremely small amount of time
-Two collections are required (but the extra memory usage is very small)
Update: The final solution has been posted.