.Net, Azure and occasionally gamedev

Spotlight: Caliburn.Micro

2017/07/02

Short description from their website:

Caliburn.Micro is a small, yet powerful framework, designed for building applications across all XAML platforms. With strong support for MVVM and other proven UI patterns, Caliburn.Micro will enable you to build your solution quickly, without the need to sacrifice code quality or testability.

I'd like to feature the framework because I have been using it for years for various WPF as well as Windowsphone applications and it has saved me probably hundreds of hours.

Like any other MVVM framework it makes working with XAML a lot easier. From the integrated IoC container, auto-bindings for view-viewmodels to the platform-independent abstractions (navigation, storage, view activations and deactivations).

But my favorite feature is the convention-based bindings which works based on the control names. It probably saved me the most work and is the most fun to work with.

Examples:

Button with x:Name="Start" automatically binds to void Start() in the attached viewmodel (which itself is automatically resolved by name as well).

Additionally the button can also bind to bool CanStart which will determine the enabled state of the button.

Similar conventions exist for various common controls:

And each control can bind to "Can<ControlName>" to bind its enabled state.

If the conventions doesn't suit your usecase (most will) it is possible to override or extend the conventions with:

ConventionManager
    .AddElementConvention<ButtonBase>(
        ButtonBase.ContentProperty,
        "DataContext",
        "Click");

(which hooks up the default button click event to its named function.)

Conventions are global and apply to all controls, but it also allows easy extensions and changes on a per-case basis using the Message.Attach property.

The Message.Attach property is used for event bindings per control:

<Button Content="Save" 
        cal:Message.Attach="[Event Click] = [Action Save('save')]"/>
<Button Content="SaveAll"
        cal:Message.Attach="[Click]=[Save('save-all')]"/>
<Button Content="Save"
        cal:Message.Attach="Click=Save"/>

It allows to assign specific events to single controls without having to override the generic conventions.

Apart from providing hardcoded strings to provide distinct values to a function it can also provide generic arguments.

By default, Caliburn.Micro allows a set of existing variables. These are all represented in the format "$name":

Additionally it is possible to define custom variables.

Example to forward the key that was pressed from events such as KeyDown and KeyUp.

MessageBinder.SpecialValues.Add("$pressedkey", context =>
{
    var keyArgs = context.EventArgs as KeyEventArgs;
    if (keyArgs != null)
        return keyArgs.Key;
    return null;
});

Generally you do not want specific keys forwarded to a ViewModel as the whole point of a ViewModel is to be completely unrelated to the View (and platform) - e.g. the same ViewModel could be used for Windows and Windowsphone (which obviously doesn't have key events); but it shows the ease of extensibility.

All these conventions in combination make it super easy to write fully decouple view/viewmodels and make testing easier.

I recently began implementing a new multiplatform app using Caliburn.Micro and Xamarin.Forms, unfortunately Xamarin doesn't support x:Name access at runtime (which means Caliburn's automatic Name conventions are unavailable).

However all the other features are still available and with the latest Xamarin.Forms I was able to achieve almost 100% code sharing between Android, iOS and UWP using Caliburn.Micro. However that will be part of the next post.

tagged as Caliburn.Micro and MVVM