Você está na página 1de 86

Caliburn Micro

http://caliburnmicro.codeplex.com/

Introduction
When my “Build Your Own MVVM Framework” talk was chosen for Mix10, I was excited to have the
opportunity to show others what we had been doing in Caliburn in a simplified, but powerful way.
After giving the talk, I received a ton of positive feedback on the techniques/framework that I had
demonstrated. I was approached by several companies and individuals who expressed an interest in
a more “official” version of what I had shown. That, coupled with the coming of Windows Phone 7,
impressed upon me a need to have a more “lean and mean” framework. My vision was to take 90%
of Caliburn’s features and squash them into 10% of the code. I started with the Mix sample
framework, then used an iterative process of integrating Caliburn v2 features, simplifying and
refactoring. I continued along those lines until I had what I felt was a complete solution that mirrored
the full version of Caliburn v2, but on a smaller scale.

Caliburn.Micro consists of one ~70k assembly (31k in XAP) that builds for WPF4, SL4 and WP7. It has
a single dependency, System.Windows.Interactivity, which you are probably already using regularly
in development. Caliburn.Micro is about 2,700 LOC total, so you can easily go through the whole
codebase in a day and hold it in your head. That’s about 10% of the size of Caliburn v2, which is
running around 27,000 LOC and is a lot harder to grasp in a short time. The best part is that I believe I
was able to put something together that contains all of the features I consider most important in
Caliburn. Here’s a brief list:

 ActionMessages – The Action mechanism allows you to “bind” UI triggers, such as a Button’s
“Click” event, to methods on your View-Model or Presenter. The mechanism allows for
passing parameters to the method as well. Parameters can be databound to other
FrameworkElements or can pass special values, such as the DataContext or EventArgs. All
parameters are automatically type converted to the method’s signature. This mechanism
also allows the “Action.Target” to vary independently of the DataContext and enables it to be
declared at different points in the UI from the trigger. When a trigger occurs, the “message”
bubbles through the element tree looking for an Action.Target (handler) that is capable of
invoking the specified method. This is why we call them messages. The “bubbling” nature of
Acton Messages is extremely powerful and very helpful especially in master/detail scenarios.
In addition to invocation, the mechanism supports a “CanExecute” guard. If the Action has a
corresponding Property or Method with the same name, but precede by the word “Can,” the
invocation of the Action will be blocked and the UI will be disabled. Actions also support
Coroutines (see below). That’s all fairly standard for existing Caliburn users, but we do have a
few improvements in Caliburn.Micro that will be making their way into the larger framework.
The Caliburn.Micro implementation of ActionMessages is built on
System.Windows.Interactivity. This allows actions to be triggered by any TriggerBase
developed by the community. Furthermore, Caliburn.Micro’s Actions have full design-time
support in Blend. Code-centric developers will be happy to know that Caliburn.Micro
supports a very terse syntax for declaring these ActionMessages through a special attached
property called Message.Attach.
 Action Conventions – Out of the box, we support a set of binding conventions around the
ActionMessage feature. These conventions are based on x:Name. So, if you have a method
called “Save” on your ViewModel and a Button named “Save” in your UI, we will
automatically create an EventTrigger for the “Click” event and assign an ActionMessage for
the “Save” method. Furthermore, we will inspect the method’s signature and properly
construct the ActionMessage parameters. This mechanism can be turned off or customized.
You can even change or add conventions for different controls. For example, you could make
the convention event for Button “MouseMove” instead of “Click” if you really wanted.
 Binding Conventions – We also support convention-based databinding. This too works with
x:Name. If you have a property on your ViewModel with the same name as an element, we
will attempt to databind them. Whereas the framework understands convention events for
Actions, it additionally understands convention binding properties (which you can customize
or extend). When a binding name match occurs, we then proceed through several steps to
build up the binding (all of which are customizable), configuring such details as BindingMode,
StringFormat, ValueConverter, Validation and UpdateSourceTrigger (works for SL TextBox
and PasswordBox too). Finally, we support the addition of custom behaviors for certain
scenarios. This allows us to detect whether we need to auto-generate a DataTemplate or
wire both the ItemsSource and the SelectedItem of a Selector based on naming patterns.
 Screens and Conductors – The Screen, ScreenConductor and ScreenCollection patterns
enable model-based tracking of the active or current item, enforcing of screen lifecycles and
elegant shutdown or shutdown cancellation in an application. Caliburn.Micro’s
implementation of these patterns is an evolution of the one found in Caliburn and supports
conducting any type of class, not just implementations of IScreen. These improvements are
being introduced back into Caliburn. You’ll find that Caliburn.Micro’s screen implementation
is quite thorough and even handles asynchronous shutdown scenarios with ease.
 Event Aggregator – Coming in at about 75LOC, Caliburn.Micro’s EventAggregator is simple
yet powerful. The aggregator follows a bus-style pub/sub model. You register a message
handler with the aggregator, and it sends you any messages you are interested in. You
declare your interest in a particular message type by implementing IHandle<TMessage>.
References to handlers are held weakly and publication occurs on the UI thread.
 Coroutines – Any action can optionally choose to return IResult or IEnumerable<IResult>,
opening the door to a powerful approach to handling asynchronous programming.
Furthermore, implementations of IResult have access to an execution context which tells
them what ActionMessage they are executing for, what FrameworkElement triggered the
messsage to be sent, what instance the ActionMessage was handled by (invoked on) and
what the View is for that instance. Such contextual information enables a loosely-coupled,
declarative mechanism by which a Presenter or View-Model can communicate with it’s View
without needing to hold a reference to it at any time.
 ViewLocator – For every ViewModel in your application, Caliburn.Micro has a basic strategy
for locating the View that should render it. We do this based on naming conventions. For
example, if your VM is called MyApplication.ViewModels.ShellViewModel, we will look for
MyApplication.Views.ShellView. Additionally, we support multiple views over the same View-
Model be attaching a View.Context in Xaml. So, given the same model as above, but with a
View.Context=”Master” we would search for MyApplication.Views.Shell.Master. Of course,
all this is customizable.
 WindowManager – This service provides a View-Model-centric way of displaying Windows
(ChildWindow in SL and Window in WPF). Simply pass it an instance of the VM and it will
locate the view, wrap it in a Window if necessary, apply all conventions you have configured
and show the window.
 PropertyChangedBase and BindableCollection – What self respecting WPF/SL framework
could go without a base implementation of INotifyPropertyChanged? The Caliburn.Micro
implementation enables string and lambda-based change notification. It also ensures that all
events are raised on the UI thread. BindableCollection is a simple collection that inherits
from ObservableCollection<T>, but that ensures that all its events are raised on the UI thread
as well.
 Bootstrapper – What’s required to configure this framework and get it up and running? Not
much. Simply inherit from Bootsrapper and add an instance of your custom bootstrapper to
the Application’s ResourceDictionary. Done. If you want, you can override a few methods to
plug in your own IoC container, declare what assemblies should be inspected for Views, etc.
It’s pretty simple.
 Logging – Caliburn.Micro implements a basic logging abstraction. This is important in any
serious framework that encourages Convention over Configuration. All the most important
parts of the framework are covered with logging. Want to know what conventions are or are
not being applied? Turn on logging. Want to know what actions are being executed? Turn on
logging. Want to know what events are being published? Turn on logging. You get the
picture.
 MVVM and MVP – In case it isn’t obvious, this framework enables MVVM. MVVM isn’t hard
on it’s own, but Caliburn.Micro strives to go beyond simply getting it done. We want to write
elegant, testable, maintainable and extensible presentation layer code…and we want it to be
easy to do so. That’s what this is about. If you prefer using Supervising Controller and
PassiveView to MVVM, go right ahead. You’ll find that Caliburn.Micro can help you a lot,
particularly it’s Screen/ScreenConductor implementation. If you are not interested in any of
the goals I just mentioned, you’d best move along. This framework isn’t for you.

Just to be clear, this isn’t a toy framework. As I said, I really focused on supporting the core and most
commonly used features from Caliburn v2. In fact, Caliburn.Micro is going to be my default
framework moving forward and I recommend that if you are starting a new project you begin with
the Micro framework. I’ve been careful to keep the application developer API consistent with the full
version of Caliburn. In fact, the improvements I made in Caliburn.Micro are being folded back into
Caliburn v2. What’s the good part about that? You can start developing with Caliburn.Micro, then if
you hit edge cases or have some other need to move to Caliburn, you will be able to do so with little
or no changes in your application.

Keeping with the spirit of “Build Your Own…” I want developers to understand how this little
framework works, inside and out. I’ve intentionally chosen Mercurial for source control, because I
want developers to take ownership. While I’ve done some work to make the most important parts of
the framework extensible, I’m hoping to see many Forks, each with their own customizations unique
to their application’s needs.
Obtain the Code
There are two ways to get the code:

Mercurial
Caliburn.Micro uses Mercurial for source control. There are many Mercurial clients available that can
be used with CodePlex. TortoiseHG is a popular Mercurial client that works as an extension in
Windows Explorer. For more information please see Using TortoiseHG with CodePlex. If you are new
to Mercurial, I highly recommend that you watch the free TekPub video on the subject here.

Clone URL: https://hg01.codeplex.com/caliburnmicro


Username: <your codeplex user name>
Password: <same as your codeplex password>

Direct download
I only recommend this method if you are really uncomfortable with Mercurial. Simply navigate to the
Source Code tab, click the link for the latest revision, then click the download link.

Build the Code

1. Navigate to the folder where you downloaded the source code.


2. Navigate to the "src" directory.
3. Open Caliburn.Micro.sln.
4. Press Ctrl-Shift-B (or use the Build menu) to build the solution.
5. Locate the assemblies in the "bin" directory under the appropriate platform's project folder.
Basic Configuration, Actions and Conventions
Open Visual Studio and create a new Silverlight 4 Application called “Caliburn.Micro.Hello”. You don’t
need a web site or test project. Add a reference to System.Windows.Interactivity.dll and
Caliburn.Micro.dll. You can find them both in the \src\Caliburn.Micro.Silverlight\Bin\Release (or
Debug) folder. Delete “MainPage.xaml” and clean up your “App.xaml.cs” so that it looks like this:

namespace Caliburn.Micro.Hello
{
using System.Windows;

public partial class App : Application


{
public App()
{
InitializeComponent();
}
}
}

Since Caliburn.Micro prefers a View-Model-First approach, let’s start there. Create your first VM and
call it ShellViewModel. Use the following code for the implementation:

namespace Caliburn.Micro.Hello
{
using System.Windows;

public class ShellViewModel : PropertyChangedBase


{
string name;

public string Name


{
get { return name; }
set
{
name = value;
NotifyOfPropertyChange(() => Name);
NotifyOfPropertyChange(() => CanSayHello);
}
}

public bool CanSayHello


{
get { return !string.IsNullOrWhiteSpace(Name); }
}

public void SayHello()


{
MessageBox.Show(string.Format("Hello {0}!", Name)); //Don't do
this in real life :)
}
}
}

Notice that the ShellViewModel inherits from PropertyChangedBase. This is a base class that
implements the infrastructure for property change notification and automatically performs UI thread
marshalling. It will come in handy :)
Now that we have our VM, let’s create the bootstrapper that will configure the framework and tell it
what to do. Create a new class named HelloBootstrapper. You can use this tiny bit of code:

namespace Caliburn.Micro.Hello
{
public class HelloBootstrapper : Bootstrapper<ShellViewModel> {}
}

There are two Bootsrappers available in Caliburn.Micro. This version allows you to specify the type of
“root view model” via the generic type. The “root view mdoel” is a VM that Caliburn.Micro will
instantiate and use to show your application. Next, we need to place the HelloBootstrapper
somewhere where it will be run at startup. To do that, change your App.xaml to match this:

Silverlight

<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Caliburn.Micro.Hello"
x:Class="Caliburn.Micro.Hello.App">
<Application.Resources>
<local:HelloBootstrapper x:Key="bootstrapper" />
</Application.Resources>
</Application>

WPF

<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Caliburn.Micro.Hello"
x:Class="Caliburn.Micro.Hello.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:HelloBootstrapper x:Key="bootstrapper" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

All we have to do is place a Caliburn.Micro bootstrapper in the Application.Resources and it will do


the rest of the work. Now, run the application. You should see something like this:
Caliburn.Micro creates the ShellViewModel, but doesn’t know how to render it. So, let’s create a
view. Create a new Silverlight User Control named ShellView. Use the following xaml:

<UserControl x:Class="Caliburn.Micro.Hello.ShellView"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBox x:Name="Name" />
<Button x:Name="SayHello"
Content="Click Me" />
</StackPanel>
</UserControl>

Run the application again. You should now see the UI:

Typing something in the TextBox will enable the Button and clicking it will show a message:
Caliburn.Micro uses a simple naming convention to locate Views for ViewModels. Essentially, it takes
the FullName and removes “Model” from it. So, given MyApp.ViewModels.MyViewModel, it would
look for MyApp.Views.MyView. Looking at the View and ViewModel side-by-side, you can see that
the TextBox with x:Name=”Name” is bound to the “Name” property on the VM. You can also see that
the Button with x:Name=”SayHello” is bound to the method with the same name on the VM. The
“CanSayHello” property is guarding access to the “SayHello” action by disabling the Button. These are
the basics of Caliburn.Micro’s ActionMessage and Conventions functionality. There’s much more to
show. But, next time I want to show how we can integrate an IoC container such as MEF.

Samples
Caliburn Micro Hello
Customizing The Bootstrapper
In the last part we discussed the most basic configuration for Caliburn.Micro and demonstrated a
couple of simple features related to Actions and Conventions. In this part, I would like to explore the
Bootstrapper class a little more. Let’s begin by configuring our application to use an IoC container.
We’ll use MEF for this example, but Caliburn.Micro will work well with any container. First, go ahead
and grab the code from Part 1 or download the code for this article. We are going to use that as our
starting point. Add two additional references: System.ComponentModel.Composition and
System.ComponentModel.Composition.Initialization. Those are the assemblies that contain MEF’s
functionality.1 Now, let’s create a new Bootstrapper called MefBootstrapper. Use the following code:

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;

public class MefBootstrapper : Bootstrapper<IShell>


{
private CompositionContainer container;

protected override void Configure()


{
container = CompositionHost.Initialize(
new AggregateCatalog(
AssemblySource.Instance.Select(x => new
AssemblyCatalog(x)).OfType<ComposablePartCatalog>()
)
);

var batch = new CompositionBatch();

batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(container);

container.Compose(batch);
}

protected override object GetInstance(Type serviceType, string key)


{
string contract = string.IsNullOrEmpty(key) ?
AttributedModelServices.GetContractName(serviceType) : key;
var exports = container.GetExportedValues<object>(contract);

if (exports.Count() > 0)
return exports.First();

throw new Exception(string.Format("Could not locate any instances of


contract {0}.", contract));
}

protected override IEnumerable<object> GetAllInstances(Type serviceType)


{
return
container.GetExportedValues<object>(AttributedModelServices.GetContractName(service
Type));
}

protected override void BuildUp(object instance)


{
container.SatisfyImportsOnce(instance);
}
}
That’s all the code to integrate MEF. First, we override the Configure method of the Bootstrapper
class. This gives us an opportunity to set up our IoC container as well as perform any other
framework configuration we may want to do, such as customizing conventions. In this case, I’m
taking advantage of Silverlight’s CompositionHost to setup the CompositionContainer. You can just
instantiate the container directly if you are working with .NET. Then, I’m creating an
AggregateCatalog and populating it with AssemblyCatalogs; one for each Assembly in
AssemblySource.Instance. So, what is AssemblySoure.Instance? This is the place that Caliburn.Micro
looks for Views. You can add assemblies to this at any time during your application to make them
available to the framework, but there is also a special place to do it in the Bootstrapper. Simply
override SelectAssemblies like this:

protected override IEnumerable<Assembly> SelectAssemblies()


{
return new[] {
Assembly.GetExecutingAssembly()
};
}

All you have to do is return a list of searchable assemblies. By default, the base class returns the
assembly that your Application exists in. So, if all your views are in the same assembly as your
application, you don’t even need to worry about this. If you have multiple referenced assemblies that
contain views, this is an extension point you need to remember. Also, if you are dynamically loading
modules, you’ll need to make sure they get registered with your IoC container and the
AssemblySoure.Instance when they are loaded.

After creating the container and providing it with the catalogs, I make sure to add a few
Caliburn.Micro-specific services. The framework provides default implementations of both
IWindowManager and IEventAggregator. Those are pieces that I’m likely to take dependencies on
elsewhere, so I want them to be available for injection. I also register the container with itself (just a
personal preference).

After we configure the container, we need to tell Caliburn.Micro how to use it. That is the purpose of
the three overrides that follow. “GetInstance” and “GetAllInstances” are required by the framework.
“BuildUp” is optionally used to supply property dependencies to instances of IResult that are
executed by the framework.

Word to the Wise

While Caliburn.Micro does provide ServiceLocator functionality through the Bootstrapper’s overrides
and the IoC class, you should avoid using this directly in your application code. ServiceLocator is
considered by many to be an anti-pattern. Pulling from a container tends to obscure the intent of the
dependent code and can make testing more complicated. In future articles I will demonstrate at least
one scenario where you may be tempted to access the ServiceLocator from a ViewModel. I’ll also
demonstrate some solutions.2

Besides what is shown above, there are some other notable methods on the Bootstrapper. You can
override OnStartup and OnExit to execute code when the application starts or shuts down
respectively and OnUnhandledException to cleanup after any exception that wasn’t specifically
handled by your application code. The last override, DisplayRootView, is unique. Let’s look at how it
is implemented in Bootstrapper<TRootModel>

protected override void DisplayRootView()


{
var viewModel = IoC.Get<TRootModel>();
#if SILVERLIGHT
var view = ViewLocator.LocateForModel(viewModel, null, null);
ViewModelBinder.Bind(viewModel, view, null);

var activator = viewModel as IActivate;


if (activator != null)
activator.Activate();

Application.RootVisual = view;
#else
IWindowManager windowManager;

try
{
windowManager = IoC.Get<IWindowManager>();
}
catch
{
windowManager = new WindowManager();
}

windowManager.Show(viewModel);
#endif
}

The Silverlight version of this method resolves your root VM from the container, locates the view for
it and binds the two together. It then makes sure to “activate” the VM if it implements the
appropriate interface. The WPF version does the same thing by using the WindowManager class,
more or less. DisplayRootView is basically a convenience implementation for model-first
development. If you don’t like it, perhaps because you prefer view-first MVVM, then this is the
method you want to override to change that behavior.

Now that you understand all about the Bootstrapper, let’s get our sample working. We need to add
the IShell interface. In our case, it’s just a marker interface. But, in a real application, you would have
some significant shell-related functionality baked into this contract. Here’s the code:

public interface IShell


{
}

Now, we need to implement the interface and decorate our ShellViewModel with the appropriate
MEF attributes:

[Export(typeof(IShell))]
public class ShellViewModel : PropertyChangedBase, IShell
{
...implementation is same as before...
}
That’s it! Your up and running with MEF and you have a handle on some of the other key extension
point of the Bootstrapper as well.

Samples
Hello Mef

Footnotes

1. If you are using .NET, you will only need to reference System.ComponentModel.Composition.
2. I’m quite guilty of this myself, but I’m trying to be more conscious of it. I’m also excited to
see that modern IoC containers as well as Caliburn.Micro provide some very nice ways to
avoid this situation.
All About Actions

We briefly introduced actions in Pt. 1, but there is so much more to know. To begin our investigation,
we’ll take our simple “Hello” example and see what it looks like when we explicitly create the actions
rather than use conventions. Here’s the Xaml:

<UserControl x:Class="Caliburn.Micro.Hello.ShellView"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-
namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivit
y"
xmlns:cal="http://www.caliburnproject.org">
<StackPanel>
<TextBox x:Name="Name" />
<Button Content="Click Me">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="SayHello" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
</UserControl>

As you can see, the Actions feature leverages System.Windows.Interactivity for it’s trigger
mechanism. This means that you can use anything that inherits from
System.Windows.Interactivity.TriggerBase to trigger the sending of an ActionMessage.1 Perhaps the
most common trigger is an EventTrigger, but you can create almost any kind of trigger imaginable or
leverage some common triggers already created by the community. ActionMessage is, of course, the
Caliburn.Micro-specific part of this markup. It indicates that when the trigger occurs, we should send
a message of “SayHello.” So, why do I use the language “send a message” instead of “execute a
method” when describing this functionality? That’s the interesting and powerful part. ActionMessage
bubbles through the Visual Tree searching for a target instance that can handle it. If a target is found,
but does not have a “SayHello” method, the framework will continue to bubble until it finds one,
throwing an exception if no “handler” is found.2 This bubbling nature of ActionMessage comes in
handy in a number of interesting scenarios, Master/Details being a key use case. Another important
feature to note is Action guards. When a handler is found for the “SayHello” message, it will check to
see if that class also has either a property or a method named “CanSayHello.” If you have a guard
property and your class implements INotifyPropertyChanged, then the framework will observe
changes in that property and re-evaluate the guard accordingly. We’ll discuss method guards in
further detail below.

Action Targets
Now you’re probably wondering how to specify the target of an ActionMessage. Looking at the
markup above, there’s no visible indication of what that target will be. So, where does that come
from? Since we used a Model-First approach, when Caliburn.Micro (hereafter CM) created the view
and bound it to the ViewModel using the ViewModelBinder, it set this up for us. Anything that goes
through the ViewModelBinder will have its action target set automatically. But, you can set it
yourself as well, using the attached property Action.Target. Setting this property positions an
ActionMessage “handler” in the Visual Tree attached to the node on with you declare the property. It
also sets the DataContext to the same value, since you often want these two things to be the same.
However, you can vary the Action.Target from the DataContext if you like. Simply use the
Action.TargetWithoutContext attached property instead. One nice thing about Action.Target is that
you can set it to a System.String and CM will use that string to resolve an instance from the IoC
container using the provided value as its key. This gives you a nice way of doing View-First MVVM if
you so desire. If you want Action.Target set and you want Action/Binding Conventions applied as
well, you can use the Bind.Model attached property in the same way.

View First
Let’s see how we would apply this to achieve MVVM using a View-First technique (gasp!) Here’s how
we would change our bootstrapper:

public class MefBootstrapper : Bootstrapper


{
//same as before

protected override void DisplayRootView()


{
Application.Current.RootVisual = new ShellView();
}

//same as before
}

Because we are using View-First, we’ve inherited from the non-generic Bootstrapper. The MEF
configuration is the same as seen previously, so I have left that out for brevity’s sake. The only other
thing that is changed is how the view gets created. In this scenario, we simply override
DisplayRootView, instantiate the view ourselves and set it as the RootVisual (or call Show in the case
of WPF). Next, we’ll slightly alter how we are exporting our ShellViewModel, by adding an explicitly
named contract:

[Export("Shell", typeof(IShell))]
public class ShellViewModel : PropertyChangedBase, IShell
{
//same as before
}

Finally, we will alter our view to pull in the VM and perform all bindings:

<UserControl x:Class="Caliburn.Micro.ViewFirst.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
cal:Bind.Model="Shell">
<StackPanel>
<TextBox x:Name="Name" />
<Button x:Name="SayHello"
Content="Click Me" />
</StackPanel>
</UserControl>
Notice the use of the Bind.Model attached property. This resolves our VM by key from the IoC
container, sets the Action.Target and DataContext and applies all conventions. I thought it would be
nice to show how View-First development is fully supported with CM, but mainly I want to make
clear the various ways that you can set targets for actions and the implications of using each
technique. Here’s a summary of the available attached properties:

 Action.Target – Sets both the Action.Target property and the DataContext property to the
specified instance. String values are used to resolve an instance from the IoC container.
 Action.TargetWithoutContext – Sets only the Action.Target property to the specified
instance. String values are used to resolve an instance from the IoC container.
 Bind.Model – View-First - Set’s the Action.Target and DataContext properties to the specified
instance. Applies conventions to the view. String values are used to resolve an instance from
the IoC container.
 View.Model – ViewModel-First – Locates the view for the specified VM instance and injects
it at the content site. Sets the VM to the Action.Target and the DataContext. Applies
conventions to the view.

Action Parameters
Now, let’s take a look at another interesting aspect of ActionMessage: Parameters. To see this in
action, let’s switch back to our original ViewModel-First bootstrapper, etc. and begin by changing our
ShellViewModel to look like this:

using System.ComponentModel.Composition;
using System.Windows;

[Export(typeof(IShell))]
public class ShellViewModel : IShell
{
public bool CanSayHello(string name)
{
return !string.IsNullOrWhiteSpace(name);
}

public void SayHello(string name)


{
MessageBox.Show(string.Format("Hello {0}!", name));
}
}

There are a few things to note here. First, we are now working with a completely POCO class; no
INPC goop here. Second, we have added an input parameter to our SayHello method. Finally, we
changed our CanSayHello property into a method with the same inputs as the action, but with a bool
return type. Now, let’s have a look at the Xaml:

<UserControl x:Class="Caliburn.Micro.HelloParameters.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-
namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cal="http://www.caliburnproject.org">
<StackPanel>
<TextBox x:Name="Name" />
<Button Content="Click Me">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="SayHello">
<cal:Parameter Value="{Binding ElementName=Name,
Path=Text}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
</UserControl>

Our markup now has one modification: We declared the parameter as part of the ActionMessage
using an ElementName Binding. You can have any number of parameters you desire. Value is a
DependencyProperty, so all the standard binding capabilities apply to parameters. Did I mention you
can do all this in Blend?

One thing that is nice about this is that every time the value of a parameter changes, we’ll call the
guard method associated with the action(CanSayHello in this case) and use its result to update the UI
that the ActionMessage is attached to. Go ahead and run the application. You’ll see that it behaves
the same as in previous examples.

In addition to literal values and Binding Expressions, there are a number of helpful “special” values
that you can use with parameters. These allow you a convenient way to access common contextual
information:

 $eventArgs – Passes the Trigger’s EventArgs or input parameter to your Action. Note: This
will be null for guard methods since the trigger hasn’t actually occurred.
 $dataContext – Passes the DataContext of the element that the ActionMessage is attached
to. This is very useful in Master/Detail scenarios where the ActionMessage may bubble to a
parent VM but needs to carry with it the child instance to be acted upon.
 $source – The actual FrameworkElement that triggered the ActionMessage to be sent.

You must start the variable with a “$” but the name is treated in a case-insensitive way by CM.

Word to the Wise

Parameters are a convenience feature. They are very powerful and can help you out of some tricky
spots, but they can be easily abused. Personally, I only use parameters in the simplest scenarios. One
place where they have worked nicely for me is in login forms. Another scenario, as mentioned
previously is Master/Detail operations.

Now, do you want to see something truly wicked? Change your Xaml back to this:

<UserControl x:Class="Caliburn.Micro.HelloParameters.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBox x:Name="Name" />
<Button x:Name="SayHello"
Content="Click Me" />
</StackPanel>
</UserControl>

Running the application will confirm for you that CM’s conventions even understand ActionMessage
parameters. We’ll discuss conventions a lot more in the future, but you should be happy to know
that these conventions are case-insensitive and can even detect the before-mentioned “special”
values.

Action Bubbling
Now, lets look at a simple Master/Detail scenario that demonstrates ActionMessage bubbling, but
let’s do it with a shorthand syntax that is designed to be more developer friendly. We’ll start by
adding a simple new class named Model:

using System;

public class Model


{
public Guid Id { get; set; }
}
And then we’ll change our ShellViewModel to this:

using System;
using System.ComponentModel.Composition;

[Export(typeof(IShell))]
public class ShellViewModel : IShell
{
public BindableCollection<Model> Items { get; private set; }

public ShellViewModel()
{
Items = new BindableCollection<Model>{
new Model { Id = Guid.NewGuid() },
new Model { Id = Guid.NewGuid() },
new Model { Id = Guid.NewGuid() },
new Model { Id = Guid.NewGuid() }
};
}

public void Add()


{
Items.Add(new Model { Id = Guid.NewGuid() });
}

public void Remove(Model child)


{
Items.Remove(child);
}
}

Now our shell has a collection of Model instances along with the ability to add or remove from the
collection. Notice that the Remove method takes a single parameter of type Model. Now, let’s
update the ShellView:

<UserControl x:Class="Caliburn.Micro.BubblingAction.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<StackPanel>
<ItemsControl x:Name="Items">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Content="Remove"
cal:Message.Attach="Remove($dataContext)" />
<TextBlock Text="{Binding Id}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Add"
cal:Message.Attach="Add" />
</StackPanel>
</UserControl>

Message.Attach
The first thing to notice is that we are using a more Xaml-developer-friendly mechanism for declaring
our ActionMessages. The Message.Attach property is backed by a simple parser which takes its
textual input and transforms it into the full Interaction.Trigger/ActionMessage that you’ve seen
previously. If you work primarily in the Xaml editor and not in the designer, you’re going to like
Message.Attach. Notice that neither Message.Attach declarations specify which event should send
the message. If you leave off the event, the parser will use the ConventionManager to determine the
default event to use for the trigger. In the case of Button, it’s Click. You can always be explicit of
coarse. Here’s what the full syntax for our Remove message would look like if we were declaring
everything:

<Button Content="Remove"
cal:Message.Attach="[Event Click] = [Action Remove($dataContext)]"
/>

Suppose we were to re-write our parameterized SayHello action with the Message.Attach syntax. It
would look like this:

<Button Content="Click Me"


cal:Message.Attach="[Event Click] = [Action SayHello(Name.Text)]"
/>

But we could also leverage some smart defaults of the parser and do it like this:

<Button Content="Click Me"


cal:Message.Attach="SayHello(Name)" />

You can specify literals as parameters as well and even declare multiple actions by separating them
with a semicolon:

<Button Content="Let's Talk"


cal:Message.Attach="[Event MouseEnter] = [Action Talk('Hello',
Name.Text)]; [Event MouseLeave] = [Action Talk('Goodbye', Name.Text)]" />

WARNING Those developers who ask me to expand this functionality into a full-blown expression
parser will be taken out back and…dealt with. Message.Attach is not about cramming code into Xaml.
It’s purpose is to provide a streamlined syntax for declaring when/what messages to send to the
ViewModel. Please don’t abuse this.

If you haven’t already, run the application. Any doubts you had will hopefully be put to rest when you
see that the message bubbling works as advertised :) Something else I would like to point out is that
CM automatically performs type-conversion on parameters. So, for example, you can pump
TextBox.Text into a System.Double parameter without any fear of a casting issue.

So, we’ve discussed using Interaction.Triggers with ActionMessage, including the use of Parameters
with literals, element bindings3 and special values. We’ve discussed the various ways to set the
action target depending on your needs/architectural style: Action.Target,
Action.TargetWithoutContext, Bind.Model or View.Model. We also saw an example of the bubbling
nature of ActionMessage and demoed it using the streamlined Message.Attach syntax. All along the
way we’ve looked at various examples of conventions in action too. Now, there’s one final killer
feature of ActionMessage we haven’t discussed yet…Coroutines. But, that will have to wait until next
time.

Samples
Explicit Actions
View First
Parameters
Bubbling Actions

Footnotes

1. Currently, the full version of Caliburn is not based on System.Windows.Interactivity.


Caliburn’s trigger mechanism was around long before Blend’s. You may notice a shocking
similarity in the markup. That said, Caliburn v2.0 will be migrated to use the Blend model in
the near future.
2. Actually, if no handler is found, before an exception is thrown, the framework will check the
current DataContext to see if it has the requested method. This seamed like a reasonable
fallback behavior.
3. One important detail about ElementName Bindings that I didn’t mention…It doesn’t work
with WP7 currently. Due to the fact that WP7 is based on a version of Silverlight 3 which had
an incomplete implementation of DependencyObject/DependencyProperty, the
infrastructure is not present to make this work in any sort of sane way. However, parameter
literals and special values still work as described along with all the rest of the ActionMessage
features.
Working with Windows Phone 7
Hopefully, previous articles have you up to speed on what Caliburn.Micro is, its basic configuration,
and how to take advantage of a few of its features. In this part, I want to talk about some WP7
specifics issues. It’s unfortunate that I have to call out WP7, but your going to find that while you may
be an experienced WPF or Silverlight developer, that doesn’t make WP7 development a snap.
Microsoft still has a long ways to go in making “three screens and the cloud” a reality. The new
features in Caliburn.Micro are specifically designed to address some of the shortcomings in WP7,
particularly around Navigation (with ViewModels and Screen Activation), Tombstoning,
Launchers/Choosers and the AppBar.

Bootstrapper

Let’s start by getting our application configured correctly. In previous parts we began by creating a
bootstrapper and adding it to our Application.Resources. We do the same thing on WP7, but we
inherit our bootstrapper from the PhoneBootstrapper class. Here’s how the bootstrapper for our
WP7 sample application looks:

using System;

using System.Collections.Generic;

using Microsoft.Phone.Tasks;

public class HelloWP7Bootstrapper : PhoneBootstrapper


{
PhoneContainer container;

protected override void Configure()


{
container = new PhoneContainer();

container.RegisterSingleton(typeof(MainPageViewModel), "MainPageViewModel",
typeof(MainPageViewModel));
container.RegisterSingleton(typeof(PageTwoViewModel), "PageTwoViewModel",
typeof(PageTwoViewModel));
container.RegisterPerRequest(typeof(TabViewModel), null, typeof(TabViewModel));

container.RegisterInstance(typeof(INavigationService), null, new


FrameAdapter(RootFrame));
container.RegisterInstance(typeof(IPhoneService), null, new
PhoneApplicationServiceAdapter(PhoneService));

container.Activator.InstallChooser<PhoneNumberChooserTask, PhoneNumberResult>();
container.Activator.InstallLauncher<EmailComposeTask>();
}

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);
}
}
Important Note About App.xaml.cs

If you create your WP7 application using a standard Visual Studio template, the generated
App.xaml.cs file will have a lot of code in it. The purpose of this code is to set up the root frame for the
application and make sure everything gets initialized properly. Of course, that's what the
bootstrapper's job is too (and in fact it does a few things better than the out-of-the-box code in
addition to configuring CM). So, you don't need both. When using CM's PhoneBootstrapper, be sure
to clear out all the code from the App.xaml.cs file except for the call to InitializeComponent in the
constructor.

For WP7, there are less IoC container options available. In this case, I’ve written a simple container
myself. You can get the full code for SimpleContainer in the Recipes section of the CM
Documentation. Additionally, I inherited from SimpleContainer to create PhoneContainer, which just
adds some custom activation logic related to Launchers/Choosers. We’ll dig into that a bit later. The
most important thing to note in this code is the use of PhoneBootstrapper and the registrations of
two services: INavigationService, which wraps the RootFrame and IPhoneService, which wraps the
native PhoneService. The RootFrame and PhoneService are created by the PhoneBootstrapper and
added to the appropriate places, so you can keep your App.xaml and App.xaml.cs files clean. Here’s
what they should look like:

<Application x:Class="Caliburn.Micro.HelloWP7.App"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Caliburn.Micro.HelloWP7">
<Application.Resources>
<local:HelloWP7Bootstrapper x:Key="bootstrapper" />
</Application.Resources>
</Application>
using System.Windows;

public partial class App : Application


{
public App()
{
InitializeComponent();
}
}

INavigationService

Let’s dig into what the FrameAdapter implementation of INavigationService does for you. First, you
should know that WP7 enforces a View-First approach to UI at the platform level. Like it or not (I
don’t) the platform is going to create pages at will and the Frame control is going to conduct your
application thusly. You don’t get to control that and there are no extensibility points, unlike the
Silverlight version of the navigation framework. Rather than fight this, I’m going to recommend
embracing the View-First approach for Pages in WP7, but maintaining a Model-First composition
strategy for the sub-components of those pages. In order to support the View-First approach, I’ve
enabled the FrameAdapter to hook into the native navigation frame’s functionality and augment it
with the following behaviors:

When Navigating To a Page

 Use the new ViewModelLocator to conventionally determine the name of the VM that
should be attached to the page being navigated to. Pull that VM by key out of the container.
 If a VM is found, use the ViewModelBinder to connect the Page to the located ViewModel.
 Examine the Page’s QueryString. Look for properties on the VM that match the QueryString
parameters and inject them, performing the necessary type coercion.
 If the ViewModel implements the IActivate interface, call its Activate method.

When Navigating Away From a Page

 Detect whether the associated ViewModel implements the IGuardClose interface.


 If IGuardClose is implemented and the app is not being tombstoned or closed, invoke the
CanClose method and use its result to optionally cancel page navigation.1
 If the ViewModel can close and implements the IDeactivate interface, call it’s Deactivate
method.
 If the application is being tombstoned or closed, pass “true” to the Deactivate method
indicating that the ViewModel should permanently close.

The behavior of the navigation service allows the correct VM to be hooked up to the page, allows
that VM to be notified that it is being navigated to (IActivate), allows it to prevent navigation away
from the current page (IGuardClose) and allows it to clean up after itself on navigation away,
tombstoning or normal “closing” of the application (IDeactivate). All these interfaces (and a couple
more) are implemented by the Screen class. I haven’t discussed Screens and Conductors yet, but you
can get started taking advantage of them with just the simple information I have provided. If you
prefer not to inherit from Screen, you can implement any of the interfaces individually of coarse.
They provide a nice View-Model-Centric, testable and predictable way of responding to navigation
without needing to wire up a ton of event handlers or write important application flow logic in the
page’s code-behind. Simply follow the same naming conventions for View/ViewModels as normal,
plug the FrameAdapter into your IoC container and implement whatever interfaces you care about
on your VMs.

IPhoneService

There’s really not much to say about this. I abstracted an interface for the built-in
PhoneApplicationService and created a decorator. This makes it easy for VMs to take a dependency
on the functionality without being coupled to the actual phone service. I didn’t add any additional
behavior.

Now that we have the basic service explanations over with, let’s create some Views and ViewModels
to get our navigation working and to demonstrate a few other features. The default WP7 template
creates a MainPage.xaml for you and configures the application to use that as its default starting
point. We’ll use that, but change the Xaml to this:

<phone:PhoneApplicationPage x:Class="Caliburn.Micro.HelloWP7.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-
namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-
namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
SupportedOrientations="Portrait"
Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0"
Margin="24,24,0,12">
<TextBlock Text="WP7 Caliburn.Micro"
Style="{StaticResource PhoneTextNormalStyle}" />
<TextBlock Text="Main Page"
Margin="-3,-8,0,0"
Style="{StaticResource PhoneTextTitle1Style}" />
</StackPanel>

<Grid Grid.Row="1">
<Button x:Name="GotoPageTwo"
Content="Goto Page Two" />
</Grid>
</Grid>

<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True">
<shell:ApplicationBar.Buttons>
<cal:AppBarButton IconUri="ApplicationIcon.png"
Text="Page Two"
Message="GotoPageTwo" />
</shell:ApplicationBar.Buttons>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
</phone:PhoneApplicationPage>

The most important thing to note here is the ApplicationBar. Since WP7's out-of-the-box AppBar
buttons and menus do not support behaviors, Caliburn.Micro defines its own. Here we demonstrate
using CM's AppBarButton. It (and the AppBarMenuItem) has a single additional property called
"Message." You can use this to set the Action.Message text you would normally set on any other
control. At runtime CM's ViewModelBinder will inspect the view to see if you are using any of CM's
custom AppBar components. If you are, it will create the necessary Triggers/Actions behind the
scenes and wire everything up. This allows you to use the full features of Actions directly with the
WP7 AppBar.

Here’s what the MainPageViewModel looks like:

using System;

public class MainPageViewModel


{
readonly INavigationService navigationService;
public MainPageViewModel(INavigationService navigationService)
{
this.navigationService = navigationService;
}

public void GotoPageTwo()


{
navigationService.Navigate(new Uri("/PageTwo.xaml?NumberOfTabs=5",
UriKind.RelativeOrAbsolute));
}
}

Here’s what it would look like if we could run it at this point:

It’s pretty simple, but there are a few things worth mentioning. The first is that our
INavigationService is being injected through the constructor. This will happen when we navigate to
the page and the VM is conventionally resolved and wired up. In this case we haven’t implemented
any interfaces or inherited from any base classes. We don’t really care about lifecycle. Take a look at
the GotoPageTwo method (conventionally wired to the big button and hooked into the AppBar by
the ViewModelBinder). We are using the INavigationService to tell the phone to go to PageTwo.xaml.
Remember the query string and have a look at the ViewModel for PageTwo:

using System;
using System.Linq;
[SurviveTombstone]
public class PageTwoViewModel : Conductor<IScreen>.Collection.OneActive {
readonly Func<TabViewModel> createTab;
readonly PivotFix<IScreen> pivotFix;

public PageTwoViewModel(Func<TabViewModel> createTab) {


this.createTab = createTab;
pivotFix = new PivotFix<IScreen>(this);
}

public int NumberOfTabs { get; set; }

protected override void OnInitialize() {


Enumerable.Range(1, NumberOfTabs).Apply(x => {
var tab = createTab();
tab.DisplayName = "Item " + x;
Items.Add(tab);
});

ActivateItem(Items[0]);
}

protected override void OnViewLoaded(object view) {


pivotFix.OnViewLoaded(view, base.OnViewLoaded);
}

protected override void ChangeActiveItem(IScreen newItem, bool closePrevious) {


pivotFix.ChangeActiveItem(newItem, closePrevious, base.ChangeActiveItem);
}
}

The value of the the QueryString parameter “NumberOfTabs” is going to be injected into the
property of the same name on the ViewModel. The OnInitialize method is part of the Activation
lifecycle I mentioned above. If you notice in the bootstrapper’s configuration, PageTwoViewModel is
a Singleton. OnInitialize will be called the first time this page is navigated to, not on any subsequent
times, while OnActivate will be called every time this page is navigated to. These are properties of
the Screen class from which this ViewModel ultimately inherits. Basically, all this method does is
create a parameterized number of child ViewModels (TabViewModel) and then “Activates” the first
one. The Items collection and Activation capabilities come from the Conductor base class. Just to
remind you, I’m going to cover Screens and Conductors much more thoroughly in a future article.
Also, take note of the SurviveTombstone attribute. We’ll get to that soon. One final thing to mention
is that the current version of the phone SDK has a bug in the Pivot control when databinding the
SelectedItem or SelectedIndex property. I've implemented a workaround and plugged it into the view
model. Hopefully the next version of the SDK will resolve this issue and I will be able to remove this
code.

Next, let's look at the view that this is bound to:

<phone:PhoneApplicationPage x:Class="Caliburn.Micro.HelloWP7.PageTwo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-
namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-
namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:Controls="clr-
namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
SupportedOrientations="Portrait"
Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<StackPanel Grid.Row="0"
Margin="24,24,0,12">
<TextBlock Text="WP7 Caliburn.Micro"
Style="{StaticResource PhoneTextNormalStyle}" />
<TextBlock Text="Page Two"
Margin="-3,-8,0,0"
Style="{StaticResource PhoneTextTitle1Style}" />
</StackPanel>

<Controls:Pivot x:Name="Items"
SelectedItem="{Binding ActiveItem, Mode=TwoWay}"
Grid.Row="1">
<Controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</Controls:Pivot.HeaderTemplate>
</Controls:Pivot>
</Grid>

</phone:PhoneApplicationPage>

It looks like this when running:


The most interesting part of this view is the Pivot control. We've named it "Items" enabling it to bind
to the Items collection on the ViewModel. Because it's an ItemsControl, it's ItemsSource will be
bound properly. It may be your intuition that Pivot inherits from Selector as well, but it does not. So,
the SelectedItem convention does not get applied. That's why we have to do that manually. We
could fix this by creating a custom convention for Pivot. That's out of the scope of this article, but is
demonstrated in the attached sample.

Let’s take a look at that TabViewModel and it’s corresponding View. First the VM:

using System;
using System.Windows;
using Microsoft.Phone.Tasks;

[SurviveTombstone]
public class TabViewModel : Screen, ILaunchChooser<PhoneNumberResult>
{
string text;

[SurviveTombstone]
public string Text
{
get { return text; }
set
{
text = value;
NotifyOfPropertyChange(() => Text);
}
}

public void Choose()


{
TaskLaunchRequested(this,
TaskLaunchEventArgs.For<PhoneNumberChooserTask>());
}

public event EventHandler<TaskLaunchEventArgs> TaskLaunchRequested = delegate {


};

public void Handle(PhoneNumberResult message)


{
MessageBox.Show("The result was " + message.TaskResult, DisplayName,
MessageBoxButton.OK); //You should abstract this…
}
}

Now you should be noticing some interesting tidbits here. I’ll be coming back to those in a minute.
Let’s take a look at the last piece in our application’s UI, the view for these tabs:

<UserControl x:Class="Caliburn.Micro.HelloWP7.TabView"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Background="{StaticResource PhoneChromeBrush}">
<TextBlock x:Name="DisplayName"
Margin="8 0 0 0"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}" />
<TextBox x:Name="Text" />
<Button Content="Choose"
x:Name="Choose" />
</StackPanel>
</UserControl>

Here we just have a TextBox bound to our Text property and a Button that will execute our Choose
method. Hopefully, you can see how all that comes together in the image above. Let’s add one more
thing, just to make our application complete before we dive into the really interesting parts. I
mentioned that I had modified my SimpleContainer to create a custom PhoneContainer. All I did was
plug in a special Caliburn.Micro piece that helps us use Launchers/Choosers easier (discussed
shortly). Pretty much every IoC Container has a place to plug in custom “activation” logic. This is code
that gets a chance to execute whenever the container creates an instance of a class. For my simple
container, I provided an overridable method to plug this in. It’s a bit different for each container, but
it’s a powerful extensibility point. By plugging in CMs InstanceActivator class, we will make
launchers/chooser so much easier for you. For now, I’ll show you what the PhoneContainer looks
like. We’ll get to the launcher/chooser bit a little later:

using System;

public class PhoneContainer : SimpleContainer


{
public PhoneContainer(WP7Bootstrapper bootStrapper)
{
Activator = new InstanceActivator(bootStrapper, type => GetInstance(type,
null));
}

public InstanceActivator Activator { get; private set; }

protected override object ActivateInstance(Type type, object[] args)


{
return Activator.ActivateInstance(base.ActivateInstance(type, args));
}
}

Tombstoning

Now that we have all the pieces, I can explain why I’ve gone through the trouble of setting all this up:
Tombstoning. At any point in time a WP7 application has to expect that it will be shutdown by the
OS. For example, if someone is using your application and their friend calls them, the phone will
Tombstone your application in order to process the call. When the call is over, your application will
be Resurrected. A well designed WP7 application should restore itself to the exact state it was in
before Tombstoning. The phone’s OS remembers the page you were on and Navigates to it
automatically (read more here). Our Navigation system described above ensures that it gets hooked
up with the right ViewModel. But, you must ensure that that View/ViewModel is put back in the
same state it was in before Tombstoning. That’s where the SurviveTombstone attribute you saw
comes into play. Whenever the OS attempts to Tombstone your application, Caliburn.Micro will grab
the current page, extract its DataContext and see if it has any attributes that implement ITombstone.
This interface is used to serialize a class or property by flattening it and storing it into the
PhoneApplicationService.State property, which is persisted by the OS solely for the purpose of
Resurrection (if it occurs). The SurviveTombstone attribute is a simple out-of-the-box
implementation of this interface that understands how to walk an object graph, examine its
properties and persist them. It has special knowledge of Conductors as well, so that it will persist
their ActiveItem correctly and inspect their children. This is an opt-in mechanism. You must decorate
every class as well as the properties you want persisted. If you look at the classes above, you can see
that the PageTwoViewModel is attributed. Because it is a Conductor, the index of its ActiveItem will
be persisted and each of its Items will be traversed as well. Because each TabViewModel is
attributed, it will be inspected for persistable properties. The Text property is attributed, so that
property on each child item will be persisted. This mechanism is customizable and entirely
replaceable if you don’t like it. First, you can create your own attributes that implement ITombstone
to customize all or part of the process. Second, you can override the SelectInstancesToTombstone
and SelectInstancesToResurrect methods on the PhoneBootstrapper to determine what should be
persisted to begin with. As I mentioned, by default, we only inspect the DataContext of the current
page. But, you could grab several key VMs from your IoC and supply them to the persistence
mechanism here if you like. Lastly, you can override the Tombstone and Resurrect methods on the
PhoneBootstrapper to replace the built-in mechanism all together. If you download the the sample
attached to this article and run the application, you will see that this all works as expected. Try
navigating to the second page, selecting a tab other than the first one and typing some text into the
text box. Next, click the “Choose” button (we are going to talk about choosers next). After the
chooser launches, press the phone’s back button to cancel. Immediately press F5 in Visual Studio to
re-attach the debugger (remember that that chooser caused your application to be tombstoned).
After the debugger is attached, your application goes back to page two with the proper tab selected
and the text filled back in the text box. The chooser result is displayed as well.2 Here’s what you
should see:

Launchers and Choosers


One unique aspect to WP7 development is Tasks. They come in two flavors. Tasks that simply launch
a built-in phone application without returning data, such as EmailComposeTask, are called Launchers.
Tasks that return data back to your application, such as PhoneNumberChooserTask, are called
Choosers. Now, let me tell you how I really feel…the WP7 API for Choosers is a software design
abomination. You need to know how it works for your own benefit and to better appreciate what I
am going to show you, so let me take a moment to explain. Executing a task is as simple as creating
the class and calling its Show method. But, remember that Tombstoning thing? As soon as you call
Show, your application gets Tombstoned. So, right now you should be wondering, “But what if I am
using a Chooser? How do I get the results back into my application?” Well, the official guidance is
that you should have created that Chooser in the constructor of your code-behind file and wired up
its completed event. So, when the phone infrastructure tries to resurrect your application, it will
navigate to that page, the chooser will be re-created and the event re-wired. When you re-wire to
the event, your event handler is called immediately. The infrastructure is trying to fake a cross-app-
instance callback. Now, does that sound like it’s going to play nice with MVVM…or any attempt at
decent software design? One thing is for sure, you have to be very careful about when you create the
Chooser and wire the event. For example, lets say you had the idea that you would create these
Choosers as singletons at startup and just wire their events then and there, in order to remove that
from your pages. Well, it won’t work. You wired the event too early. It’s also quite possible to wire it
too late. It must be done at just the right time. But, what is the right time? From what I can tell, it’s
not clearly defined by their API. If you do it in your page’s constructor, it should work though. But
should you handle the event in the constructor? Probably not, especially since your main UI isn’t
even visible yet. So, you probably at least need to wire for the Loaded event and delay handling of
the callback until the UI is visible. As you can see, this part of the WP7 API is a disaster. I’ve done
some things to try to improve this and make it more friendly to UI architecture. The following
functionality is handled by the InstanceActivator and must be hooked into your IoC container for it to
be enabled. Here’s how it works:

 First, developers register the Launcher/Chooser types they intend to use with the Activator.
If you look back at the sample’s bootstrapper, you will see that I used the methods
InstallLauncher and InstallChooser.
 Each instance that is created by the IoC container will be inspected by the Activator to see if
it implements certain interfaces.
 If the instance implements ILaunchTask or ILaunchChooser<TResult>, the activator will wire
itself to the event defined by the interface.
 When the VM wants to execute a task, it raises ILaunchTask.TaskLaunchRequested. You can
see an example of this in the the TabViewModel.Choose method.
 The infrastructure is notified of the event and then determines if the sender implements
IConfigureTask<TTask>. If it does, the task instance is passed to the sender’s Configure
method. (Some tasks have parameters which must be set, but the sample above does not.)
 Next, the infrastructure “records” the sender of the event so that it knows who to call back
after resurrection.
 The infrastructure now calls Show on the task and your application is Tombstoned.
 When, your application resurrects, it should put itself back in the state it was before
tombstoning.
 Since all instances come from the IoC container, we inspect each instance that is created to
see if it was the one we “recorded” as the sender of the task launch.
 When we find a match, we attempt to call ILaunchChooser<TResult>.Handle with the
Chooser result at the “latest possible time.” The latest possible time is evaluated based on
the features of the class. If it is IViewAware, we call handle after the View’s Loaded event
fires. If it isn’t but implements IActivate, we call Handle after the class is activated (assuming
it isn’t already activated.) If these conditions aren’t met, we call Handle immediately.

It sounds complicated. That’s mostly because, frankly, Choosers are not very friendly to any sort of
reasonable software design. However, I think the result of the custom Activator, especially when
combined with the SurviveTombstone attribute is a very natural developer experience. If you run the
sample, you will see that this does indeed work and that the Chooser result is passed back to the
correct VM after it’s View is shown.

I’ve gone through a lot of WP7 specific stuff in this article. Please remember that all of this is
completely optional. You can still leverage Caliburn.Micro without it. I think the FrameAdapter will
prove to be the most useful and generalizable feature for building UI. Hopefully the simple
tombstoning mechanism and Launcher/Chooser abstraction will help you too.

Samples
Hello WP7
IResult and Coroutines
Previously, I mentioned that there was one more compelling feature of the Actions concept called
Coroutines. If you haven’t heard that term before, here’s what wikipedia1 has to say:

In computer science, coroutines are program components that generalize subroutines to allow
multiple entry points for suspending and resuming execution at certain locations. Coroutines are well-
suited for implementing more familiar program components such as cooperative tasks,
iterators,infinite lists and pipes.

Here’s one way you can thing about it: Imagine being able to execute a method, then pause it’s
execution on some statement, go do something else, then come back and resume execution where
you left off. This technique is extremely powerful in task-based programming, especially when those
tasks need to run asynchronously. For example, let’s say we have a ViewModel that needs to call a
web service asynchronously, then it needs to take the results of that, do some work on it and call
another web service asynchronously. Finally, it must then display the result in a modal dialog and
respond to the user’s dialog selection with another asynchronous task. Accomplishing this with the
standard event-driven async model is not a pleasant experience. However, this is a simple task to
accomplish by using coroutines. The problem…C# doesn’t implement coroutines natively.
Fortunately, we can (sort of) build them on top of iterators.

There are two things necessary to take advantage of this feature in Caliburn.Micro: First, implement
the IResult interface on some class, representing the task you wish to execute; Second, yield
instances of IResult from an Action2. Let’s make this more concrete. Say we had a Silverlight
application where we wanted to dynamically download and show screens not part of the main
package. First we would probably want to show a “Loading” indicator, then asynchronously
download the external package, next hide the “Loading” indicator and finally navigate to a particular
screen inside the dynamic module. Here’s what the code would look like if your first screen wanted
to use coroutines to navigate to a dynamically loaded second screen:

using System.Collections.Generic;
using System.ComponentModel.Composition;

[Export(typeof(ScreenOneViewModel))]
public class ScreenOneViewModel
{
public IEnumerable<IResult> GoForward()
{
yield return Loader.Show("Downloading...");
yield return new
LoadCatalog("Caliburn.Micro.Coroutines.External.xap");
yield return Loader.Hide();
yield return new ShowScreen("ExternalScreen");
}
}

First, notice that the Action “GoForward” has a return type of IEnumerable<IResult>. This is critical
for using coroutines. The body of the method has four yield statements. Each of these yields is
returning an instance of IResult. The first is a result to show the “Downloading” indicator, the second
to download the xap asynchronously, the third to hide the “Downloading” message and the fourth to
show a new screen from the downloaded xap. After each yield statement, the compiler will “pause”
the execution of this method until that particular task completes. The first, third and fourth tasks are
synchronous, while the second is asynchronous. But the yield syntax allows you to write all the code
in a sequential fashion, preserving the original workflow as a much more readable and declarative
structure. To understand a bit more how this works, have a look at the IResult interface:

public interface IResult


{
void Execute(ActionExecutionContext context);
event EventHandler<ResultCompletionEventArgs> Completed;
}

It’s a fairly simple interface to implement. Simply write your code in the “Execute” method and be
sure to raise the “Completed” event when you are done, whether it be a synchronous or an
asynchronous task. Because coroutines occur inside of an Action, we provide you with an
ActionExecutionContext useful in building UI-related IResult implementations. This allows the
ViewModel a way to declaratively state it intentions in controlling the view without having any
reference to a View or the need for interaction-based unit testing. Here’s what the
ActionResultContext looks like:

public class ActionExecutionContext


{
public ActionMessage Message;
public FrameworkElement Source;
public object EventArgs;
public object Target;
public DependencyObject View;
public MethodInfo Method;
public Func<bool> CanExecute;
public object this[string key];
}

And here’s an explanation of what all these properties mean:

 Message – The original ActionMessage that caused the invocation of this IResult.
 Source – The FrameworkElement that triggered the execution of the Action.
 EventArgs – Any event arguments associated with the trigger of the Action.
 Target – The class instance on which the actual Action method exists.
 View – The view associated with the Target.
 Method – The MethodInfo specifying which method to invoke on the Target instance.
 CanExecute – A function that returns true if the Action can be invoked, false otherwise.
 Key Index: A place to store/retrieve any additional metadata which may be used by
extensions to the framework.

Bearing that in mind, I wrote a naive Loader IResult that searches the VisualTree looking for the first
instance of a BusyIndicator to use to display a loading message. Here’s the implementation:

using System;
using System.Windows;
using System.Windows.Controls;

public class Loader : IResult


{
readonly string message;
readonly bool hide;
public Loader(string message)
{
this.message = message;
}

public Loader(bool hide)


{
this.hide = hide;
}

public void Execute(ActionExecutionContext context)


{
var view = context.View as FrameworkElement;
while(view != null)
{
var busyIndicator = view as BusyIndicator;
if(busyIndicator != null)
{
if(!string.IsNullOrEmpty(message))
busyIndicator.BusyContent = message;
busyIndicator.IsBusy = !hide;
break;
}

view = view.Parent as FrameworkElement;


}

Completed(this, new ResultCompletionEventArgs());


}

public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };

public static IResult Show(string message = null)


{
return new Loader(message);
}

public static IResult Hide()


{
return new Loader(true);
}
}

See how I took advantage of context.View? This opens up a lot of possibilities while maintaining
separation between the view and the view model. Just to list a few interesting things you could do
with IResult implementations: show a message box, show a VM-based modal dialog, show a VM-
based Popup at the user’s mouse position, play an animation, show File Save/Load dialogs, place
focus on a particular UI element based on VM properties rather than controls, etc. Of coarse, one of
the biggest opportunities is calling web services. Let’s look at how you might do that, but by using a
slightly different scenario, dynamically downloading a xap:

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.ReflectionModel;
using System.Linq;

public class LoadCatalog : IResult


{
static readonly Dictionary<string, DeploymentCatalog> Catalogs = new
Dictionary<string, DeploymentCatalog>();
readonly string uri;
[Import]
public AggregateCatalog Catalog { get; set; }

public LoadCatalog(string relativeUri)


{
uri = relativeUri;
}

public void Execute(ActionExecutionContext context)


{
DeploymentCatalog catalog;

if(Catalogs.TryGetValue(uri, out catalog))


Completed(this, new ResultCompletionEventArgs());
else
{
catalog = new DeploymentCatalog(uri);
catalog.DownloadCompleted += (s, e) =>{
if(e.Error == null)
{
Catalogs[uri] = catalog;
Catalog.Catalogs.Add(catalog);
catalog.Parts
.Select(part =>
ReflectionModelServices.GetPartType(part).Value.Assembly)
.Where(assembly =>
!AssemblySource.Instance.Contains(assembly))
.Apply(x => AssemblySource.Instance.Add(x));
}
else Loader.Hide().Execute(context);

Completed(this, new ResultCompletionEventArgs {


Error = e.Error,
WasCancelled = false
});
};

catalog.DownloadAsync();
}
}

public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };


}

In case it wasn’t clear, this sample is using MEF. Furthermore, we are taking advantage of the
DeploymentCatalog created for Silverlight 4. You don’t really need to know a lot about MEF or
DeploymentCatalog to get the takeaway. Just take note of the fact that we wire for the
DownloadCompleted event and make sure to fire the IResult.Completed event in its handler. This is
what enables the async pattern to work. We also make sure to check the error and pass that along in
the ResultCompletionEventArgs. Speaking of that, here’s what that class looks like:

public class ResultCompletionEventArgs : EventArgs


{
public Exception Error;
public bool WasCancelled;
}

Caliburn.Micro’s enumerator checks these properties after it get’s called back from each IResult. If
there is either an error or WasCancelled is set to true, we stop execution. You can use this to your
advantage. Let’s say you create an IResult for the OpenFileDialog. You could check the result of that
dialog, and if the user canceled it, set WasCancelled on the event args. By doing this, you can write
an action that assumes that if the code following the Dialog.Show executes, the user must have
selected a file. This sort of technique can simplify the logic in such situations. Obviously, you could
use the same technique for the SaveFileDialog or any confirmation style message box if you so
desired. My favorite part of the LoadCatalog implementation shown above, is that the original
implementation was written by a CM user! Thanks janoveh for this awesome submission! As a side
note, one of the things we added to the CM project site is a “Recipes” section. We are going to be
adding more common solutions such as this to that area in the coming months. So, it will be a great
place to check for cool plugins and customizations to the framework.

Another thing you can do is create a series of IResult implementations built around your application’s
shell. That is what the ShowScreen result used above does. Here is its implementation:

using System;
using System.ComponentModel.Composition;

public class ShowScreen : IResult


{
readonly Type screenType;
readonly string name;

[Import]
public IShell Shell { get; set; }

public ShowScreen(string name)


{
this.name = name;
}

public ShowScreen(Type screenType)


{
this.screenType = screenType;
}

public void Execute(ActionExecutionContext context)


{
var screen = !string.IsNullOrEmpty(name)
? IoC.Get<object>(name)
: IoC.GetInstance(screenType, null);

Shell.ActivateItem(screen);
Completed(this, new ResultCompletionEventArgs());
}

public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };

public static ShowScreen Of<T>()


{
return new ShowScreen(typeof(T));
}
}

This bring up another important feature of IResult. Before CM executes a result, it passes it through
the IoC.BuildUp method allowing your container the opportunity to push dependencies in through
the properties. This allows you to create them normally within your view models, while still allowing
them to take dependencies on application services. In this case, we depend on IShell. You could also
have your container injected, but in this case I chose to use the IoC static class internally. As a general
rule, you should avoid pulling things from the container directly. However, I think it is acceptable
when done inside of infrastructure code such as a ShowScreen IResult.

I hope this gives some explanation and creative ideas for what can be accomplished with IResult. Be
sure to check out the sample application attached. There’s a few other interesting things in there as
well.

Samples
Coroutines

Note: Please be sure to run the sample as an out-of-browser application.

Footnotes

1. When I went to look up the “official” definition on wikipedia I was interested to see what it
had to say about implementations in various languages. Scrolling down to the section on
C#…Caliburn was listed! Fun stuff.
2. You can also return a single instance of IResult without using IEnuermable<IResult> if you
just want a simple way to execute a single task.
Screens, Conductors and Composition
Actions, Coroutines and Conventions tend to draw the most attention to Caliburn.Micro, but the
Screens and Conductors piece is probably most important to understand if you want your UI to be
engineered well. It’s particularly important if you want to leverage composition. The terms Screen,
Screen Conductor and Screen Collection have more recently been codified by Jeremy Miller during
his work on the book "Presentation Patterns" for Addison Wesley. While these patterns are primarily
used in CM by inheriting ViewModels from particular base classes, its important to think of them as
roles rather than as View-Models. In fact, depending on your architecture, a Screen could a be a
UserControl, Presenter or ViewModel. That’s getting a little ahead of ourselves though. First, let’s
talk about what these things are in general.

Theory
Screen

This is the simplest construct to understand. You might think of it as a stateful unit of work existing
within the presentation tier of an application. It’s independent from the application shell. The shell
may display many different screens, some even at the same time. The shell may display lots of
widgets as well, but these are not part of any screen. Some screen examples might be a modal dialog
for application settings, a code editor window in Visual Studio or a page in a browser. You probably
have a pretty good intuitive sense about this.

Often times a screen has a lifecycle associated with it which allows the screen to perform custom
activation and deactivation logic. This is what Jeremy calls the ScreenActivator. For example, take the
Visual Studio code editor window. If you are editing a C# code file in one tab, then you switch to a tab
containing an XML document, you will notice that the toolbar icons change. Each one of those
screens has custom activation/deactivation logic that enables it to setup/teardown the application
toolbars such that they provide the appropriate icons based on the active screen. In simple scenarios,
the ScreenActivator is often the same class as the Screen. However, you should remember that these
are two separate roles. If a particular screen has complex activation logic, it may be necessary to
factor the ScreenActivator into its own class in order to reduce the complexity of the Screen. This is
particularly important if you have an application with many different screens, but all with the same
activation/deactivation logic.

Screen Conductor

Once you introduce the notion of a Screen Activation Lifecycle into your application, you need some
way to enforce it. This is the role of the ScreenConductor. When you show a screen, the conductor
makes sure it is properly activated. If you are transitioning away from a screen, it makes sure it gets
deactivated. There’s another scenario that’s important as well. Suppose that you have a screen which
contains unsaved data and someone tries to close that screen or even the application. The
ScreenConductor, which is already enforcing deactivation, can help out by implementing Graceful
Shutdown. In the same way that your Screen might implement an interface for
activation/deactivation, it may also implement some interface which allows the conductor to ask it
“Can you close?” This brings up an important point: in some scenarios deactivating a screen is the
same as closing a screen and in others, it is different. For example, in Visual Studio, it doesn’t close
documents when you switch from tab to tab. It just activates/deactivates them. You have to explicitly
close the tab. That is what triggers the graceful shutdown logic. However, in a navigation based
application, navigating away from a page would definitely cause deactivation, but it might also cause
that page to close. It all depends on your specific application’s architecture and it’s something you
should think carefully about.

Screen Collection

In an application like Visual Studio, you would not only have a ScreenConductor managing activation,
deactivation, etc., but would also have a ScreenCollection maintaining the list of currently opened
screens or documents. By adding this piece of the puzzle, we can also solve the issue of deactivation
vs. close. Anything that is in the ScreenCollection remains open, but only one of those items is active
at a time. In an MDI-style application like VS, the conductor would manage switching the active
screen between members of the ScreenCollection. Opening a new document would add it to the
ScreenCollection and switch it to the active screen. Closing a document would not only deactivate it,
but would remove it from the ScreenCollection. All that would be dependent on whether or not it
answers the question “Can you close?” positively. Of course, after the document is closed, the
conductor needs to decide which of the other items in the ScreenCollection should become the next
active document.

Implementations
There are lots of different ways to implement these ideas. You could inherit from a TabControl and
implement an IScreenConductor interface and build all the logic directly in the control. Add that to
your IoC container and you’re off and running. You could implement an IScreen interface on a
custom UserControl or you could implement it as a POCO used as a base for Supervising Controllers.
ScreenCollection could be a custom collection with special logic for maintaining the active screen, or
it could just be a simple IList<IScreen>.

Caliburn.Micro Implementations

These concepts are implemented in CM through various interfaces and base classes which can be
used mostly1 to build ViewModels. Let’s take a look at them:

Screens

In Caliburn.Micro we have broken down the notion of screen activation into several interfaces:

 IActivate – Indicates that the implementer requires activation. This interface provides an
Activate method, an IsActive property and an Activated event which should be raised when
activation occurs.
 IDeactivate – Indicates that the implementer requires deactivation. This interface has a
Deactivate method which takes a bool property indicating whether to close the screen in
addition to deactivating it. It also has two events: AttemptingDeactivation, which should be
raised before deactivation and Deactivated which should be raised after deactivation.
 IGuardClose – Indicates that the implementer may need to cancel a close operation. It has
one method: CanClose. This method is designed with an async pattern, allowing complex
logic such as async user interaction to take place while making the close decision. The caller
will pass an Action<bool> to the CanClose method. The implementer should call the action
when guard logic is complete. Pass true to indicate that the implementer can close, false
otherwise.

In addition to these core lifecycle interfaces, we have a few others to help in creating consistency
between presentation layer classes:

 IHaveDisplayName – Has a single property called DisplayName


 INotifyPropertyChangedEx – This interface inherits from the standard
INotifyPropertyChanged and augments it with additional behaviors. It adds an IsNotifying
property which can be used to turn off/on all change notification, a NotifyOfPropertyChange
method which can be called to raise a property change and a Refresh method which can be
used to refresh all bindings on the object.
 IObservableCollection<T> – Composes the following interfaces: IList<T>,
INotifyPropertyChangedEx and INotifyCollectionChanged
 IChild<T> – Implemented by elements that are part of a hierarchy or that need a reference to
an owner. It has one property named Parent.
 IViewAware – Implemented by classes which need to be made aware of the view that they
are bound to. It has an AttachView method which is called by the framework when it binds
the view to the instance. It has a GetView method which the framework calls before creating
a view for the instance. This enables caching of complex views or even complex view
resolution logic. Finally, it has an event which should be raised when a view is attached to the
instance called ViewAttached.

Because certain combinations are so common, we have some convenience interfaces and base
classes:

 PropertyChangedBase – Implements INotifyPropertyChangedEx (and thus


INotifyPropertyChanged). It provides a lambda-based NotifyOfPropertyChange method in
addition to the standard string mechanism, enabling strongly-typed change notification. Also,
all property change events are automatically marshaled to the UI thread.2
 BindableCollection – Implements IObservableCollection<T> by inheriting from the standard
ObservableCollection<T> and adding the additional behavior specified by
INotifyPropertyChangedEx. Also, this class ensures that all property change and collection
change events occur on the UI thread.(2)
 IScreen – This interface composes several other interfaces: IHaveDisplayName, IActivate,
IDeactivate, IGuardClose and INotifyPropertyChangedEx
 Screen – Inherits from PropertyChangedBase and implements the IScreen interface.
Additionally, IChild<IConductor> and IViewAware are implemented.

What this all means is that you will probably inherit most of your view models from either
PropertyChangedBase or Screen. Generally speaking, you would use Screen if you need any of the
activation features and PropertyChangedBase for everything else. CM’s default Screen
implementation has a few additional features as well and makes it easy to hook into the appropriate
parts of the lifecycle:

 OnInitialize – Override this method to add logic which should execute only the first time that
the screen is activated. After initialization is complete, IsInitialized will be true.
 OnActivate – Override this method to add logic which should execute every time the screen
is activated. After activation is complete, IsActive will be true.
 OnDeactivate – Override this method to add custom logic which should be executed
whenever the screen is deactivated or closed. The bool property will indicated if the
deactivation is actually a close. After deactivation is complete, IsActive will be false.
 CanClose – The default implementation always allows closing. Override this method to add
custom guard logic.
 OnViewLoaded – Since Screen implements IViewAware, it takes this as an opportunity to let
you know when your view’s Loaded event is fired. Use this if you are following a
SupervisingController or PassiveView style and you need to work with the view. This is also a
place to put view model logic which may be dependent on the presence of a view even
though you may not be working with the view directly.
 TryClose – Call this method to close the screen. If the screen is being controlled by a
Conductor, it asks the Conductor to initiate the shutdown process for the Screen. If the
Screen is not controlled by a Conductor, but exists independently (perhaps because it was
shown using the WindowManager), this method attempts to close the view. In both
scenarios the CanClose logic will be invoked and if allowed, OnDeactivate will be called with a
value of true.

So, just to re-iterate: if you need a lifecycle, inherit from Screen; otherwise inherit from
PropertyChangedBase.

Conductors

As I mentioned above, once you introduce lifecycle, you need something to enforce it. In
Caliburn.Micro, this role is represented by the IConductor interface which has the following
members:

 ActiveItem – A property that indicates what item the conductor is currently tracking as
active.
 GetConductedItems – Call this method to return a list of all the items that the conductor is
tracking. If the conductor is using a “screen collection,” this returns all the “screens,”
otherwise this only returns ActiveItem.
 ActivateItem – Call this method to activate a particular item. It will also add it to the currently
conducted items if the conductor is using a “screen collection.”
 CloseItem – Call this method to close a particular item. It will also remove it from the
currently conducted items if the conductor is using a “screen collection.”
 ActivationProcessed – Raised when the conductor has processed the activation of an item. It
indicates whether or not the activation was successful.3
 INotifyPropertyChangedEx – This interface is composed into IConductor.

You may have noticed that CM’s IConductor interface uses the term “item” rather than “screen” and
that I was putting the term “screen collection” in quotes. The reason for this is that CM’s conductor
implementations do not require the item being conducted to implement IScreen or any particular
interface. Conducted items can be POCOs. Rather than enforcing the use of IScreen, each of the
conductor implementations is generic, with no constraints on the type. As the conductor is asked to
activate/deactivate/close/etc each of the items it is conducting, it checks them individually for the
following fine-grained interfaces: IActivate, IDeactive, IGuardClose and IChild<IConductor>. In
practice, I usually inherit conducted items from Screen, but this gives you the flexibility to use your
own base class, or to only implement the interfaces for the lifecycle events you care about on a per-
class basis. You can even have a conductor tracking heterogeneous items, some of which inherit from
Screen and others that implement specific interfaces or none at all.

Out of the box CM has two implementations of IConductor, one that works with a “screen collection”
and one that does not. We’ll look at the conductor without the collection first.

Conductor<T>

This simple conductor implements the majority of IConductor’s members through explicit interface
mechanisms and adds strongly typed versions of the same methods which are available publicly. This
allows working with conductors generically through the interface as well as in a strongly typed
fashion based on the items they are conducting. The Conductor<T> treats deactivation and closing
synonymously. Since the Conductor<T> does not maintain a “screen collection,” the activation of
each new item causes both the deactivation and close of the previously active item. The actual logic
for determining whether or not the conducted item can close can be complex due to the async
nature of IGuardClose and the fact that the conducted item may or may not implement this
interface. Therefore, the conductor delegates this to an ICloseStrategy<T> which handles this and
tells the conductor the results of the inquiry. Most of the time you’ll be fine with the
DefaultCloseStrategy<T> that is provided automatically, but should you need to change things
(perhaps IGuardClose is not sufficient for your purposes) you can set the CloseStrategy property on
Conductor<T> to your own custom strategy.

Conductor<T>.Collection.OneActive

This implementation has all the features of Conductor<T> but also adds the notion of a “screen
collection.” Since conductors in CM can conduct any type of class, this collection is exposed through
an IObservableCollection<T> called Items rather than Screens. As a result of the presence of the
Items collection, deactivation and closing of conducted items are not treated synonymously. When a
new item is activated, the previous active item is deactivated only and it remains in the Items
collection. To close an item with this conductor, you must explicitly call its CloseItem method.4 When
an item is closed and that item was the active item, the conductor must then determine which item
should be activated next. Be default, this is the item before the previous active item in the list. If you
need to change this behavior, you can override DetermineNextItemToActivate.

There are two very important details about both of CMs IConductor implementations that I have not
mentioned yet. First, they both inherit from Screen. This is a key feature of these implementations
because it creates a composite pattern between screens and conductors. So, let’s say you are
building a basic navigation-style application. Your shell would be an instance of Conductor<IScreen>
because it shows one Screen at a time and doesn’t maintain a collection. But, let’s say that one of
those screens was very complicated and needed to have a multi-tabbed interface requiring lifecycle
events for each tab. Well, that particular screen could inherit from
Conductor<T>.Collection.OneActive. The shell need not be concerned with the complexity of the
individual screen. One of those screens could even be a UserControl that implemented IScreen
instead of a ViewModel if that’s what was required. The second important detail is a consequence of
the first. Since all OOTB implementations of IConductor inherit from Screen it means that they too
have a lifecycle and that lifecycle cascades to whatever items they are conducting. So, if a conductor
is deactivated, it’s ActiveItem will be deactivated as well. If you try to close a conductor, it’s going to
only be able to close if all of the items it conducts can close. This turns out to be a very powerful
feature. There’s one aspect about this that I’ve noticed frequently trips up developers. If you activate
an item in a conductor that is itself not active, that item won’t actually be activated until the
conductor gets activated. This makes sense when you think about it, but can occasionally cause hair
pulling.

Quasi-Conductors

Not everything in CM that can be a screen is rooted inside of a Conductor. For example, what about
the your root view model? If it’s a conductor, who is activating it? Well, that’s one of the jobs that
the Bootstrapper performs. The Bootstrapper itself is not a conductor, but it understands the fine-
grained lifecycle interfaces discussed above and ensures that your root view model is treated with
the respect it deserves. The WindowManager works in a similar way5 by acting a little like a
conductor for the purpose of enforcing the lifecycle of your modal (and modeless - WPF only)
windows. So, lifecycle isn’t magical. All your screens/conductors must be either rooted in a conductor
or managed by the Bootstrapper or WindowManager to work properly; otherwise you are going to
need to manage the lifecycle yourself.

View-First

If you are working with WP7 or using the Silverlight Navigation Framework, you may be wondering
if/how you can leverage screens and conductors. So far, I’ve been assuming a primarily ViewModel-
First approach to shell engineering. But the WP7 platform enforces a View-First approach by
controlling page navigation. The same is true of the SL Nav framework. In these cases, the Phone/Nav
Framework acts like a conductor. In order to make this play well with ViewModels, the WP7 version
of CM has a FrameAdapter which hooks into the NavigationService. This adapter, which is set up by
the PhoneBootstrapper, understands the same fine-grained lifecycle interfaces that conductors do
and ensures that they are called on your ViewModels at the appropriate points during navigation.
You can even cancel the phone’s page navigation by implementing IGuardClose on your ViewModel.
While the FrameAdapter is only part of the WP7 version of CM, it should be easily portable to
Silverlight should you wish to use it in conjunction with the Silverlight Navigation Framework.

Simple Navigation
Previously, we discussed the theory and basic APIs for Screens and Conductors in Caliburn.Micro.
Now I would like to walk through the first of several samples. This particular sample demonstrates
how to set up a simple navigation-style shell using Conductor<T> and two “Page” view models. As
you can see from the project structure, we have the typical pattern of Bootstrapper and
ShellViewModel. In order to keep this sample as simple as possible, I’m not even using an IoC
container with the Bootstrapper. Let’s look at the ShellViewModel first. It inherits from
Conductor<object> and is implemented as follows:

public class ShellViewModel : Conductor<object> {


public ShellViewModel() {
ShowPageOne();
}

public void ShowPageOne() {


ActivateItem(new PageOneViewModel());
}

public void ShowPageTwo() {


ActivateItem(new PageTwoViewModel());
}
}

Here is the corresponding ShellView:

<UserControl x:Class="Caliburn.Micro.SimpleNavigation.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tc="clr-
namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit">
<tc:DockPanel>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
tc:DockPanel.Dock="Top">
<Button x:Name="ShowPageOne"
Content="Show Page One" />
<Button x:Name="ShowPageTwo"
Content="Show Page Two" />
</StackPanel>

<ContentControl x:Name="ActiveItem" />


</tc:DockPanel>
</UserControl>
Notice that the ShellViewModel has two methods, each of which passes a view model instance to the
ActivateItem method. Recall from our earlier discussion that ActivateItem is a method on
Conductor<T> which will switch the ActiveItem property of the conductor to this instance and push
the instance through the activation stage of the screen lifecycle (if it supports it by implementing
IActivate). Recall also, that if ActiveItem is already set to an instance, then before the new instance is
set, the previous instance will be checked for an implementation of IGuardClose which may or may
not cancel switching of the ActiveItem. Assuming the current ActiveItem can close, the conductor will
then push it through the deactivation stage of the lifecycle, passing true to the Deactivate method to
indicate that the view model should also be closed. This is all it takes to create a navigation
application in Caliburn.Micro. The ActiveItem of the conductor represents the “current page” and the
conductor manages the transitions from one page to the other. This is all done in a ViewModel-First
fashion since its the conductor and it’s child view models that are driving the navigation and not the
“views.”

Once the basic Conductor structure is in place, it’s quite easy to get it rendering. The ShellView
demonstrates this. All we have to do is place a ContentControl in the view. By naming it “ActiveItem”
our data binding conventions kick in. The convention for ContentControl is a bit interesting. If the
item we are binding to is not a value type and not a string, then we assume that the Content is a
ViewModel. So, instead of binding to the Content property as we would in the other cases, we
actually set up a binding with CM’s custom attached property: View.Model. This property causes
CM’s ViewLocator to look up the appropriate view for the view model and CM’s ViewModelBinder to
bind the two together. Once that is complete, we pop the view into the ContentControl’s Content
property. This single convention is what enables the powerful, yet simple ViewModel-First
composition in the framework.

For completeness, let’s take a look at the PageOneViewModel and PageTwoViewModel:

public class PageOneViewModel {}

public class PageTwoViewModel : Screen {


protected override void OnActivate() {
MessageBox.Show("Page Two Activated"); //Don't do this in a real
VM.
base.OnActivate();
}
}

Along with their views:

<UserControl x:Class="Caliburn.Micro.SimpleNavigation.PageOneView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock FontSize="32">Page One</TextBlock>
</UserControl>

<UserControl x:Class="Caliburn.Micro.SimpleNavigation.PageTwoView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock FontSize="32">Page Two</TextBlock>
</UserControl>
I’ve intentionally kept this bare bones so that it’s easy to play around with and see how these pieces
work together. It’s not the slightest bit impressive, but here’s what it looks like:

I’d like to point out a few final things. Notice that PageOneViewModel is just a POCO, but
PageTwoViewModel inherits from Screen. Remember that the conductors in CM don’t place any
constraints on what can be conducted. Rather, they check each instance for support of the various
fine-grained lifecycle instances at the necessary times. So, when ActivateItem is called for
PageTwoViewModel, it will first check PageOneViewModel to see if it implements IGuardClose. Since
it does not, it will attempt to close it. It will then check to see if it implements IDeactivate. Since it
does not, it will just proceed to activate the new item. First it checks if the new item implements
IChild<IConductor>. Since Screen does, it hooks up the hierarchical relationship. Next, it will check
PageTwoViewModel to see if it implements IActivate. Since Screen does, the code in my OnActivate
method will then run. Finally, it will set the ActiveItem property on the conductor and raise the
appropriate events. Here’s an important consequence of this that should be remembered: The
activation is a ViewModel-specific lifecycle process and doesn’t guarantee anything about the state
of the View. Many times, even though your ViewModel has been activated, it’s view may not yet be
visible. You will see this when you run the sample. The MessageBox will show when the activation
occurs, but the view for page two will not yet be visible. Remember, if you have any activation logic
that is dependent on the view being already loaded, you should override Screen.OnViewLoaded
instead of/in combination with OnActivate.

Simple MDI
Let’s look at another example: this time a simple MDI shell that uses “Screen Collections.” As you can
see, once again, I have kept things pretty small and simple:
Here’s a screenshot of the application when it’s running:

Here we have a simple WPF application with a series of tabs. Clicking the “Open Tab” button does
the obvious. Clicking the “X” inside the tab will close that particular tab (also, probably obvious). Let’s
dig into the code by looking at our ShellViewModel:

public class ShellViewModel : Conductor<IScreen>.Collection.OneActive {


int count = 1;

public void OpenTab() {


ActivateItem(new TabViewModel {
DisplayName = "Tab " + count++
});
}
}

Since we want to maintain a list of open items, but only keep one item active at a time, we use
Conductor<T>.Collection.OneActive as our base class. Note that, different from our previous
example, I am actually constraining the type of the conducted item to IScreen. There’s not really a
technical reason for this in this sample, but this more closely mirrors what I would actually do in a
real application. The OpenTab method simply creates an instance of a TabViewModel and sets its
DisplayName property (from IScreen) so that it has a human-readable, unique name. Let’s think
through the logic for the interaction between the conductor and its screens in several key scenarios:

Opening the First Item

1. Adds the item to the Items collection.


2. Checks the item for IActivate and invokes it if present.
3. Sets the item as the ActiveItem.

Opening an Additional Item

1. Checks the current ActiveItem for IDeactivate and invokes if present. False is passed to
indicate that it should be deactivated only, and not closed.
2. Checks the new item to see if it already exists in the Items collection. If not, it is added to the
collection. Otherwise, the existing item is returned.
3. Checks the item for IActivate and invokes if present.
4. Sets the new item as the ActiveItem.

Closing an Existing Item

1. Passes the item to the CloseStrategy to determine if it can be closed (by default it looks for
IGuardClose). If not, the action is cancelled.
2. Checks to see if the closing item is the current ActiveItem. If so, determine which item to
activate next and follow steps from “Opening an Additional Item.”
3. Checks to see if the closing item is IDeactivate. If so, invoke with true to indicate that it
should be deactivated and closed.
4. Remove the item from the Items collection.

Those are the main scenarios. Hopefully you can see some of the differences from a
Conductor without a collection and understand why those differences are there. Let’s see
how the ShellView renders:

<Window x:Class="Caliburn.Micro.SimpleMDI.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
Width="640"
Height="480">
<DockPanel>
<Button x:Name="OpenTab"
Content="Open Tab"
DockPanel.Dock="Top" />
<TabControl x:Name="Items">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DisplayName}" />
<Button Content="X"
cal:Message.Attach="CloseItem($dataContext)" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
</DockPanel>
</Window>
As you can see we are using a WPF TabControl. CM’s conventions will bind its ItemsSource to the
Items collection and its SelectedItem to the ActiveItem. It will also add a default ContentTemplate
which will be used to compose in the ViewModel/View pair for the ActiveItem. Conventions can also
supply an ItemTemplate since our tabs all implement IHaveDisplayName (through Screen), but I’ve
opted to override that by supplying my own to enable closing the tabs. We’ll talk more in depth
about conventions in a later article. For completeness, here are the trivial implementations of
TabViewModel along with its view:

namespace Caliburn.Micro.SimpleMDI {
public class TabViewModel : Screen {}
}

<UserControl x:Class="Caliburn.Micro.SimpleMDI.TabView"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Orientation="Horizontal">
<TextBlock Text="This is the view for "/>
<TextBlock x:Name="DisplayName" />
<TextBlock Text="." />
</StackPanel>
</UserControl>

I’ve tried to keep it simple so far, but that’s not the case for our next sample. In preparation, you
might want to at least think through or try to do these things:

 Get rid of the generic TabViewModel. You wouldn’t really do something like this in a real
application. Create a couple of custom view models and views. Wire things up so that you
can open different view models in the conductor. Confirm that you see the correct view in
the tab control when each view model is activated.
 Rebuild this sample in Silverlight. Unfortunately, Silverlight’s TabControl is utterly broken and
cannot fully leverage databinding. Instead, try using a horizontal ListBox as the tabs and a
ContentControl as the tab content. Put these in a DockPanel and use some naming
conventions and you will have the same affect as a TabControl.
 Create a toolbar view model. Add an IoC container and register the ToolBarViewModel as a
singleton. Add it to the ShellViewModel and ensure that it is rendered in the ShellView
(remember you can use a named ContentControl for this). Next, have the ToolBarViewModel
injected into each of the TabViewModels. Write code in the TabViewModel OnActivate and
OnDeactivate to add/remove contextual items from the toolbar when the particular
TabViewModel is activated. BONUS: Create a DSL for doing this which doesn’t require explicit
code in the OnDeactivate override. HINT: Use the events.
 Take the SimpleMDI sample and the SimpleNavigation sample and compose them together.
Either add the MDI Shell as a PageViewModel in the Navigation Sample or add the Navigation
Shell as a Tab in the MDI Sample.

Hybrid
This sample is based loosely on the ideas demonstrated by Billy Hollis in this well-known DNR TV
episode. Rather than take the time to explain what the UI does, have a look at this short video for a
brief visual explanation.

Ok, now that you’ve seen what it does, let’s look at how it’s put together. As you can see from the
screenshot, I’ve chosen to organize the project by features: Customers, Orders, Settings, etc. In most
projects I prefer to do something like this rather than organizing by “technical” groupings, such as
Views and ViewModels. If I have a complex feature, then I might break that down into those areas.

I’m not going to go line-by-line through this sample. It’s better if you take the time to look through it
and figure out how things work yourself. But, I do want to point out a few interesting
implementation details.

ViewModel Composition

One of the most important features of Screens and Conductors in Caliburn.Micro is that they are an
implementation of the Composite Pattern, making them easy to compose together in different
configurations. Generally speaking, composition is one of the most important aspects of object
oriented programming and learning how to use it in your presentation tier can yield great benefits.
To see how composition plays a role in this particular sample, lets look at two screenshots. The first
shows the application with the CustomersWorkspace in view, editing a specific Customer’s Address.
The second screen is the same, but with its View/ViewModel pairs rotated three-dimensionally, so
you can see how the UI is composed.

Editing a Customer’s Address

Editing a Customer’s Address (3D Breakout)


In this application, the ShellViewModel is a Conductor<IWorkspace>.Collection.OneActive. It is
visually represented by the Window Chrome, Header and bottom Dock. The Dock has buttons, one
for each IWorkspace that is being conducted. Clicking on a particular button makes the Shell activate
that particular workspace. Since the ShellView has a TransitioningContentControl bound to the
ActiveItem, the activated workspace is injected and it’s view is shown at that location. In this case,
it’s the CustomerWorkspaceViewModel that is active. It so happens that the
CustomerWorkspaceViewModel inherits from
Conductor<CustomerViewModel>.Collection.OneActive. There are two contextual views for this
ViewModel (see below). In the screenshot above, we are showing the details view. The details view
also has a TransitioningContentControl bound to the CustomerWorkspaceViewModel’s ActiveItem,
thus causing the current CustomerViewModel to be composed in along with its view. The
CustomerViewModel has the ability to show local modal dialogs (they are only modal to that specific
custom record, not anything else). This is managed by an instance of DialogConductor, which is a
property on CustomerViewModel. The view for the DialogConductor overlays the CustomerView, but
is only visible (via a value converter) if the DialogConductor’s ActiveItem is not null. In the state
depicted above, the DialogConductor’s ActiveItem is set to an instance of AddressViewModel, thus
the modal dialog is displayed with the AddressView and the underlying CustomerView is disabled.
The entire shell framework used in this sample works in this fashion and is entirely extensible simply
by implementing IWorkspace. CustomerViewModel and SettingsViewModel are two different
implementations of this interface you can dig into.

Multiple Views over the Same ViewModel


You may not be aware of this, but Caliburn.Micro can display multiple Views over the same
ViewModel. This is supported by setting the View.Context attached property on the
View/ViewModel’s injection site. Here’s an example from the default CustomerWorkspaceView:

<clt:TransitioningContentControl cal:View.Context="{Binding State, Mode=TwoWay}"


cal:View.Model="{Binding}"
Style="{StaticResource specialTransition}"/>

There is a lot of other Xaml surrounding this to form the chrome of the CustomerWorkspaceView,
but the content region is the most noteworthy part of the view. Notice that we are binding the
View.Context attached property to the State property on the CustomerWorkspaceViewModel. This
allows us to dynamically change out views based on the value of that property. Because this is all
hosted in the TransitioningContentControl, we get a nice transition whenever the view changes. This
technique is used to switch the CustomerWorkspaceViewModel from a “Master” view, where it
displays all open CustomerViewModels, a search UI and a New button, to a “Detail” view, where it
displays the currently activated CustomerViewModel along with it’s specific view (composed in). In
order for CM to find these contextual views, you need a namespace based on the ViewModel name,
minus the words “View” and “Model”, with some Views named corresponding to the Context. For
example, when the framework looks for the Detail view of
Caliburn.Micro.HelloScreens.Customers.CustomersWorkspaceViewModel, it’s going to look for
Caliburn.Micro.HelloScreens.Customers.CustomersWorkspace.Detail That’s the out-of-the-box
naming convention. If that doesn’t work for you, you can simply customize the
ViewLocator.LocateForModelType func.

Custom IConductor Implementation

Although Caliburn.Micro provides the developer with default implementations of IScreen and
IConductor. It’s easy to implement your own. In the case of this sample, I needed a dialog manager
that could be modal to a specific part of the application without affecting other parts. Normally, the
default Conductor<T> would work, but I discovered I needed to fine-tune shutdown sequence, so I
implemented my own. Let’s take a look at that:

[Export(typeof(IDialogManager)), PartCreationPolicy(CreationPolicy.NonShared)]
public class DialogConductorViewModel : PropertyChangedBase, IDialogManager,
IConductor {
readonly Func<IMessageBox> createMessageBox;

[ImportingConstructor]
public DialogConductorViewModel(Func<IMessageBox> messageBoxFactory) {
createMessageBox = messageBoxFactory;
}

public IScreen ActiveItem { get; private set; }

public IEnumerable GetConductedItems() {


return ActiveItem != null ? new[] { ActiveItem } : new object[0];
}

public void ActivateItem(object item) {


ActiveItem = item as IScreen;
var child = ActiveItem as IChild<IConductor>;
if(child != null)
child.Parent = this;

if(ActiveItem != null)
ActiveItem.Activate();

NotifyOfPropertyChange(() => ActiveItem);


ActivationProcessed(this, new ActivationProcessedEventArgs { Item =
ActiveItem, Success = true });
}

public void CloseItem(object item) {


var guard = item as IGuardClose;
if(guard != null) {
guard.CanClose(result => {
if(result)
CloseActiveItemCore();
});
}
else CloseActiveItemCore();
}

object IConductor.ActiveItem {
get { return ActiveItem; }
set { ActivateItem(value); }
}

public event EventHandler<ActivationProcessedEventArgs> ActivationProcessed =


delegate { };

public void ShowDialog(IScreen dialogModel) {


ActivateItem(dialogModel);
}

public void ShowMessageBox(string message, string title = null,


MessageBoxOptions options = MessageBoxOptions.Ok, Action<IMessageBox> callback =
null) {
var box = createMessageBox();

box.DisplayName = title ?? "Hello Screens";


box.Options = options;
box.Message = message;

if(callback != null)
box.Deactivated += delegate { callback(box); };

ActivateItem(box);
}

void CloseActiveItemCore() {
var oldItem = ActiveItem;
ActivateItem(null);
oldItem.Deactivate(true);
}
}

Strictly speaking, I didn’t actually need to implement IConductor to make this work (since I’m not
composing it into anything). But I chose to do this in order to represent the role this class was playing
in the system and keep things as architecturally consistent as possible. The implementation itself is
pretty straight forward. Mainly, a conductor needs to make sure to Activate/Deactivate its items
correctly and to properly update the ActiveItem property. I also created a couple of simple methods
for showing dialogs and message boxes which are exposed through the IDialogManager interface.
This class is registered as NonShared with MEF so that each portion of the application that wants to
display local modals will get its own instance and be able to maintain its own state, as demonstrated
with the CustomerViewModel discussed above.

Custom ICloseStrategy

Possibly one of the coolest features of this sample is how we control application shutdown. Since
IShell inherits IGuardClose, in the Bootstrapper we just override DisplayRootView and wire
Silverlight’s MainWindow.Closing event to call IShell.CanClose:

protected override void DisplayRootView() {


base.DisplayRootView();

if (Application.IsRunningOutOfBrowser) {
mainWindow = Application.MainWindow;
mainWindow.Closing += MainWindowClosing;
}
}

void MainWindowClosing(object sender, ClosingEventArgs e) {


if (actuallyClosing)
return;

e.Cancel = true;

Execute.OnUIThread(() => {
var shell = IoC.Get<IShell>();

shell.CanClose(result => {
if(result) {
actuallyClosing = true;
mainWindow.Close();
}
});
});
}

The ShellViewModel inherits this functionality through its base class


Conductor<IWorkspace>.Collection.OneActive. Since all the built-in conductors have a CloseStrategy,
we can create conductor specific mechanisms for shutdown and plug them in easily. Here’s how we
plug in our custom strategy:

[Export(typeof(IShell))]
public class ShellViewModel : Conductor<IWorkspace>.Collection.OneActive, IShell
{
readonly IDialogManager dialogs;

[ImportingConstructor]
public ShellViewModel(IDialogManager dialogs,
[ImportMany]IEnumerable<IWorkspace> workspaces) {
this.dialogs = dialogs;
Items.AddRange(workspaces);
CloseStrategy = new ApplicationCloseStrategy();
}

public IDialogManager Dialogs {


get { return dialogs; }
}
}
And here’s the implementation of that strategy:

public class ApplicationCloseStrategy : ICloseStrategy<IWorkspace> {


IEnumerator<IWorkspace> enumerator;
bool finalResult;
Action<bool, IEnumerable<IWorkspace>> callback;

public void Execute(IEnumerable<IWorkspace> toClose, Action<bool,


IEnumerable<IWorkspace>> callback) {
enumerator = toClose.GetEnumerator();
this.callback = callback;
finalResult = true;

Evaluate(finalResult);
}

void Evaluate(bool result)


{
finalResult = finalResult && result;

if (!enumerator.MoveNext() || !result)
callback(finalResult, new List<IWorkspace>());
else
{
var current = enumerator.Current;
var conductor = current as IConductor;
if (conductor != null)
{
var tasks = conductor.GetConductedItems()
.OfType<IHaveShutdownTask>()
.Select(x => x.GetShutdownTask())
.Where(x => x != null);

var sequential = new SequentialResult(tasks.GetEnumerator());


sequential.Completed += (s, e) => {
if(!e.WasCancelled)
Evaluate(!e.WasCancelled);
};
sequential.Execute(new ActionExecutionContext());
}
else Evaluate(true);
}
}
}

The interesting thing I did here was to reuse the IResult functionality for async shutdown of the
application. Here’s how the custom strategy uses it:

1. Check each IWorkspace to see if it is an IConductor.


2. If true, grab all the conducted items which implement the application-specific interface
IHaveShutdownTask.
3. Retrieve the shutdown task by calling GetShutdownTask. It will return null if there is no task,
so filter those out.
4. Since the shutdown task is an IResult, pass all of these to a SequentialResult and begin
enumeration.
5. The IResult can set ResultCompletionEventArgs.WasCanceled to true to cancel the
application shutdown.
6. Continue through all workspaces until finished or cancellation occurs.
7. If all IResults complete successfully, the application will be allowed to close.

The CustomerViewModel and OrderViewModel use this mechanism to display a modal dialog if there
is dirty data. But, you could also use this for any number of async tasks. For example, suppose you
had some long running process that you wanted to prevent shutdown of the application. This would
work quite nicely for that too.

Samples
Simple Navigation
Simple MDI
Hybrid

Footnotes

1. These classes can also be used very easily to create a SupervisingController or even a
PassiveView design if so desired. Normally, using these classes as view models will suffice,
but since the base implementations Screen, Conductor<T> and
Conductor<T>.Collection.OneActive all implement IViewAware, it’s easy to get a reference to
the view and take one of these alternative approaches. Additionally, since all Caliburn.Micro
code depends only on the interfaces, you could easily implement IConductor on top of a
docking window manager or some other complex control or service.
2. Even though these classes do automatic UI thread marshalling, they are still safe to use in a
unit test. Under the covers, these classes use CM’s Execute.OnUIThread utility method. This
method calls a custom action to do the thread marshalling which is setup by the
Bootstrapper. If you are working with these classes without running the Bootstrapper (as
would be the case with testing), a default action is used which does not do any marshalling.
3. If activation would cause the closing of the ActiveItem, such as it would with Conductor<T>,
and the active item’s CanClose returned false, then activation of the new item would not
succeed. The current item would remain active.
4. Or if the item inherits from Screen, you can call the Screen’s TryClose method, which actually
just calls Parent.CloseItem passing itself as the item to be closed.
5. In fact the WPF version of the Bootstrapper uses the WindowManager internally to show
your MainWindow. I’ll have a whole article on the WindowManager coming soon.
All About Conventions
One of the main features of Caliburn.Micro is manifest in its ability to remove the need for boiler
plate code by acting on a series of conventions. Some people love conventions and some hate them.
That’s why CM’s conventions are fully customizable and can even be turned off completely if not
desired. If you are going to use conventions, and since they are ON by default, it’s good to know what
those conventions are and how they work. That’s the subject of this article.

View Resolution (ViewModel-First)


Basics
The first convention you are likely to encounter when using CM is related to view resolution. This
convention affects any ViewModel-First areas of your application. In ViewModel-First, we have an
existing ViewModel that we need to render to the screen. To do this, CM uses a simple naming
pattern to find a UserControl1 that it should bind to the ViewModel and display. So, what is that
pattern? Let’s just take a look at ViewLocator.LocateForModelType to find out:

public static Func<Type, DependencyObject, object, UIElement> LocateForModelType =


(modelType, displayLocation, context) =>{
var viewTypeName = modelType.FullName.Replace("Model", string.Empty);
if(context != null)
{
viewTypeName = viewTypeName.Remove(viewTypeName.Length - 4, 4);
viewTypeName = viewTypeName + "." + context;
}

var viewType = (from assmebly in AssemblySource.Instance


from type in assmebly.GetExportedTypes()
where type.FullName == viewTypeName
select type).FirstOrDefault();

return viewType == null


? new TextBlock { Text = string.Format("{0} not found.", viewTypeName) }
: GetOrCreateViewType(viewType);
};

Let’s ignore the “context” variable at first. To derive the view, we make an assumption that you are
using the text “ViewModel” in the naming of your VMs, so we just change that to “View” everywhere
that we find it by removing the word “Model”. This has the effect of changing both type names and
namespaces. So ViewModels.CustomerViewModel would become Views.CustomerView. Or if you are
organizing your application by feature: CustomerManagement.CustomerViewModel becomes
CustomerManagement.CustomerView. Hopefully, that’s pretty straight forward. Once we have the
name, we then search for types with that name. We search any assembly you have exposed to CM as
searchable via AssemblySource.Instance.2 If we find the type, we create an instance (or get one from
the IoC container if it’s registered) and return it to the caller. If we don’t find the type, we generate a
view with an appropriate “not found” message.

Now, back to that “context” value. This is how CM supports multiple Views over the same
ViewModel. If a context (typically a string or an enum) is provided, we do a further transformation of
the name, based on that value. This transformation effectively assumes you have a folder
(namespace) for the different views by removing the word “View” from the end and appending the
context instead. So, given a context of “Master” our ViewModels.CustomerViewModel would
become Views.Customer.Master.
Other Things To Know
Besides instantiation of your View, GetOrCreateViewType will call InitializeComponent on your View
(if it exists). This means that for Views created by the ViewLocator, you don’t have to have code-
behinds at all. You can delete them if that makes you happy :) You should also know that
ViewLocator.LocateForModelType is never called directly. It is always called indirectly through
ViewLocator.LocateForModel. LocateForModel takes an instance of your ViewModel and returns an
instance of your View. One of the functions of LocateForModel is to inspect your ViewModel to see if
it implements IViewAware. If so, it will call it’s GetView method to see if you have a cached view or if
you are handling View creation explicitly. If not, then it passes your ViewModel’s type to
LocateForModelType.

Customization
The out-of-the-box convention is pretty simple and based on a number of patterns we’ve used and
seen others use in the real world. However, by no means are you limited to these simple patterns.
You’ll notice that all the methods discussed above are implemented as Funcs rather than actual
methods. This means that you can customize them by simply replacing them with your own
implementations. If you just want to add to the existing behavior, simply store the existing Func in a
variable, create a new Func that calls the old and and assign the new Func to
ViewLocator.LocateForModelType.3

Framework Usage
There are three places that the framework uses the ViewLocator; three places where you can expect
the view location conventions to be applied. The first place is in Bootstrapper<T>. Here, your root
ViewModel is passed to the locator in order to determine how your application’s shell should be
rendered. In Silverlight this results in the setting or your RootVisual. In WPF, this creates your
MainWindow. In fact, in WPF the bootstrapper delegates this to the WindowManager, which brings
me to… The second place the ViewLocator is used is the WindowManager, which calls it to determine
how any dialog ViewModels should be rendered. The third and final place that leverages these
conventions is the View.Model attached property. Whenever you do ViewModel-First composition
rendering by using the View.Model attached property on a UIElement, the locator is invoked to see
how that composed ViewModel should be rendered at that location in the UI. You can use the
View.Model attached property explicitly in your UI (optionally combining it with the View.Context
attached property for contextual rendering), or it can be added by convention, thus causing
conventional composition of views to occur. See the section below on property binding conventions.

ViewModel Resolution (View-First)


Basics
Though Caliburn.Micro prefers ViewModel-First development, there are times when you may want
to take a View-First approach, especially when working with WP7. In the case where you start with a
view, you will likely then need to resolve a ViewModel. We use a similar naming convention for this
scenario as we did with view location. Let’s take a look at ViewModelLocator.LocateForViewType:

public static Func<Type, object> LocateForViewType = viewType =>{


var typeName = viewType.FullName;

if(!typeName.EndsWith("View"))
typeName += "View";
var viewModelName = typeName.Replace("View", "ViewModel");
var key = viewModelName.Substring(viewModelName.LastIndexOf(".") + 1);

return IoC.GetInstance(null, key);


};

While with View location we change instances of “ViewModel” to “View”, with ViewModel location
we change “View” to “ViewModel.” The other interesting difference is in how we get the instance of
the ViewModel itself. Because your ViewModels may be registered by an interface or a concrete
class, we don’t pull them from the container by type. Instead we pull them by key, using just the
derived name, minus all the namespace stuff.

Other Things To Know


ViewModelLocator.LocateForViewType is actually never called directly by the framework. It’s called
internally by ViewModelLocator.LocateForView. LocateForView first checks your View instance’s
DataContext to see if you’ve previous cached or custom created your ViewModel. If the DataContext
is null, only then will it call into LocateForViewType. A final thing to note is that automatic
InitializeComponent calls are not supported by view first, by its nature.

Customization
You may not be happy with the way that LocateForViewType retrieves your ViewModel from the IoC
container by key. No problem. Simply replace the Func with your own implementation. As you can
see, it doesn’t really require that much code to map one thing to another.

Framework Usage
The ViewModelLocator is only used by the WP7 version of the framework. It’s used by the
FrameAdapter which insures that every time you navigate to a page, it is supplied with the correct
ViewModel. It could be easily adapted for use by the Silverlight Navigation Framework if desired.

ViewModelBinder
Basics
When we bind together your View and ViewModel, regardless of whether you use a ViewModel-First
or a View-First approach, the ViewModelBinder.Bind method is called. This method sets the
Action.Target of the View to the ViewModel and correspondingly sets the DataContext to the same
value.4 It also checks to see if your ViewModel implements IViewAware, and if so, passes the View to
your ViewModel. This allows for a more SupervisingController style design, if that fits your scenario
better. The final important thing the ViewModelBinder does is determine if it needs to create any
conventional property bindings or actions. To do this, it searches the UI for a list of element
candidates for bindings/actions and compares that against the properties and methods of your
ViewModel. When a match is found, it creates the binding or the action on your behalf.

Other Things To Know


On the WP7 platform, if the View you are binding is a PhoneApplicationPage, this service is
responsible for wiring up actions to the ApplicationBar’s Buttons and Menus. See the WP7 specific
docs for more information on that.

Customization
Should you decide that you don’t like the behavior of the ViewModelBinder (more details below), it
follows the same patterns as the above framework services. It has several Funcs you can replace with
your own implementations, such as Bind, BindActions and BindProperties. Probably the most
important aspect of customization though, is the ability to turn off the binder’s convention features.
To do this, set ViewModelBinder.ApplyConventionsByDefault to false. If you want to enable it on a
view-by-view basis, you can set the View.ApplyConventions attached property to true on your View.
This attached property works both ways. So, if you have conventions on by default, but need to turn
them off on a view-by-view basis, you just set this property to false.

Framework Usage
The ViewModelBinder is used in three places inside of Caliburn.Micro. The first place is inside the
implementation of the View.Model attached property. This property takes your ViewModel, locates a
view using the ViewLocator and then passes both of them along to the ViewModelBinder. After
binding is complete, the View is injected inside the element on which the property is defined. That’s
the ViewModel-First usage pattern. The second place that uses the ViewModelBinder is inside the
implementation of the Bind.Model attached property. This property takes a ViewModel and passes it
along with the element on which the property is defined to the ViewModelBinder. In other words,
this is View-First, since you have already instantiated the View inline in your Xaml and are then just
invoking the binding against a ViewModel. The final place that the ViewModelBinder is used is in the
WP7 version of the framework. Inside of the FrameAdapter, when a page is navigated to, the
ViewModelLocator is first used to obtain the ViewModel for that page. Then, the ViewModelBinder is
uses to connect the ViewModel to the page.

Element Location
Basics
Now that you understand the basic role of the ViewModelBinder and where it is used by the
framework, I want to dig into the details of how it applies conventions. As mentioned above, the
ViewModelBinder “searches the UI for a list of element candidates for bindings/actions and
compares that against the properties and methods of your ViewModel.” The first step in
understanding how this works is knowing how the framework determines which elements in your UI
may be candidates for conventions. It does this by using a func on the static ExtensionMethods class
called GetNamedElementsInScope.5 Basically this method does two things. First, it identifies a scope
to search for elements in. This means it walks the tree until it finds a suitable root node, such as a
Window, UserControl or element without a parent (indicating that we are inside a DataTemplate).
Once it defines the “outer” borders of the scope, it begins it’s second task: locating all elements in
that scope that have names. The search is careful to respect an “inner” scope boundary by not
traversing inside of child user controls. The elements that are returned by this function are then used
by the ViewModelBinder to apply conventions.

Other Things To Know


There are a few limitations to what the GetNamedElementsInScope method can accomplish out-of-
the-box. It can only search the visual tree, ContentControl.Content and ItemsControl.Items. In WPF,
it also searches HeaderContentControl.Header and HeaderedItemsControl.Header. What this means
is that things like ContextMenus, Tooltips or anything else that isn’t in the visual tree or one of these
special locations won’t get found when trying to apply conventions.

Customization
You may not encounter issues related to the above limitations of element location. But if you do, you
can easily replace the default implementation with your own. Here’s an interesting technique you
might choose to use: If the view is a UserControl or Window, instead of walking the tree for
elements, use some reflection to discover all private fields that inherit from FrameworkElement. We
know that when Xaml files are compiled, a private field is created for everything with an x:Name. Use
this to your advantage. You will have to fall back to the existing implementation for DataTemplate UI
though. I don’t provide this implementation out-of-the-box, because it is not guaranteed to succeed
in Silverlight. The reason is due to the fact that Silverlight doesn’t allow you to get the value of a
private field unless the calling code is the code that defines the field. However, if all of your views are
defined in a single assembly, you can easily make the modification I just described by creating your
new implementation in the same assembly as the views. Furthermore, if you have a multi-assembly
project, you could write a little bit of plumbing code that would allow the
GetNamedElementsInScope Func to find the assembly-specific implementation which could actually
perform the reflection.6

Framework Usage
I’ve already mentioned that element location occurs when the ViewModelBinder attempts to bind
properties or methods by convention. But, there is a second place that uses this functionality: the
Parser. Whenever you use Message.Attach and your action contains parameters, the message parser
has to find the elements that you are using as parameter inputs. It would seem that we could just do
a simple FindName, but FindName is case-sensitive. As a result, we have to use our custom
implementation which does a case-insensitive search. This ensures that the same semantics for
binding are used in both places.

Action Matching
Basics
The next thing the ViewModelBinder does after locating the elements for convention bindings is
inspect them for matches to methods on the ViewModel. It does this by using a bit of reflection to
get the public methods of the ViewModel. It then loops over them looking for a case-insensitive
name match with an element. If a match is found, and there aren’t any pre-existing
Interaction.Triggers on the element, an action is attached. The check for pre-existing triggers is used
to prevent the convention system from creating duplicate actions to what the developer may have
explicitly declared in the markup. To be on the safe side, if you have declared any triggers on the
matched element, it is skipped.

Other Things To Know


The conventional actions are created by setting the Message.Attach attached property on the
element. Let’s look at how that is built up:

var message = method.Name;


var parameters = method.GetParameters();

if(parameters.Length > 0)
{
message += "(";

foreach(var parameter in parameters)


{
var paramName = parameter.Name;
var specialValue = "$" + paramName.ToLower();

if(MessageBinder.SpecialValues.Contains(specialValue))
paramName = specialValue;
message += paramName + ",";
}

message = message.Remove(message.Length - 1, 1);


message += ")";
}

Log.Info("Added convention action for {0} as {1}.", method.Name, message);


Message.SetAttach(foundControl, message);

As you can see, we build a string representing the message. This string contains only the action part
of the message; no event is declared. You can also see that it loops through the parameters of the
method so that they are included in the action. If the parameter name is the same as a special
parameter value, we make sure to append the “$” to it so that it will be recognized correctly by the
Parser and later by the MessageBinder when the action is invoked.

When the Message.Attach property is set, the Parser immediately kicks in to convert the string
message into some sort of TriggerBase with an associated ActionMessage. Because we don’t declare
an event as part of the message, the Parser looks up the default Trigger for the type of element that
the message is being attached to. For example, if the message was being attached to a Button, then
we would get an EventTrigger with it’s Event set to Click. This information is configured through the
ConventionManager with reasonable defaults out-of-the-box. See the sections on
ConventionManager and ElementConventions below for more information on that. The
ElementConvention is used to create the Trigger and then the parser converts the action information
into an ActionMessage. The two are connected together and then added to the Interaction.Triggers
collection of the element.

Customization
ViewModelBinder.BindActions is a Func and thus can be entirely replaced if desired. Adding to or
changing the ElementConventions via the ConventionManager will also effect how actions are put
together. More on that below.

Framework Usage
BindActions is used exclusively by the ViewModelBinder.

Property Matching
Basics
Once action binding is complete, we move on to property binding. It follows a similar process by
looping through the named elements and looking for case-insensitive name matches on properties.
Once a match is found, we then get the ElementConventions from the ConventionManager so we
can determine just how databinding on that element should occur. The ElementConvention defines
an ApplyBinding Func that takes the view model type, property path, property info, element
instance, and the convention itself. This Func is responsible for creating the binding on the element
using all the contextual information provided. The neat thing is that we can have custom binding
behaviors for each element if we want. CM defines a basic implementation of ApplyBinding for most
elements, which lives on the ConventionManager. It’s called SetBinding and looks like this:

public static Func<Type, string, PropertyInfo, FrameworkElement, ElementConvention,


bool> SetBinding =
(viewModelType, path, property, element, convention) => {
var bindableProperty = convention.GetBindableProperty(element);
if(HasBinding(element, bindableProperty))
return false;

var binding = new Binding(path);

ApplyBindingMode(binding, property);
ApplyValueConverter(binding, bindableProperty, property);
ApplyStringFormat(binding, convention, property);
ApplyValidation(binding, viewModelType, property);
ApplyUpdateSourceTrigger(bindableProperty, element, binding);

BindingOperations.SetBinding(element, bindableProperty, binding);

return true;
};

The first thing this method does is get the dependency property that should be bound by calling
GetBindableProperty on the ElementConvention. Next we check to see if there is already a binding
set for that property. If there is, we don’t want to overwrite it. The developer is probably doing
something special here, so we return false indicating that a binding has not been added. Assuming no
binding exists, this method then basically delegates to other methods on the ConventionManager for
the details of binding application. Hopefully that part makes sense. Once the binding is fully
constructed we add it to the element and return true indicating that the convention was applied.

There’s another important aspect to property matching that I haven’t yet mentioned. We can match
on deep property paths by convention as well. So, let’s say that you have a Customer property on
your ViewModel that has a FirstName property you want to bind a Textbox to. Simply give the
TextBox an x:Name of “Customer_FirstName” The ViewModelBinder will do all the work to make
sure that that is a valid property and will pass the correct view model type, property info and
property path along to the ElementConvention’s ApplyBinding func.

Other Things To Know


I mentioned above that “CM defines a basic implementation of ApplyBinding for most elements.” It
also defines several custom implementations of the ApplyBinding Func for elements that are typically
associated with specific usage patterns or composition. For WPF and Silverlight, there are custom
binding behaviors for ItemsControl and Selector. In addition to binding the ItemsSource on an
ItemsControl, the ApplyBinding func also inspects the ItemTemplate, DisplayMemberPath and
ItemTemplateSelector (WPF) properties. If none of these are set, then the framework knows that
since you haven’t specified a renderer for the items, it should add one conventionally.7 So, we set the
ItemTemplate to a default DataTemplate. Here’s what it looks like:

<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro">
<ContentControl cal:View.Model="{Binding}"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch" />
</DataTemplate>

Since this template creates a ContentControl with a View.Model attached property, we create the
possibility of rich composition for ItemsControls. So, whatever the Item is, the View.Model attached
property allows us to invoke the ViewModel-First workflow: locate the view for the item, pass the
item and the view to the ViewModelBinder (which in turn sets it’s own conventions, possibly
invoking more composition) and then take the view and inject it into the ContentControl. Selectors
have the same behavior as ItemsControls, but with an additional convention around the
SelectedItem property. Let’s say that your Selector is called Items. We follow the above conventions
first by binding ItemsSource to Items and detecting whether or not we need to add a default
DataTemplate. Then, we check to see if the SelectedItem property has been bound. If not, we look
for three candidate properties on the ViewModel that could be bound to SelectedItem: ActiveItem,
SelectedItem and CurrentItem. If we find one of these, we add the binding. So, the pattern here is
that we first call ConventionManager.Singularize on the collection property’s name. In this case
“Items” becomes “Item” Then we call ConventionManager.DerivePotentialSelectionNames which
prepends “Active” “Selected” and “Current” to “Item” to make the three candidates above. Then, we
create a binding if we find one of these on the ViewModel. For WPF, we have a special ApplyBinding
behavior for the TabControl.8 It takes on all the conventions of Selector (setting it’s ContentTemplate
instead of ItemTemplate to the DefaultDataTemplate), plus an additional convention for the tab
header’s content. If the TabControl’s DisplayMemberPath is not set and the ViewModel implements
IHaveDisplayName, then we set it’s ItemTemplate to the DefaultHeaderTemplate, which looks like
this:

<DataTemplate
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<TextBlock Text="{Binding DisplayName, Mode=TwoWay}" />
</DataTemplate>

So, for a named WPF TabControl we can conventionally bind in the list of tabs (ItemsSource), the tab
item’s name (ItemTemplate), the content for each tab (ContentTemplate) and keep the selected tab
synchronized with the model (SelectedItem). That’s not bad for one line of Xaml like this:

<TabControl x:Name="Items" />

In addition to the special cases listed above, we have one more that is important: ContentControl. In
this case, we don’t supply a custom ApplyBinding Func, but we do supply a custom
GetBindableProperty Func. For ContentControl, when we go to determine which property to bind to,
we inspect the ContentTemplate and ContentTemplateSelector (WPF). If they are both null, you
haven’t specified a renderer for your model. Therefore, we assume that you want to use the
ViewModel-First workflow. We implement this by having the GetBindableProperty Func return the
View.Model attached property as the property to be bound. In all other cases ContentControl would
be bound on the Content property. By selecting the View.Model property in the absence of a
ContentTemplate, we enable rich composition.

I hope you will find that these special cases make sense when you think about them. As always, if you
don’t like them, you can change them…

Customization
As you might imagine, the BindProperties functionality is completely customizable by replacing the
Func on the ViewModelBinder. For example, if you like the idea of Action conventions but not
Property conventions, you could just replace this Func with one that doesn’t do anything. However,
it’s likely that you will want more fine grained control. Fortunately, nearly every aspect of the
ConventionManager or of a particular ElementConvention is customizable. More details about the
ConventionManager are below.
One of the common ways you will configure conventions is by adding new conventions to the
system. Most commonly this will be in adding the Silverlight toolkit controls or the WP7 toolkit
controls. Here’s an example of how you would set up an advanced convention for the WP7 Pivot
control which would make it work like the WPF TabControl:

ConventionManager.AddElementConvention<Pivot>(Pivot.ItemsSourceProperty,
"SelectedItem", "SelectionChanged").ApplyBinding =
(viewModelType, path, property, element, convention) => {
ConventionManager
.GetElementConvention(typeof(ItemsControl))
.ApplyBinding(viewModelType, path, property, element, convention);
ConventionManager
.ConfigureSelectedItem(element, Pivot.SelectedItemProperty,
viewModelType, path);
ConventionManager
.ApplyHeaderTemplate(element, Pivot.HeaderTemplateProperty,
viewModelType);
};

Pretty cool?

Framework Usage
BindProperties is used exclusively by the ViewModelBinder.

ConventionManager
If you’ve read this far, you know that the ConventionManager is leveraged heavily by the Action and
Property binding mechanisms. It is the gateway to fine-tuning the majority of the convention
behavior in the framework. What follows is a list of the replaceable Funcs and Properties which you
can use to customize the conventions of the framework:

Properties

 BooleanToVisibilityConverter – The default IValueConverter used for converting Boolean to


Visibility and back. Used by ApplyValueConverter.
 IncludeStaticProperties - Indicates whether or not static properties should be included during
convention name matching. False by default.
 DefaultItemTemplate – Used when an ItemsControl or ContentControl needs a
DataTemplate.
 DefaultHeaderTemplate – Used by ApplyHeaderTemplate when the TabControl needs a
header template.

Funcs

 Singularize – Turns a word from its plural form to its singular form. The default
implementation is really basic and just strips the trailing ‘s’.
 DerivePotentialSelectionNames – Given a base collection name, returns a list of possible
property names representing the selection. Uses Singularize.
 SetBinding – The default implementation of ApplyBinding used by ElementConventions
(more info below). Changing this will change how all conventional bindings are applied. Uses
the following Funcs internally:
o HasBinding - Determines whether a particular dependency property already has a
binding on the provided element. If a binding already exists, SetBinding is aborted.
o ApplyBindingMode - Applies the appropriate binding mode to the binding.
o ApplyValidation - Determines whether or not and what type of validation to enable
on the binding.
o ApplyValueConverter - Determines whether a value converter is is needed and
applies one to the binding. It only checks for BooleanToVisibility conversion by
default.
o ApplyStringFormat - Determines whether a custom string format is needed and
applies it to the binding. By default, if binding to a DateTime, uses the format
"{0:MM/dd/yyyy}".
o ApplyUpdateSourceTrigger - Determines whether a custom update source trigger
should be applied to the binding. For WPF, always sets to
UpdateSourceTrigger=PropertyChanged. For Silverlight, calls ApplySilverlightTriggers.

Methods

 AddElementConvention – Adds or replaces an ElementConvention.


 GetElementConvention – Gets the convention for a particular element type. If not found,
searches the type hierarchy for a match.
 ConfigureSelectedItem – Configures the SelectedItem convention on an element.
 ApplyHeaderTemplate – Applies the header template convention to an element.
 ApplySilverlightTriggers – For TextBox and PasswordBox, wires the appropriate events to
binding updates in order to simulate WPF’s UpdateSourceTrigger=PropertyChanged.

ElementConvention
ElementConventions can be added or replaced through ConventionManager.AddElementConvention.
But, it’s important to know what these conventions are and how they are used throughout the
framework. At the very bottom of this article is a code listing showing how all the elements are
configured out-of-the-box. Here are the Properties and Funcs of the ElementConvention class with
brief explanations:

Properties

 ElementType – The type of element to which the convention applies.


 ParameterProperty – When using Message.Attach to declare an action, if a parameter that
refers to an element is specified, but the property of that element is not, the
ElementConvention will be looked up and the ParameterProperty will be used. For example,
if we have this markup:

<TextBox x:Name="something" />


<Button cal:Message.Attach="MyMethod(something)" />
When the Button’s ActionMessage is created, we look up “something”, which is a TextBox. We get
the ElementConvention for TextBox which has its ParameterProperty set to “Text.” Therefore, we
create the parameter for MyMethod from something.Text.

Funcs

 GetBindableProperty – Gets the property for the element which should be used in
convention binding.
 CreateTrigger – When Message.Attach is used to declare an Action, and the specific event is
not specified, the ElementConvention will be looked up and the CreateTrigger Func will be
called to create the Interaction.Trigger. For example in the Xaml above, when the
ActionMessage is created for the Button, the Button’s ElementConvention will be looked up
and its CreateTrigger Func will be called. In this case, the ElementConvention returns an
EventTrigger configured to use the Click event.
 ApplyBinding – As described above, when conventional databinding occurs, the element we
are binding has its ElementConvention looked up and it’s ApplyBinding func is called. By
default this just passes through to ConventionManager.SetBinding. But certain elements (see
above…or below) customize this in order to enable more powerful composition scenarios.

Out-Of-The-Box Element Conventions


Following is the full code-listing showing how the built-in controls have their ElementConventions
configured out-of-the-box:

#if SILVERLIGHT
AddElementConvention<HyperlinkButton>(HyperlinkButton.ContentProperty, "DataContext",
"Click");
AddElementConvention<PasswordBox>(PasswordBox.PasswordProperty, "Password",
"PasswordChanged");
#else
AddElementConvention<PasswordBox>(PasswordBox.DataContextProperty, "DataContext",
"PasswordChanged");
AddElementConvention<Hyperlink>(Hyperlink.DataContextProperty, "DataContext", "Click");
AddElementConvention<RichTextBox>(RichTextBox.DataContextProperty, "DataContext",
"TextChanged");
AddElementConvention<Menu>(Menu.ItemsSourceProperty,"DataContext", "Click");
AddElementConvention<MenuItem>(MenuItem.ItemsSourceProperty, "DataContext", "Click");
AddElementConvention<Label>(Label.ContentProperty, "Content", "DataContextChanged");
AddElementConvention<Slider>(Slider.ValueProperty, "Value", "ValueChanged");
AddElementConvention<Expander>(Expander.IsExpandedProperty, "IsExpanded", "Expanded");
AddElementConvention<StatusBar>(StatusBar.ItemsSourceProperty, "DataContext", "Loaded");
AddElementConvention<ToolBar>(ToolBar.ItemsSourceProperty, "DataContext", "Loaded");
AddElementConvention<ToolBarTray>(ToolBarTray.VisibilityProperty, "DataContext", "Loaded");
AddElementConvention<TreeView>(TreeView.ItemsSourceProperty, "SelectedItem",
"SelectedItemChanged");
AddElementConvention<TabControl>(TabControl.ItemsSourceProperty, "ItemsSource",
"SelectionChanged")
.ApplyBinding = (viewModelType, path, property, element, convention) => {
if(!SetBinding(viewModelType, path, property, element, convention))
return;

var tabControl = (TabControl)element;


if(tabControl.ContentTemplate == null && tabControl.ContentTemplateSelector == null &&
property.PropertyType.IsGenericType) {
var itemType = property.PropertyType.GetGenericArguments().First();
if(!itemType.IsValueType && !typeof(string).IsAssignableFrom(itemType))
tabControl.ContentTemplate = DefaultItemTemplate;
}

ConfigureSelectedItem(element, Selector.SelectedItemProperty, viewModelType, path);

if(string.IsNullOrEmpty(tabControl.DisplayMemberPath))
ApplyHeaderTemplate(tabControl, TabControl.ItemTemplateProperty, viewModelType);
};
AddElementConvention<TabItem>(TabItem.ContentProperty, "DataContext", "DataContextChanged");
AddElementConvention<Window>(Window.DataContextProperty, "DataContext", "Loaded");
#endif
AddElementConvention<UserControl>(UserControl.VisibilityProperty, "DataContext", "Loaded");
AddElementConvention<Image>(Image.SourceProperty, "Source", "Loaded");
AddElementConvention<ToggleButton>(ToggleButton.IsCheckedProperty, "IsChecked", "Click");
AddElementConvention<ButtonBase>(ButtonBase.ContentProperty, "DataContext", "Click");
AddElementConvention<TextBox>(TextBox.TextProperty, "Text", "TextChanged");
AddElementConvention<TextBlock>(TextBlock.TextProperty, "Text", "DataContextChanged");
AddElementConvention<Selector>(Selector.ItemsSourceProperty, "SelectedItem",
"SelectionChanged")
.ApplyBinding = (viewModelType, path, property, element, convention) => {
if (!SetBinding(viewModelType, path, property, element, convention))
return;

ConfigureSelectedItem(element, Selector.SelectedItemProperty,viewModelType, path);


ConfigureItemsControl((ItemsControl)element, property);
};
AddElementConvention<ItemsControl>(ItemsControl.ItemsSourceProperty, "DataContext", "Loaded")
.ApplyBinding = (viewModelType, path, property, element, convention) => {
if (!SetBinding(viewModelType, path, property, element, convention))
return;

ConfigureItemsControl((ItemsControl)element, property);
};
AddElementConvention<ContentControl>(ContentControl.ContentProperty, "DataContext",
"Loaded").GetBindableProperty =
delegate(DependencyObject foundControl) {
var element = (ContentControl)foundControl;
#if SILVERLIGHT
return element.ContentTemplate == null && !(element.Content is DependencyObject)
? View.ModelProperty
: ContentControl.ContentProperty;
#else
return element.ContentTemplate == null && element.ContentTemplateSelector == null &&
!(element.Content is DependencyObject)
? View.ModelProperty
: ContentControl.ContentProperty;
#endif
};
AddElementConvention<Shape>(Shape.VisibilityProperty, "DataContext", "MouseLeftButtonUp");
AddElementConvention<FrameworkElement>(FrameworkElement.VisibilityProperty, "DataContext",
"Loaded");

Footnotes

1. The WindowManager uses the ViewLocator under the covers. It inspects types to see if they
are UserControl or Window/ChildWindow. If they are not, it automatically creates a parent
Window/ChildWindow. So, you can choose to create your dialog views either as a
UserControl or Window/ChildWindow in this particular scenario and the framework will take
care of the rest. I typically make views UserControls when I can because that makes them a
bit more reusable.
2. The bootstrapper is responsible for making sure that your application’s assembly is added to
the AssemblySource, but you can add any additional assemblies by overriding the
Bootstrapper’s SelectAssemblies method and returning the full list. You can also add
additional assemblies to this collection at any time during application execution. So, if you
are dynamically downloading modules that contain more views, you can handle that scenario
pretty easily.
3. This pattern is borrowed from Javascript and I felt it generally made extensibility simpler for
the most common use cases.
4. Recall that in Caliburn.Micro DataContext has the purpose of specifying to what instance
databinding expressions are resolved and Action.Target specifies the instance that handles
an Action. Thus, DataContext and Action.Target are allowed to vary independently of one
another. By default, whenever the Action.Target is set, the DataContext is set to the same
value though. To change this you can set DataContext explicitly to a different value or more
commonly, you can use the Action.TargetWithoutContext attached property to set only the
Action.Target without affecting the DataContext.
5. GetNamedElementsInScope used to be an extension method. However, it became apparent
that developers wanted to customize the implementation. So, I made it into a Func. For lack
of a better place to put it, it still lives on the ExtensionMethods class.
6. Well, I assume this would work. I haven’t actually tried it though.
7. If your item is a ValueType or a String we don’t generate a default DataTemplate. We assume
that you want to use the default ToString rendering that the platform provides.
8. We don’t have this convention in Silverlight because A. TabControl is not part of the core
framework and B. Silverlight’s TabControl is broken for databinding and has been for two
versions of the framework without a fix. Please vote this issue up
http://silverlight.codeplex.com/workitem/3604 It was reported about a year and a half ago
and is not yet fixed.
Recipes

SimpleContainer
Caliburn.Micro is best used with an Inversion of Control (IoC) Container. Because many developers
have a preference for a particular container, such a component is not included out-of-the-box with
CM. Should you find yourself in a situation where you are building a small application or something
for WP7 where you cannot or do not want to use a full featured IoC container, the following code
should provide you with a solution.

Features

 Singleton Registration
 PerRequest (Transient) Registration
 Instance Registration
 Registration of Arbitrary Handlers
 Get a single instance by Type and/or key.
 Get all instances of a particular type.
 Automatic Func<T> factory creation.
 Automatic greedy constructor injection.
 Constructor injection of IEnumerable<TService>
 Overridable instance activation.

Implementation

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

public class SimpleContainer


{
readonly List<ContainerEntry> entries = new List<ContainerEntry>();

public void RegisterInstance(Type service, string key, object implementation)


{
RegisterHandler(service, key, () => implementation);
}

public void RegisterPerRequest(Type service, string key, Type implementation)


{
RegisterHandler(service, key, () => BuildInstance(implementation));
}

public void RegisterSingleton(Type service, string key, Type implementation)


{
object singleton = null;
RegisterHandler(service, key, () => singleton ?? (singleton =
BuildInstance(implementation)));
}

public void RegisterHandler(Type service, string key, Func<object> handler)


{
GetOrCreateEntry(service, key).Add(handler);
}

public object GetInstance(Type service, string key)


{
var entry = GetEntry(service, key);
if(entry != null)
return entry.Single()();
if(typeof(Delegate).IsAssignableFrom(service))
{
var typeToCreate = service.GetGenericArguments()[0];
var factoryFactoryType = typeof(FactoryFactory<>).MakeGenericType(typeToCreate);
var factoryFactoryHost = Activator.CreateInstance(factoryFactoryType);
var factoryFactoryMethod = factoryFactoryType.GetMethod("Create");
return factoryFactoryMethod.Invoke(factoryFactoryHost, new object[] { this });
}
else if(typeof(IEnumerable).IsAssignableFrom(service))
{
var listType = service.GetGenericArguments()[0];
var instances = GetAllInstances(listType).ToList();
var array = Array.CreateInstance(listType, instances.Count);

for(var i = 0; i < array.Length; i++)


{
array.SetValue(instances[i], i);
}

return array;
}

return null;
}

public IEnumerable<object> GetAllInstances(Type service)


{
var entry = GetEntry(service, null);
return entry != null ? entry.Select(x => x()) : new object[0];
}

public void BuildUp(object instance)


{
var injectables = from property in instance.GetType().GetProperties()
where property.CanRead && property.CanWrite &&
property.PropertyType.IsInterface
select property;

injectables.Apply(x =>{
var injection = GetAllInstances(x.PropertyType);
if(injection.Any())
x.SetValue(instance, injection.First(), null);
});
}

ContainerEntry GetOrCreateEntry(Type service, string key)


{
var entry = GetEntry(service, key);
if (entry == null)
{
entry = new ContainerEntry { Service = service, Key = key };
entries.Add(entry);
}

return entry;
}

ContainerEntry GetEntry(Type service, string key)


{
return service == null
? entries.Where(x => x.Key == key).FirstOrDefault()
: entries.Where(x => x.Service == service && x.Key == key).FirstOrDefault();
}

protected object BuildInstance(Type type)


{
var args = DetermineConstructorArgs(type);
return ActivateInstance(type, args);
}

protected virtual object ActivateInstance(Type type, object[] args)


{
return args.Length > 0 ? Activator.CreateInstance(type, args) :
Activator.CreateInstance(type);
}

object[] DetermineConstructorArgs(Type implementation)


{
var args = new List<object>();
var constructor = SelectEligibleConstructor(implementation);

if (constructor != null)
args.AddRange(constructor.GetParameters().Select(info =>
GetInstance(info.ParameterType, null)));

return args.ToArray();
}

static ConstructorInfo SelectEligibleConstructor(Type type)


{
return (from c in type.GetConstructors()
orderby c.GetParameters().Length descending
select c).FirstOrDefault();
}

class ContainerEntry : List<Func<object>>


{
public string Key;
public Type Service;
}

class FactoryFactory<T>
{
public Func<T> Create(SimpleContainer container)
{
return () => (T)container.GetInstance(typeof(T), null);
}
}
}
LoadCatalog Result
Contributed by janoveh

The following is a simple IResult implementation for using MEF's DeploymentCatalog to dynamically
download and plug in xaps. In order for it to work properly, you must make sure to add the
AggregateCatalog as an exported value in the container.

Implementation

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.ReflectionModel;
using System.Linq;

public class LoadCatalog : IResult


{
static readonly Dictionary<string, DeploymentCatalog> Catalogs = new
Dictionary<string, DeploymentCatalog>();
readonly string uri;

[Import]
public AggregateCatalog Catalog { get; set; }

public LoadCatalog(string relativeUri)


{
uri = relativeUri;
}

public void Execute(ActionExecutionContext context)


{
DeploymentCatalog catalog;

if(Catalogs.TryGetValue(uri, out catalog))


Completed(this, new ResultCompletionEventArgs());
else
{
catalog = new DeploymentCatalog(uri);
catalog.DownloadCompleted += (s, e) =>{
if(e.Error == null)
{
Catalogs[uri] = catalog;
Catalog.Catalogs.Add(catalog);
catalog.Parts
.Select(part =>
ReflectionModelServices.GetPartType(part).Value.Assembly)
.Where(assembly =>
!AssemblySource.Instance.Contains(assembly))
.Apply(x => AssemblySource.Instance.Add(x));
}

Completed(this, new ResultCompletionEventArgs {


Error = e.Error,
WasCancelled = false
});
};

catalog.DownloadAsync();
}
}

public event EventHandler<ResultCompletionEventArgs> Completed =


delegate { };
}

Usage

public IEnumerable<IResult> LoadCatalogs()


{
yield return new LoadCatalog("TestCatalog1.xap");
yield return new LoadCatalog("TestCatalog2.xap");
yield return new LoadCatalog("TestCatalog3.xap");
yield return new LoadCatalog("TestCatalog4.xap");
}

Much thanks to codeplex user janoveh on whose work this recipe was based.
Action Filters
Contributed by Marco Amendola

One of the features missing in Caliburn.Micro is filters, a set of action decorations aimed to provide
additional behaviors to a particular action. Filters bring two major advantages:

 They help to keep View Model free from noisy code that is unrelated to its main purpose.
This greatly simplifies unit testing.
 They allow the developer to share the implementation of cross-cutting concerns between
different View Models by moving it into infrastructure components.

Download the Sample Solution

Design
Filters falls into two main categories, depending on the mechanism used to interact with the target
action: IExecutionWrapper and IContextAware. The common IFilter interface is little more than a
marker and just defines a Priority property used to guide the filter application order:

public interface IFilter


{
int Priority { get; }
}

IExecutionWrapper
Most filter frameworks are built around AOP concepts and work through the interception of action
execution. Doing this allows you to add operations before and after the action execution itself or
something more complex like dispatching the action in another thread. The coroutine infrastructure
already has this capability, so a filter willing to intercept an action can simply wrap the original
execution into a “wrapping” IResult:

public interface IExecutionWrapper : IFilter


{
IResult Wrap(IResult inner);
}

To enable filter hooking, replace the core invocation method of ActionMessage:

//in bootstrapper code


...
FilterFramework.Configure();
...

public static class FilterFramework


{
public static void Configure()
{
...
ActionMessage.InvokeAction = InvokeAction;
}
...
public static void InvokeAction(ActionExecutionContext context)
{
var values = MessageBinder.DetermineParameters(context,
context.Method.GetParameters());
var result =
Coroutine.CreateParentEnumerator(ExecuteActionWithParameters(values).GetEnu
merator());

var wrappers =
FilterManager.GetFiltersFor(context).OfType<IExecutionWrapper>();
var pipeline = result.WrapWith(wrappers);

//if pipeline has error, action execution should throw!


pipeline.Completed += (o, e) => {
Execute.OnUIThread(() => {
if(e.Error != null) {
throw new Exception(
string.Format("An error occurred while executing
{0}.", context.Message),
e.Error
);
}
});
};

pipeline.Execute(context);
}
...
}

Every action is actually executed within an ExecuteActionResult (code omitted here) that deals with
simple actions as well as coroutines. It does this by conforming all of them to a common IResult
interface. This “core” IResult is afterwards wrapped over and over by each filter attached to the
action and finally executed.

Let’s have a look at FilterManager:

public static class FilterManager {


public static Func<ActionExecutionContext, IEnumerable<IFilter>>
GetFiltersFor = context => {
//TODO: apply caching?
return context.Target.GetType().GetAttributes<IFilter>(true)
.Union(context.Method.GetAttributes<IFilter>(true))
.OrderBy(x => x.Priority);
};

public static IResult WrapWith(this IResult inner,


IEnumerable<IExecutionWrapper> wrappers) {
return wrappers.Aggregate(inner, (current, wrapper) =>
wrapper.Wrap(current));
}
}

Note that the GetFiltersFor method is replaceable to allow for another filter lookup strategy (for
example, based on convention or external configuration instead of attributes).

IContextAware
While IExecutionWrapper-s do their work during the action execution, the other filter category,
IContextAware, operates when an action is not executing, providing preconditions for execution (the
related predicate is held by ActionExecutionContext) or observing the ViewModel to force an update
of the action availability:

public interface IContextAware : IFilter, IDisposable


{
void MakeAwareOf(ActionExecutionContext context);
}

Filters implementing this interface are given a chance, during ActionMessage initialization, to hook
the execution context. To achieve this, the framework hooks into ActionMessage.PrepareContext:

public static class FilterFramework {


public static void Configure() {
var oldPrepareContext = ActionMessage.PrepareContext;
ActionMessage.PrepareContext = context => {
oldPrepareContext(context);
PrepareContext(context);
};

ActionMessage.InvokeAction = InvokeAction;
}

public static void PrepareContext(ActionExecutionContext context) {


var contextAwareFilters = FilterManager.GetFiltersFor(context)
.OfType<IContextAware>()
.ToArray();

contextAwareFilters.Apply(x => x.MakeAwareOf(context));


context.Message.Detaching += (o, e) => {
contextAwareFilters.Apply(x => x.Dispose()); };
}
}

Implementing Filters
To simplify filters construction, use the base class for IExecutionWrapper which includes all the
boilerplate code and provides the standard customization points:

public abstract class ExecutionWrapperBase : Attribute, IExecutionWrapper,


IResult {
IResult inner;
event EventHandler<ResultCompletionEventArgs> CompletedEvent = delegate
{ };

public int Priority { get; set; }

IResult IExecutionWrapper.Wrap(IResult inner) {


this.inner = inner;
return this;
}

void IResult.Execute(ActionExecutionContext context) {


if(!CanExecute(context)) {
CompletedEvent(this, new ResultCompletionEventArgs {
WasCancelled = true });
return;
}

try {
EventHandler<ResultCompletionEventArgs> onCompletion = null;
onCompletion = (o, e) => {
inner.Completed -= onCompletion;
AfterExecute(context);
FinalizeExecution(context, e.WasCancelled, e.Error);
};
inner.Completed += onCompletion;

BeforeExecute(context);
Execute(inner, context);
}
catch(Exception ex) {
FinalizeExecution(context, false, ex);
}
}

event EventHandler<ResultCompletionEventArgs> IResult.Completed {


add { CompletedEvent += value; }
remove { CompletedEvent -= value; }
}

protected virtual bool CanExecute(ActionExecutionContext context) {


return true;
}

protected virtual void BeforeExecute(ActionExecutionContext context) {}

protected virtual void AfterExecute(ActionExecutionContext context) {}

protected virtual void Execute(IResult inner, ActionExecutionContext


context) {
inner.Execute(context);
}

protected virtual bool HandleException(ActionExecutionContext context,


Exception ex) {
return false;
}

void FinalizeExecution(ActionExecutionContext context, bool


wasCancelled, Exception ex) {
if(ex != null && HandleException(context, ex))
ex = null;

CompletedEvent(this, new ResultCompletionEventArgs { WasCancelled =


wasCancelled, Error = ex });
}
}

Sample Filters and Usage


/// <summary>
/// Provides asynchronous execution of the action in a background thread
/// </summary>
public class AsyncAttribute : ExecutionWrapperBase
{
protected override void Execute(IResult inner, ActionExecutionContext
context)
{
ThreadPool.QueueUserWorkItem(state =>
{
inner.Execute(context);
});
}
}
//usage:
//[Async]
//public void MyAction() { ... }

/// <summary>
/// Allows to specify a "rescue" method to handle exception occurred during
execution
/// </summary>
public class RescueAttribute : ExecutionWrapperBase
{

public RescueAttribute() : this("Rescue") { }


public RescueAttribute(string methodName)
{
MethodName = methodName;
}

public string MethodName { get; private set; }

protected override bool HandleException(ActionExecutionContext context,


Exception ex)
{
var method = context.Target.GetType().GetMethod(MethodName, new[] {
typeof(Exception) });
if (method == null) return false;

try
{
var result = method.Invoke(context.Target, new object[] { ex
});
if (result is bool)
return (bool)result;
else
return true;
}
catch
{
return false;
}
}
}
//usage:
//[Rescue]
//public void ThrowingAction()
//{
// throw new NotImplementedException();
//}
//public bool Rescue(Exception ex)
//{
// MessageBox.Show(ex.ToString());
// return true;
//}

/// <summary>
/// Sets "IsBusy" property to true (on models implementing ICanBeBusy)
during the execution
/// </summary>
public class SetBusyAttribute : ExecutionWrapperBase
{
protected override void BeforeExecute(ActionExecutionContext context)
{
SetBusy(context.Target as ICanBeBusy, true);
}
protected override void AfterExecute(ActionExecutionContext context)
{
SetBusy(context.Target as ICanBeBusy, false);
}
protected override bool HandleException(ActionExecutionContext context,
Exception ex)
{
SetBusy(context.Target as ICanBeBusy, false);
return false;
}

private void SetBusy(ICanBeBusy model, bool isBusy)


{
if (model != null)
model.IsBusy = isBusy;
}

}
//usage:
//[SetBusy]
//[Async] //prevents UI freezing, thus allowing busy state representation
//public void VeryLongAction() { ... }

/// <summary>
/// Updates the availability of the action (thus updating the UI)
/// </summary>
public class DependenciesAttribute : Attribute, IContextAware
{
ActionExecutionContext _context;
INotifyPropertyChanged _inpc;

public DependenciesAttribute(params string[] propertyNames)


{
PropertyNames = propertyNames ?? new string[] { };
}

public string[] PropertyNames { get; private set; }


public int Priority { get; set; }

public void MakeAwareOf(ActionExecutionContext context)


{
_context = context;
_inpc = context.Target as INotifyPropertyChanged;
if (_inpc != null)
_inpc.PropertyChanged += inpc_PropertyChanged;
}

public void Dispose()


{
if (_inpc != null)
_inpc.PropertyChanged -= inpc_PropertyChanged;
_inpc = null;
}

void inpc_PropertyChanged(object sender, PropertyChangedEventArgs e)


{
if (PropertyNames.Contains(e.PropertyName))
{
Execute.OnUIThread(() =>
{
_context.Message.UpdateAvailability();
});
}
}
}
//usage:
//[Dependencies("MyProperty", "MyOtherProperty")]
//public void DoAction() { ... }
//public bool CanDoAction() { return MyProperty > 0 && MyOtherProperty < 1;
}

/// <summary>
/// Allows to specify a guard method or property with an arbitrary name
/// </summary>
public class PreviewAttribute : Attribute, IContextAware
{
public PreviewAttribute(string methodName)
{
MethodName = methodName;
}

public string MethodName { get; private set; }


public int Priority { get; set; }

public void MakeAwareOf(ActionExecutionContext context)


{
var targetType = context.Target.GetType();
var guard = targetType.GetMethod(MethodName);
if (guard== null)
guard = targetType.GetMethod("get_" + MethodName);

if (guard == null) return;

var oldCanExecute = context.CanExecute;


context.CanExecute = () =>
{
if (oldCanExecute != null && !oldCanExecute()) return false;

return (bool)guard.Invoke(
context.Target,
MessageBinder.DetermineParameters(context,
guard.GetParameters())
);
};
}

public void Dispose() { }

}
//usage:
//[Preview("IsMyActionAvailable")]
//public void MyAction(int value) { ... }
//public bool IsMyActionAvailable(int value) { ... }

Download the Sample Solution

Last edited Nov 15 2010 at 10:33 PM by EisenbergEffect, version 15

Comments

ROBOlav Dec 22 2010 at 1:50 PM


Thank you for this guide!

I've used this with the Async-attribute, and it worked great.

However, lately I've started using the IWindowManager.Show() -function to open Screens as
separate windows. Doing this caused a run time NullReferenceException in the newly added
FilterManager. Removing the actions from my XAML-file preveted this, but then I don't get much
work done :)

Have any of you experienced the same, and if so, have a quick fix?
Silverlight Navigation
Contributed by Greg Gum

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

Download the Sample

Você também pode gostar