Wednesday, January 24, 2007

How to propagate changes across threads in WPF?

If you are reading this blog, I assume you already knew that in WPF,
it doesn't not support collection change notifications across threads.

Beatriz Costa has a great post about this (see http://www.beacosta.com/Archive/2006_09_01_bcosta_archive.html).

Kent (http://www.newsalloy.c8/681/) has written a nice wrap class DispatchingNotifyingCollection to solve this problem. But unfortunately, his solution didn't work when used together with CollectionView because of a bug in CollectionView as mentioned in the following post http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1144125&SiteID=1. Also, his solution seems make it harder to solve the multi thread problems since different threads can change both the wrapped collection and DispatchingNotifyingCollection at the same time.

So how to fix the filter problems?
Inspired by Kent's code, here is my solution. I called it DispatchingObservableCollection.
It is simpler than Kent's solution and also works with the CollectionView filter.

This is my first post and hopefully someone will read it and find it useful. :)

public class DispatchingObservableCollection<Titem> : ObservableCollection<Titem>

{

private readonly Dispatcher _dispatcher;

public Dispatcher Dispatcher

{

get

{

return _dispatcher;

}

}

public DispatchingObservableCollection(Dispatcher dispatcher)

{

if (dispatcher == null)

{

throw new ArgumentNullException("dispatcher can not be null");

}

_dispatcher = dispatcher;

}

private delegate void OnCollectionChangedHandler(NotifyCollectionChangedEventArgs e);

protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)

{

if (_dispatcher.CheckAccess())

{

base.OnCollectionChanged(e);

}

else

{

_dispatcher.Invoke(DispatcherPriority.DataBind, new OnCollectionChangedHandler(base.OnCollectionChanged), e);

}

}

}


1 comment:

肖重庆 said...

Hi, Sam and Bea:

Thanks for your comment. I am surprised your guys actually take time to read my post.

As I mentioned in my post, my solution is not thread safe so I am aware of the problems you have mentioned.

My solution will work only under the following conditions.
1. A worker thread is updating the collection.
2. The UI thread is only using data binding to display the collection.
(This is what is required in my current project and that is why I come up with the siimple solution)

For more complex condition, say multi threads can update the collection at the same time, my solution won't work, more work need to be done to make it thread safe.

Once again, thanks for your comments.
(Especially thanks Bea since your blogs have helped me a lot to understand data binding in WPF.)