WPF 4.5: Accessing bound collections on non UI threads

July 21, 2012

no comments

The single threaded behavior of WPF (and other UI technologies) requires that anything tied to the user interface be manipulated on the UI thread, incuding data bound objects. There are several ways to do that, assuming the code is on a non-UI thread, such as using Dispatcher.(Begin)Invoke, capturing and using the current SynchronizationContext, etc.

Specifically, if some collection is data bound, items cannot be added or removed from it from a non-UI thread. WPF 4 (and earlier) throws an exception, because the data binding mechanism expects to be notified of changes (e.g. ObservableCollection<T>) on the UI thread.

One of the improvements in WPF4.5 is the ability to manipulate bound collections on a non-UI thread without requiring marshalling the manipulating code to the UI thread. The way to do that is not obvious, however.

Let’s assume we have a simple ObservableCollection<int> that is bound to some ListBox named _list. To enable manipulation on a non-UI thread, we must first define a lock object to be used by our and WPF’s code so that the collection is not corrupted. To do that we need to call the static BindingOperations.EnableCollectionSynchronization method, providing the collection in question and the object to be used as a lock. Here’s a complete example in the code behind file:

  1. public partial class MainWindow : Window {
  2.     ObservableCollection<int> _numbers = new ObservableCollection<int>();
  3.     object _lock = new object();
  4.  
  5.     public MainWindow() {
  6.         InitializeComponent();
  7.  
  8.         _list.ItemsSource = _numbers;
  9.         BindingOperations.EnableCollectionSynchronization(_numbers, _lock);
  10.  
  11.         ThreadPool.QueueUserWorkItem(_ => {
  12.             var rnd = new Random();
  13.             for(; ; ) {
  14.                 lock(_lock) {
  15.                     _numbers.Add(rnd.Next(1000));
  16.                 }
  17.                 Thread.Sleep(1000);
  18.             }
  19.         });
  20.     }
  21. }

The lock itself can be any object, provided it’s a reference type, for which System.Object fits perfectly, as it’s always a reference type. This is the concept for the C# lock keyword (calling Monitor.Enter/Exit behind the scenes). Notice also that although we’re providing the lock to WPF, we still need to use it explicitly in our non-UI thread manipulating code to ensure the collection is not corrupted.

This feature can certainly improve performance because it does not require thread switching for every update. It does require locking, however, which is not ideal, but merely a fact of life in a multithreaded world.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*