Search code examples
wpfmultithreadingdata-bindingconcurrent-collections

Is WPF binding to concurrent collections safe?


I was wondering, if it is safe to bind a WPF control to a concurrent collection, specifically a wrapper class around one of the System.Collections.Concurrent collections that also implements INotifyCollectionChanged?

I understand that CollectionChanged must be invoked on the UI-thread (and without the index parameters). But, what happens, if another thread manipulates the source collection while the UI is updating itself? Does WPF just gracefully ignore the problem (like it does in so many other places)?


Solution

  • That depends on the implementation of your wrapper. Let's make a simple example adding INotifyCollectionChanged to a BlockingCollection<T> allowing calls of non UI threads:

    public void AddNotified(T item)
    {
        base.Add(item);
    
        var args = new NotifyCollectionChangedEventArgs(
            NotifyCollectionChangedAction.Add,
            item,
            Count - 1);
    
        //Ensure no items are changed until the UI is updated
    
        Application.Current.Dispatcher.Invoke(() =>
            CollectionChanged?.Invoke(this, args));
    }
    

    The implementation of Add itself is threadsafe, but to be sure the UI shows the current items the implementation you need to ensure that there are no other items are changed between adding and updating (See comment in code).

    WPF updates the UI based on the NotifyCollectionChangedAction and updated items passed at raising the INotifyCollectionChanged.CollectionChanged. This means the UI relys on this information. The result: An interim collection update leads to an unsynchronized UI until the update was raised or a NotifyCollectionChangedAction.Reset was called and the UI shows different items like inside your source collection.

    Synchronizing collections with the UI is a very wide and intresting topic. There are already multiple solutions available that may match your specific problem. To give you some possible approaches to solve problems like this have a look at here are some links: