[box type=”info”]As if Caliburn wasn’t amazing enough, Rob has responded to my original post and given some brilliant tips that resulted in a bunch of refactoring. You get to see the final product.[/box]

Until we get C# 5 on the phone, Rob’s coroutines are a pretty damn sweet way to bring together multiple asynchronous calls in a very tidy syntax. The heavy-lifting we need to do in a WP7 page load almost invariably involves async calls to load data (especially after tombstoning), plus some user notification. Coroutines eat this stuff for breakfast.

So how do we roll this all together? What I wanted was a way for any given page to do this:

Load up and bind to the relevant view model;

All pages should implement the “After first layout updated” pattern;

If the page’s view model knows about my heavy-lifting paradigm, then use it;

Do it sexily with coroutines, which keeps the code tidy and helps us with user notifications in asynch-world.

Step 1

Use Caliburn Micro. It’s just that easy. If you’re still manually setting DataContext in your XAML pages (without a good reason), you’re doing it wrong.

Step 2

To make sure all my pages implement the pattern, I created a custom FrameAdapter based on the Caliburn one. Previously I had used a custom base page, but going the FrameAdapter route means we don’t have to munge the machine generated xaml when we create a new page.

There’s a couple of interesting bits in here:

On the Frame’s navigated override, we hook up the Content’s LayoutUpdated event. The content of the frame is our xaml view.

We check if the pages’s DataContext is IFirstLayoutAware.

We use the brand-new Action.Invoke method from Caliburn Micro, which creates and execution context for us, then executes the named method (which we’ve defined as required in IFirstLayoutAware.)

To take advantage of this custom frame adapter, we need only inject it in our Caliburn Bootstrapper, in place of the default FrameAdapter. I’m using Ian Randall’s MicroIoc container here. Line 12 is the only change required to wake up the functionality in the class above.

Step 3

You would have seen the IFirstLayoutAware interface in the previous step. This is just a tiny interface that defines the behaviour required of View Models that will take advantage of our performance approach:

The IEnumerable<IResult> type will be familiar if you’ve read the documentation around Coroutines. I you haven’t, you need to do so right now before you read on. I’ll wait.

Step 4

So, within any of your View Models that implement IFirstLayoutAware you need to implement that special method. How you do it will depend on how you’ve chosen to divide up the loading behaviour for your application, but here’s mine for the first page of my Silent Auction app:

Isn’t it gorgeous? Those yield returns are sent to Caliburn’s Action pipeline, and executed in turn. There’s a lot of custom code behind each one, but just quickly:

LoadSettings does some asynchronous calls to a web API to get some basic information.

Once LoadSettings is complete, we can turn off the loading message and refresh some data on the page via Refresh(); (e.g. links to brand images that we have just loaded from settings).

LoadAuctionItems is less urgent (we need it for the next page), so it can happen last, and just chug away in the background while the user is thinking.

Remember that all of the guidance around Silverlight and WP7 still apply. Inside those IResult objects we should be using proper asynchronous coding – don’t block on web requests; marshall callbacks to the UI thread; and all that good stuff.

The using(this.Block(..)){} pattern is another gem from Rob Eisenberg. Block is an extension method that returns a DisposableAction, which in itself is a sweet little pattern. It says “give me an object that will execute a defined action when it is disposed”:

Conclusion

Like I said at the start, this is just a recipe, made up of many parts magical Caliburn fairy dust, and some special sauce. You’ll need to understand MVVM and Caliburn to really make the most of it. Let me know if you like it.

Related

7 Replies to “WP7 Background Loading with Caliburn and Coroutines”

Very good stuff. Let me make a couple of suggestions. Someone recently reminded me that using blocks work fine inside of iterators, so you might consider re-writing your coroutine to something like this:

If you are inheriting from PropertyChangedBase or one of its derivatives, you can also use the Refresh method in place of the call you have above.

Another thought relates to the base view. You might consider hooking into the navigation service and applying this behavior via wiring to events on the page being navigated to. Then, you won’t need a custom base class.