Andrew Whiddett on Asynchronous Databinding, the Dispatcher class and using DispatcherPriority.Background

Andrew Whiddett is a developer at REZN8, an amazing interactive design firm. REZN8 built the Netflix demo that was shown at PDC05. Andrew doesn't have a blog and asked me to be a proxy for a code sample he wrote, which I was more than obliged to do! He's a great developer and, until he gets his own blog, I'll be proxying any information he wants to share. The code sample itself is posted here and his mini-article is posted below:

The WPF samples are all very nice, but they typically are relatively simple implementations to show off a particular API set. We all know that real applications are more complex, and in most cases; getting data takes a period of time, which we need to account for in the application design.

The WPF binding system too so powerful to be ignored, in that it allows a complete separation of the UI Design from the business object implementation; this gives the application a level of abstraction that has never been available before, but must be implemented with real world issues; such as return data performance.

Here is an example that shows how to deal with some of these real world binding issues.

Let’s say there is a CLR based data bound object that you are trying to implement. For example a collection of FOO objects, e.g.

An Object called FOO that contains a bunch of properties that we want to bind (in this case it just contains a description)

Well, the initial load performance is not too great, but this follows the pattern implemented in most of the WPF examples..

Now add in a sleep : why you might ask; well really we are getting this data from somehere else; a database via a WCF call. In the real world, it might take some time, or even never make it at all.

So, the new fill routine looks something like:

protected void FillTheData()

{

for (int iLoop = 0; iLoop < 1000; iLoop++)

{

this.Add(new FOO("First String"));

Thread.Sleep(500);

}

}

What happens when you run this version ? The application takes FOREVER to load up.. Seriously, cancel the app; it will take nearly 8 minutes to display. Realy what we wanted to happen was for the data to flow in as it comes in over the wire rather than blocking the UI… Well that’s what threads are for after all…

So, lets kick off the FillTheData on a thread, that way we can stop blocking the UI threads…

In this case we can do this in the constructor, e.g.

public MyDataObjects()

{

Thread th = new Thread(new ThreadStart(this.FillTheData));

th.Start();

}

If you run it now, what happens is you get an exception:-

This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

What this means is the collection has to be updated on the UI thread; not so nice; actually at this point I almost gave up trying to use the native data binding; but I really wanted to use it as it makes it so much easier for the UI designers to implement the design, and I really did not want to have to hand code it… well it took a bit of digging, but there is a solution: Kick the ObservableCollection.Add back to the UI (Dispatcher) thread…

So, in this example we create a method that populates the collection on a callback (the AddAFoo method), and we use BeginInvoke to Invoke a operation (to the callback) on the dispatcher thread.

// NOTE: This needs to run on the dispatcher thread...

protected object AddAFOO(Object data)

{

FOO myNewFoo = data as FOO;

if(myNewFoo != null) this.Add(myNewFoo);

return null;

}

protected void FillTheData()

{

for (int iLoop = 0; iLoop < 1000; iLoop++)

{

Application app = System.Windows.Application.Current;

if (app != null)

{

app.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(AddAFOO), new FOO("First String"));

Thread.Sleep(500);

}

}

}

}

So, run this version, and sure enough, the data trickles it goes; which really leaverages the power of the databind, without the UI designer having to worry about the implimentation at all.

One little note here, if you use the Dispatcher associated with the app then you will only be able to use this solution in scenarios where the controls you are populating were created on the application’s main thread (i.e. the one that called Run). It would be better maybe to use the Dispatcher associated with some specific Visual or to add a private Dispatcher variable to the MyDataObjects class that gets initialized to Dispatcher.CurrentDispatcher in its constructor.

Wow…this post saved me a lot of time and effort. Far simpler than not using databinding…which wasn’t really an option for me. Thanks for the post. Any idea if databinding might learn how to hop threads in the future? Acquiring data on different threads seems pretty common.