Intro

Caliburn.Micro is a powerful MVVM framework. What follows is an implementation of Caliburn.Micro for use with a Silverlight Navigation application. Briefly, Caliburn allows you do use Convention Binding which automatically binds your ViewModelto your view based on naming conventions. This eliminates a great deal of hand coding that is normally required to wire up your VM and view using commands.

In this recipe, I show how Caliburn can be used along with MEF Navigation to enable URI navigation which brings deep linking to your application.

Uri Navigation in Silverlight

Is an Internet app really an Internet app if you can’t navigate using a URI? I don’t think so. E-commerce since definitely needs this feature, but even a LOB app should allow you to use the backwards and forward buttons of the browser.

The Silverlight Navigation Application template in Visual Studio does do just that. However, in doing so it forces “View-first” architecture in your application because it must be able to translate http://example.com/#/Page1 into a specific page. So how can we enable a view-first architecture? To get there, we first need to cover a view classes that are used in Silverlight URI navigation and then see how we can customize them to fit our own needs.

The Navigation Frame Class

In order to navigate, the SL Navigation template uses a control called a Frame (System.Windows.Controls.Frame) in MainPage.xaml. The Frame is integrated into the browser and can work with the browser’s navigation buttons (you can also set it to integrate with buttons in the app that work like the browser buttons, say in an Out-Of-The-Browser app). Backwards and Forward navigation is expected navigation for websites. If it doesn’t support it, you get the user hitting the back button and instead of going to the prior page in your app, the user gets thrown out of your app to the prior page in the browsers journal. Navigation with the Frame works, but what we would really like is a way to control the Frame so we can properly conduct the application even if it is being driven by a URI. This brings us to the Frame.ContentLoader.

Frame.ContentLoader

The Frame as mentioned above is not actually loading the content; it has a property called ContentLoader. The default value of ContentLoader property is an instance of the class PageResourceContentLoader (in System.Windows.Navigation). The PageResourceContentLoader is based on INavigationContentLoader and it is through this interface we can get back to a view-first implementation.

INavigationContentLoader

The release of Silverlight 4 brought us the INavigationContentLoader. The use of this interface was first covered by David Poll in Opening Up SL 4 Navigation . In this blog, he creates an example of a TypenameContentLoader which, as the name implies, load the page based on a class name that is passed in through the URI. This was a step in the right direction, but passing a type name isn’t really what we want. What we really want is to be able to pass in a token such as “Home” to create our ViewModel and along with that, our actual view. And we want to use Caliburn.Micro for its convention binding. In addition, let’s make it MEF driven since it’s easily available in Silverlight 4, and can bring loading on demand to the table as well.

Introducing the MEFContentLoader

The MEF content loader does all that I just described. In a nutshell, this class has a method called NavigateToPage that takes the target URI, gets the ViewModel using MEF, gets the View using more MEF, and then binds them together with Caliburn.Micro. The MEFContentLoader is in the sample application below. Let’s jump right into what you need to do to implement this class in your own application.

1. Start with the Silverlight Navigation Application template. Add a reference to Caliburn.Micro, as well as MEFNavigation.
2. Go to the MainPage and add an xmlns to MEFNavigation.
3. Remove the default he content loader and the URI mapper. Replace it with this xaml:

<navigation:Frame.ContentLoader>
      <mef:MEFContentLoader />
</navigation:Frame.ContentLoader>


This is going to replace the default loader with our own MEF Loader.

4. Go to the Home Page. Add a reference to MEFNavigation. Add the following attribute to the Home class:

[ExportPage("/Home")]
public partial class Home : Page
{ 
   //implementation elided
}


This attribute specifies to MEF that this class is a View, and that the tag for it is “Home”

5. Create a ViewModel, with a base type of Screen (from Caliburn.Micro), like this:

[ExportViewModel("Home")]
public class HomePageViewModel : Screen
{ 
   ///implementation elided
}


This is going to tell MEF that this is the ViewModel for the Home screen. Note that the base is of type Screen. You could use other base types, but you would have to update the MEFLoader. But Screen adds a lot of benefits so is what I have used here.
And that’s it! You don’t need to write any MEF code whatsoever; just those two decorations. Just fire up your project and it will go right to the home page. Wire up your other pages and those will work just like the above. And Caliburn.Micro is doing the binding for you, again with no further configuration. Honestly, it really doesn’t get any easier than this.

I have not included a bootstrapper in this sample to keep it simple, but this could easily be added and would be the same as in other Caliburn.Micro samples. A bootstrapper is not required to make the above work, as the MEF initialization is occurring in the MEFContentLoader.

Loading on Demand

The sample application includes a third page called Reports. Note that this page is in its own project and the Silverlight App does not reference this project. So how is this page showing up? This is more MEF magic. When the MEF loader fails to find the page in the local zap, it looks for any other xap files in the website. Since there IS a reference to the Reports project in the Website, it will find the other zap in the ClientBin and pull it out of there. In other words, it’s loading on demand. This reduces the load time of the initial xap, as well as enabling the concept of plug-ins to your application.

The Sample App

The sample is just three pages, created just like in the steps above. Just run the app. The page will tell you which page you are on. Type in the textbox, then click the button. If you get a MessageBox, you know the binding is working.

The MEFNavigation Project

This project includes the classes that enable URI Navigation. It is based on the samples which Glenn Block used in his Mix 10 MEF Demo. In the demo, he used MEF to pull out the Page using MEF. I modified this to pull out both the ViewModel and the Page. These classes are worthy of a blog post in themselves, so I am going to hold off covering those classes. But you don’t need to modify these to try them out in your own projects.

Wrap Up

There is still more to include in the MEFLoader to get it up to production quality:

  • Base the MEFContentLoader on the Caliburn.Micro Conductor and include lifecycle events.
  • Support Deep Linking (to a specific productID for example).
  • Support the default Page Navigation behavior as a fall-back of the ViewModel navigation fails.
  • Include an Error Page for broken links.


But the above is a step forward and something I think is going to become very useful to Uri based navigation in Silverlight.

For more info, see Greg's blog at http://SilverlightDev.net

Last edited Nov 27, 2010 at 5:07 PM by gregoryagu, version 1

Comments

No comments yet.