Thursday, August 8, 2013

Binding for separate threads

I had been in struggling with binding data into Grid using ObservableCollection because of exception "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread" then I just figured out that: try to adding items to this collection "ObservableCollection" out of the main thread, we will get the exception mentioned above. Searching around, found http://www.thomaslevesque.com/tag/mvvm/ this help me! Actually, I wanna to say big thanks Thomas to share his knowledge.

Here are solutions: using SynchronizationContext since it is the one collection was created. Below is implementation:

public class AsyncObservableCollection<T> : ObservableCollection<T>
{
    private SynchronizationContext _synchronizationContext = SynchronizationContext.Current;
 
    public AsyncObservableCollection()
    {
    }
 
    public AsyncObservableCollection(IEnumerable<T> list)
        : base(list)
    {
    }
 
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (SynchronizationContext.Current == _synchronizationContext)
        {
            // Execute the CollectionChanged event on the current thread
            RaiseCollectionChanged(e);
        }
        else
        {
            // Post the CollectionChanged event on the creator thread
            _synchronizationContext.Post(RaiseCollectionChanged, e);
        }
    }
 
    private void RaiseCollectionChanged(object param)
    {
        // We are in the creator thread, call the base implementation directly
        base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
    }
 
    protected override void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (SynchronizationContext.Current == _synchronizationContext)
        {
            // Execute the PropertyChanged event on the current thread
            RaisePropertyChanged(e);
        }
        else
        {
            // Post the PropertyChanged event on the creator thread
            _synchronizationContext.Post(RaisePropertyChanged, e);
        }
    }
 
    private void RaisePropertyChanged(object param)
    {
        // We are in the creator thread, call the base implementation directly
        base.OnPropertyChanged((PropertyChangedEventArgs)param);
    }
}

Note: instances of this class must be created on the UI thread (inside Dispatcher)