WittyCoding

Coding blog

WPF 4.5 : EnableCollectionSynchronization

The last week, I was testing a new feature of WPF 4.5 : EnableCollectionSynchronization

I created a view with a ListBox and a ViewModel with a property of ObservableCollection type and a constructor that enables the synchronization:

private readonly ObservableCollection<CommentTypeViewModel> _commentTypes = new ObservableCollection<CommentTypeViewModel>();

public ObservableCollection<CommentTypeViewModel> CommentTypes
{
    get { return _commentTypes; }
}

private readonly object _commentTypesLock = new object();

public ManageCommentTypeViewModel()
{
    BindingOperations.EnableCollectionSynchronization(CommentTypes, _commentTypesLock);
}

With a command, a method is called by another thread (no UI thread) and adds an item in the collection.

And, surprise, it doesn’t work. I get the usual NotSupportedException exception. After some tests, I realized that it did not work, because the creation of ViewModel wasn’t in the UI thread.

With the following line, no error:

Application.Current.Dispatcher.Invoke(() => BindingOperations.EnableCollectionSynchronization(CommentTypes, CommentTypesLock));

I wondered why it was not supported in another thread and why there was no error in the ViewModel constructor.

With my ReSharper friend, I decompiled the EnableCollectionSynchronization method:

public static void EnableCollectionSynchronization(IEnumerable collection, object lockObject)
{
    if (collection == null)
        throw new ArgumentNullException("collection");
    if (lockObject == null)
        throw new ArgumentNullException("lockObject");
    ViewManager.Current.RegisterCollectionSynchronizationCallback(collection, lockObject, (CollectionSynchronizationCallback) null);
}

Then ViewManager.Current :

internal static ViewManager Current
{
    get
    {
		return DataBindEngine.CurrentDataBindEngine.ViewManager;
    }
}

And finally DataBindEngine.CurrentDataBindEngine :

[ThreadStatic]
private static DataBindEngine _currentEngine;

internal static DataBindEngine CurrentDataBindEngine
{
    get
    {
        if (DataBindEngine._currentEngine == null)
			DataBindEngine._currentEngine = new DataBindEngine();
        return DataBindEngine._currentEngine;
    }
}

We realize that DataBingEngine is created for each thread.

It is normal in order to manage a multithreaded application with several windows.

And it is also normal to have no errors when creating my ViewModel. The lock object isn’t stored on the same engine as my ListBox.

Finally, with this method, Microsoft offers a new solution to this problem, but it is still difficult to implement. This is especially true if you have multiple windows with different UI Threads. It becomes difficult to know which thread is used. And in the worst case, if the ViewModel is shared between two windows, you have need to initialize the lock object in multiple threads (each window).

The ViewModel becomes dependent on the view…

Tags: WPF

No Comments

Add a Comment