Saturday, June 7, 2014

Upgrading Caliburn Micro from 1.5 to 2.0 for a WPF application

I am happy to see that the Model-View-View Model (MVVM) framework Caliburn Micro is adopting the Portable Class Library approach in version 2.0, and I thought that now would also be a good time to upgrade some of my existing applications from Caliburn Micro 1.5 to version 2.0.

So far, this seems to be a painless experience, but I ran to a few issues after upgrading to 2.0 via NuGet. I'd thought I share these experiences in case someone else is facing the same issues.

The application in question is a WPF application, and it is using the Managed Extensibility Framework (MEF) for bootstrapping the application.

When trying to build the application immediately after the upgrade, I ran into a compilation error in the class definition line of my MEF bootstrapper class:

public MefBootstrapper : Bootstrapper<IShell>

error CS0246: The type or namespace name 'Bootstrapper' could not be found (are you missing a using directive or an assembly reference?)

Searching the Caliburn Micro documentation, I found that the bootstrapper base class is now called ... BootstrapperBase! And it is non-generic.

OK, this change seems easy:

public MefBootstrapper : BootstrapperBase

Hooray, the application builds! Let's run it. And wait ... and wait ... and wait ... but it never starts?

Of course! Since the bootstrapper base class is now non-generic, there is no way for the bootstrapper to know which View it should start displaying, unless it is explicitly being told which View it should display. And according to this documentation page, the fix is easy; just add

DisplayRootViewFor<IShell>();

to the overridden OnStartup method.

Let's try to run the application again. Still no sight of the root window. What is missing?

Looking more closely into the bootstrapper implementation example here, the constructor also seems to perform some initialization operation. This was not necessary with the pre-2.0 Caliburn Micro versions, most likely because the base class constructor performed this operation instead. But with 2.0 it seems to be necessary to also implement the bootstrapper constructor explicitly. According to the migration instructions here it also seems like the Start method has been renamed Initialize. So, here goes:

public MefBootstrapper() { Initialize(); }

Run the application, and ... Yes! The start-up window appears!

To summarize: when upgrading a WPF/MEF application from using Caliburn Micro version 1.5 or earlier to version 2.0, make sure the following details are in place:

  • The MEF based bootstrapper class should inherit from BootstrapperBase.
  • The root view will be displayed by calling DisplayRootViewFor<> in the overridden OnStartup method.
  • The bootstrapper default constructor must be explicitly defined, and call the Initialize() method.

EDIT

Ironically, when I started upgrading my second application I faced a completely different compilation error:

error CS1501: No overload for method 'Publish' takes 1 arguments

But this issue has a quick and easy fix, as pointed out in the migration instructions:

EventAggregator.Publish now takes an action to marshal the event. Use EventAggregator.PublishOnUIThread for the existing behaviour.


10 comments:

  1. Many thanks! This helped me a lot.

    ReplyDelete
  2. Saved me a lot of time!

    ReplyDelete
  3. Absolutlely mavellous. Thank you very much - had already wasted 2 days on this after upgrading. So simple, yet so obscure.

    ReplyDelete
  4. Great article! Just wanted to say thank you! I was missing the Initialize() in the default constructor!

    ReplyDelete
  5. You saved a lot off time to others :)
    Thank you!

    ReplyDelete