Welcome back :)

After wasting spending a couple weeks writing the "sprint two" post on data entry (and MVVM, DI, etc), I've realised that I need to focus on audience. Sean d'Souza and The Brain Audit have finally sunk in.

When I started this series of posts, I didn't really consider who exactly I was writing for. Trying to balance between beginner and intermediate is tough, especially when I'm fairly new to WP8 development. Someone is bound to get bored or lost.

So I've made a decision.

These posts are targeted at experienced Windows developers, preferably with some knowledge of WPF and MVVM, who want to write a Windows Phone 8 app.

Of course this means the series has officially been renamed to "Journey to the WP8 App Store in 3 months" :) Eep!

I'm going to be using Matteo Pagani's series on Caliburn Micro with Windows Phone 8 as a reference (along with SO, of course). In case Matteo's site disappears, I'm copying the code examples here and modifying as required to work with the latest version of Caliburn.Micro. Total credit goes to Matteo.

Moving to Caliburn.Micro

I come from a heavy Prism background, so seeing the PhoneBootstrapper class made my eyes light up. (On a side note, I don't see p&p paying any attention to Prism for WP8 which is why I had to choose between MVVM Light and Caliburn.Micro)

To be honest, this looks an awful lot like configuring Prism. Unity has been replaced with PhoneContainer and there a few phone-specific methods, but the code should be quite recognizable.

Create a Bootstrapper

public class Bootstrapper : PhoneBootstrapper
{
PhoneContainer container;

protected override void Configure()
{
  // Fixes a superfluous compiler error while viewing App.xaml
  // Value cannot be null. Parameter name: rootFrame
  if (Execute.InDesignMode)
  {
    return;
  }

  container = new PhoneContainer();
  container.RegisterPhoneServices(RootFrame);
  container.PerRequest<MainViewModel>();

  AddCustomConventions();
}

static void AddCustomConventions()
{
}

protected override object GetInstance(Type service, string key)
{
    return container.GetInstance(service, key);
}

protected override IEnumerable<object> GetAllInstances(Type service)
{
    return container.GetAllInstances(service);
}

protected override void BuildUp(object instance)
{
    container.BuildUp(instance);
}
}

Update (clean up) App

We declare the bootstrapper inside Application.Resources, and since we're letting the framework configure everything for us, we can strip these files down to a minimum.

<Application
x:Class="IsItWorthIt.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:IsItWorthIt">

<Application.Resources>
    <local:Bootstrapper x:Key="Bootstrapper"/>
</Application.Resources>

</Application>

and the code-behind

public partial class App : Application
{
    public static PhoneApplicationFrame RootFrame { get; private set; }

public App()
{
  // Standard XAML initialization
  InitializeComponent();

  // Show graphics profiling information while debugging.
  if (Debugger.IsAttached)
  {
      // Display the current frame rate counters.
      Application.Current.Host.Settings.EnableFrameRateCounter = true;

      // Prevent the screen from turning off while under the debugger by disabling
      // the application's idle detection.
      // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run
      // and consume battery power when the user is not using the phone.
      PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
  }
}
}

Displaying our view

Since our application comes with a built-in sample view and viewmodel, let's connect them first. Caliburn.Micro seems to rely on convention over configuration which means a couple things for us:

  • Views and ViewModels are stored in separate folders, named Views and ViewModels. Note that the sample app already creates ViewModels for you.
  • The namespaces for Views and ViewModels should also end in Views and ViewModels.
  • A View and ViewModel are linked by name (e.g. Items <-> ItemsViewModel)

To update the demo app,

  1. Create a Views subdirectory at the same level as ViewModels
  2. Move MainPage.xaml to Views
  3. Update its namespace (remember to update the full class name in .xaml as well. You'll also need to update the path to the SampleData folder by prepending ../)
  4. Delete the code in the constructor that's setting the DataContext (Caliburn.Micro is doing this automagically for us now)
  5. Delete the entire OnNavigatedTo method
  6. Delete the line in DetailsPage.OnNavigatedTo that is setting the DataContext. Details will just have to be broken for now.
  7. Rename MainViewModel to MainPageViewModel
  8. Add a call to LoadData from the MainPageViewModel constructor.
  9. Double-click on Properties/WMAppManifest.xml and update the Navigation Page to Views/MainPage.xaml

After performing the appropriate steps to get the sample MainPage view and viewmodel configured appropriately, you should be able to run the application and see....exactly what you would have seen before we introduced Caliburn.Micro :)

caliburn-integrated

Interested in learning more about developing for Windows Phone 8? Enter your information to receive e-mail notifications on relevant articles.