Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BindingOperations.EnableCollectionSynchronization mystery in WPF

Tags:

c#

.net

wpf

I have been struggling to grasp this concept and even after many experiments I still can't figure out what the best practise is with ObservableCollections in WPF and using BindingOperations.EnableCollectionSynchronization.

If I have a viewmodel with an observable collection and I enable collection sync on it using a lock as shown below:

m_obsverableCollection = new ObservableCollection<..>;
BindingOperations.EnableCollectionSynchronization(m_obsverableCollection,
                                                   m_obsverableCollectionLock);

Does that mean that every modification and enumeration over that observable collection will:

  1. Lock the collection automatically using the m_obsverableCollectionLock?
  2. Marshall all modifications on the thread on which the collection was created?
  3. Marshall all modifications on the thread on which the binding operations call was made?

When using BindingOperations.EnableCollectionSynchronization, will I ever need to do any kind of locking explicitly?

The problem which spawned all this is that even after using BindingOperations.EnableCollectionSynchronization and locking items using the same lock I passed into that method, very occasionally I get the "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread." exception

like image 363
Ruskin Avatar asked Nov 01 '13 20:11

Ruskin


2 Answers

We finally got to the bottom of it:

We have to enable CollectionSynchronization on the dispatcher:

Application.Current.Dispatcher.BeginInvoke(new Action(()=>
{
    BindingOperations.EnableCollectionSynchronization(m_obsverableCollection, m_observableCollectionLock);
}));

Then everytime any other thread wants to access the observable you can simply:

lock (m_observableCollectionLock)
    m_observableCollection.Add(...)
like image 178
Ruskin Avatar answered Oct 13 '22 22:10

Ruskin


I haven't used that particular syntax, but whenever I need to update an ObservableCollection from a background thread, I follow this pattern:

// i just typed this off the top of my head, so be forewarned...  :)
lock(someLockingObj)
{
    Application.Current.Dispatcher.BeginInvoke(new Action(()=>
    {
       ... update here....
    }));
}

Usually the error that you've encountered occurs when a bg thread is trying to update the ObservableCollection directly, without the Dispatcher.BeginInvoke (or even Invoke would work too, most of the times, IMHO).

like image 32
code4life Avatar answered Oct 13 '22 23:10

code4life