Tag Archives: Caliburn Micro Tutorial

Caliburn Micro Part 7: Basic Dependency Injection With WinRT and Phone 8.1

This tutorial is mostly targeted at Windows Phone development but most of it will carry over to Windows 8 store apps and to a certain extent, desktop apps.

Caliburn makes available the WinRTContainer which can be used to register dependencies. The different ways they can be registered are listed below.

RegisterInstance – The registered instance will be returned each request
RegisterPerRequest – A new instance of the specified type will be returned each time
RegisterSingleton – Similar to register instance but singletons are only constructed when the first request is made
Handler – Provides a way of adding logic for context sensitive implementations
AllTypesOf – Registers all specified types in an assembly as singletons

Example

Say we had a small application that allowed the adding of users. The viewmodel takes a single parameter in its constructor which is an interface to a database.

public class AddUsersViewModel
{
    public AddUsersViewModel( IDataStore dataStore )
    {
    }
}

In this instance we only want one instance of the AddUsersViewModel to exist at a time so we register it as a singleton with the container. The code below is from App.xaml.cs.

protected override void Configure()
{
    container = new WinRTContainer();

    container.RegisterWinRTServices();

    container.RegisterSingleton( typeof( AddUsersViewModel ), null, typeof( AddUsersViewModel ) );
}

Now given that our viewmodel takes arguments in its constructor, we want Caliburn to inject those for us when it creates the singleton instance of it. Note that _dataStore is an instance of IDataStore that we have created.

protected override void Configure()
{
    container = new WinRTContainer();

    container.RegisterWinRTServices();

    container.RegisterInstance( typeof( IDataStore ), null, _dataStore );

    container.RegisterSingleton( typeof( AddUsersViewModel ), null, typeof( AddUsersViewModel ) );
}

With the above code caliburn will automatically inject our instance of IDataStore into the constructor of AddUsersViewModel when it creates an instance of it. This is especially useful when you are using the navigation service in Windows Phone 8.1 apps.

Caliburn Micro Part 6: The Window Manager

Caliburn usually takes care of creating the main window for use, but what if we wanted to dynamically create a popup window our self? To do this we can use the provided WindowManager class.

Creating a popup window

IWindowManager manager = new WindowManager();
manager.ShowDialog( myViewModel, null, null );

Simple put the code above creates a new modal window which shows the view associated with the supplied view model (myViewModel).

Customising the window

We can do this by passing an array of settings to the ShowDialog function, to do this we use an ExpandoObject which is interpreted at runtime ( this means that you won’t get any intelli sense or error checking). You can add any property to the ExpandoObject that would be settable on a wpf window.

dynamic settings = new ExpandoObject();
settings.WindowStartupLocation = WindowStartupLocation.CenterOwner;
settings.ResizeMode = ResizeMode.NoResize;
settings.MinWidth = 450;
settings.Title = "My New Window";
settings.Icon = new BitmapImage( new Uri( "pack://application:,,,/MyApplication;component/Assets/myicon.ico" ) );

IWindowManager manager = new WindowManager();
manager.ShowDialog( myViewModel, null, settings );

Notes

The new window does not have to be modal, there are other functions on the window manager for showing a non modal window and a popup.

That’s it for this tutorial join us next time for a look at using Dependency Injection.

Caliburn Micro Part 5: WinRT and Phone 8.1

Welcome to the next part of this blog series on Caliburn Micro, in the previous part we saw how the Event Aggregator can be used to pass messages between different View Models. In this next part we will see how Caliburn Micro can be used in a Windows RT or Windows Phone 8.1 application.

It should be noted that Visual Studio 13 or higher and Windows 8.1 are required to develop Windows Phone 8.1 and Window Store 8.1 apps.

In the following examples a Windows Phone 8.1 one app is used but the procedure should be similar if not the same for Windows Store apps.

Step 1: Getting Started

First off create a new Windows Phone 8.1 or a Windows Store project and grab the Caliburn Micro nugget package from the Library Package Manager in Visual Studio.

Step 2: Adding Caliburn Micro Support

If you have used Caliburn Micro in other applications you will probably have created a bootstrapper to set up all the Caliburn Micro related stuff and start your application. Windows Phone 8.1 and Windows Store apps work in a slightly different way so a bootstrapper is not required. If you look in the solution explorer there should be a file called App.xaml, we will start by editing this.

Edit the file so that it looks like the code below, note that x:Class is unique to the name of your application and so should be left as it is.

<caliburn:CaliburnApplication
    x:Class="YourAppName.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:caliburn="using:Caliburn.Micro">

</caliburn:CaliburnApplication>

Next we need to edit App.xaml.cs to add code that will setup and start our application. Change App.xaml.cs so that it looks as below.

public sealed partial class App : CaliburnApplication
{
    private WinRTContainer container;

    public App()
    {
        InitializeComponent();
    }

    protected override void Configure()
    {
        container = new WinRTContainer();

        container.RegisterWinRTServices();

        container.PerRequest<ShellViewModel>();
    }

    protected override void PrepareViewFirst(Frame rootFrame)
    {
        container.RegisterNavigationService(rootFrame);
    }

    protected override void OnLaunched(LaunchActivatedEventArgs args)
    {
        DisplayRootViewFor<ShellViewModel>();
    }

    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);
    }
}

Things to take note of here are that you need to add a new entry for every View Model that you create, so in the Configure function you would add a new container.PerRequest with the name of your View Model. Also of note is the DisplayRootViewFor in the OnLaunched function, this needs to be changed to whichever View Model you want displayed when your app starts up.

Step 3: Develop Your Application

That’s about all you need to know about setting up the application, if you need help on how the rest of Caliburn Micro works please see the previous blog posts in this series.

That’s it for this tutorial join us next time for a look at using the Window Manager.

Caliburn Micro Part 4: The Event Aggregator

Welcome to the fourth part of this tutorial on the basics of Caliburn Micro, in the previous part we saw how actions worked. In this next part we will go through the basics of the Event Aggregator.

Description

The event aggregator is a service that allows View Models to communicate with each other using messages. A View Model can subscribe to as many messages as it wants and will be notified each time one of these messages is published by the same or a different View Model.

Step 1: New Components

In this example we will build a small application that changes the text in one View Model when buttons in another are pressed, we will build upon the application that we built in the past tutorials. In order to do this we will need two additional View Models, so lets start by creating the one containing the buttons. Create a new class, call it ButtonsViewModel and add code so that it looks as below.

public class ButtonsViewModel
{
    public void Button1()
    {
    }

    public void Button2()
    {
    }

    public void Button3()
    {
    }
}

Lets also make a View to go along with it as well called ButtonsView.

<UserControl x:Class="CaliburnMicroExample.ButtonsView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" >
    <StackPanel Orientation="Vertical">
        <Button x:Name="Button1" Content="Button 1" />
        <Button x:Name="Button2" Content="Button 2" />
        <Button x:Name="Button3" Content="Button 2" />
    </StackPanel>
</UserControl>

Now that we have the buttons set up lets create the View Model that will display some text to the user. Create a new View Model and call it TextViewModel.

public class TextViewModel : PropertyChangedBase
{
    private string _text;

    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            NotifyOfPropertyChange(() => Text);
        }
    }

    public TextViewModel()
    {
        Text = "No button pressed";
    }
}

Also create TextView to go along with it.

<UserControl x:Class="CaliburnMicroExample.TextView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" >
    <Grid>
        <TextBlock x:Name="Text" VerticalAlignment="Center" />
    </Grid>
</UserControl>

Finally we need to update ShellViewModel and ShellView so that they contain the new View / View Model combos we have made. Start by changing ShellViewModel as below.

public class ShellViewModel
{
    public ButtonsViewModel ButtonsVM
    {
        get;
        set;
    }

    public TextViewModel TextVM
    {
        get;
        set;
    }

    public ShellViewModel()
    {
        ButtonsVM = new ButtonsViewModel();
        TextVM = new TextViewModel();
    }
}

Change ShellView as shown below.

<UserControl x:Class="CaliburnMicroExample.ShellView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:cal="http://www.caliburnproject.org"
             xmlns:local="clr-namespace:CaliburnMicroExample"
             mc:Ignorable="d" >
    <StackPanel Orientation="Horizontal">
        <local:ButtonsView cal:Bind.Model="{Binding ButtonsVM}" />
        <local:TextView cal:Bind.Model="{Binding TextVM}" />
    </StackPanel>
</UserControl>

If you run the program now you should see a small app with 3 buttons down the left hand side and some text displayed to the right.

Step 2: Implementing IHandle

We are going to be publishing messages from the ButtonsViewModel that will be picked up in the TextViewModel. To do this we need to make TextViewModel aware of the message that it is going to receive. Caliburn offers the IHandle interface which lets a View Model listen for a message of its choice, start by creating a new class and calling it ChangeTextMessage. This will act as the message that we send between our two View Models.

public class ChangeTextMessage
{
    public string Text
    {
        get;
        private set;
    }

    public ChangeTextMessage(string text)
    {
        Text = text;
    }
}

Now lets extend TextViewModel to support the IHandle interface, as you can see below once we received the message we set the text that is displayed to the text received in the message.

public class TextViewModel : PropertyChangedBase, IHandle<ChangeTextMessage>
{
    private string _text;

    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            NotifyOfPropertyChange(() => Text);
        }
    }

    public TextViewModel()
    {
        Text = "No buttons pressed";
    }

    public void Handle(ChangeTextMessage message)
    {
        Text = message.Text;
    }
}

Step 3: Event Aggregator

Now that we have added the ability for TextViewModel to handle a message we need to start adding the capability for it to receive them and for ButtonsViewModel to send them. To do this we need to pass an instance of EventAggregator to each of our interested View Models, start by creating a new instance of it in the ShellViewModel constructor and passing it to the other two View Models.

public ShellViewModel()
{
    IEventAggregator events = new EventAggregator();

    ButtonsVM = new ButtonsViewModel(events);
    TextVM = new TextViewModel(events);
}

In TextViewModel save the passed in instance to a local variable.

private IEventAggregator _events;

public TextViewModel(IEventAggregator events)
{
    _events = events;

    Text = "No buttons pressed";
}

Do the same in ButtonsViewModel as well.

private IEventAggregator _events;

public ButtonsViewModel(IEventAggregator events)
{
    _events = events;
}

Step 4: Subscribe

The next step is to subscribe TextViewModel to the Caliburn message pipe, this is as simple as calling subscribe on the EventAggregator object that we passed in.

public TextViewModel(IEventAggregator events)
{
    _events = events;

    _events.Subscribe(this);

    Text = "No buttons pressed";
}

Step 5: Publish

The final thing we need to do is send a message every time a button is pressed in ButtonsViewModel, extend your code as shown below.

public void Button1()
{
    _events.PublishOnUIThread(new ChangeTextMessage("Button 1 Pressed"));
}

public void Button2()
{
    _events.PublishOnUIThread(new ChangeTextMessage("Button 2 Pressed"));
}

public void Button3()
{
    _events.PublishOnUIThread(new ChangeTextMessage("Button 3 Pressed"));
}

If you run the application now you should see that pressing buttons on the left changes the text on the right.

That’s it for this tutorial join us next time for a look at using Caliburn Micro in Windows Phone 8.1 and Windows Store projects.

Caliburn Micro Part 3: Actions

Welcome to the third part of this tutorial on the basics of Caliburn Micro, in the previous part we saw how to do some basic databinding and eventing. In this next part we will go through the basics of actions.

Long Syntax

Last time we saw how to bind the click event of a button to a function in the associated View Model, by setting the name of the button to the name of the function. This works well if you only want to bind to the default event but what if you wanted to bind to a different event or even pass parameters?

Lets start by changing out previous example to use the long syntax. Edit the xaml in ShellView to look as follows.

<Grid>
    <Button Content="Press Me" VerticalAlignment="Top">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <cal:ActionMessage MethodName="ChangeMessage" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
    <TextBlock x:Name="Message" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>

You’ll need to add these two namespace references as well.

xmlns:cal="http://www.caliburnproject.org"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

If you run the app now you should see that it runs exactly the same as before. All we have done here is explicitly say which event we are listening for and which function in the View Model should be called.

Next lets look at how we can pass parameters with the action message, modify ShellView as follows so that it passes a parameter when the button is clicked.

<Button Content="Press Me" VerticalAlignment="Top">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <cal:ActionMessage MethodName="ChangeMessage">
                <cal:Parameter Value="2" />
            </cal:ActionMessage>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

Next edit the ChangeMessage function in ShellViewModel so that it takes an integer parameter.

public void ChangeMessage(int incrementBy)
{
    _pressCount += incrementBy;

    Message = "Presses = " + _pressCount;
}

If you run the app again you should notice that the count is now increased by two, this is because when the button is clicked it sends the action message to the View Model with the specified parameter which is then added to the count.

Short Syntax

If the above seemed like a quite a lot of xaml it can be shorted by using the short action message syntax. We can achieve what we did before by modifying ShellView like below.

<Button Content="Press Me" VerticalAlignment="Top" cal:Message.Attach="[Event Click] = [Action ChangeMessage(2)]" />

What we have done here is use one of Caliburn Micros attached properties to achieve the same as we did before but with much less xaml. I like this method as it simplifies the code somewhat, but in more complex cases it may be clearer to use the longer syntax.

In addition to passing literal values and binding expressions as parameters it is also possible to pass some special values that allow you access to some convenient information. These are as follows:

$eventArgs
Passes the EventArgs or input parameter to your Action.
$dataContext
Passes the DataContext of the element that the ActionMessage is attached to.
$source
The actual FrameworkElement that triggered the ActionMessage to be sent.
$view
The view (usually a UserControl or Window) that is bound to the ViewModel.
$executionContext
The action’s execution context, which contains all the above information and more.
$this
The actual UI element to which the action is attached. In this case, the element itself won’t be passed as a parameter, but rather its default property.

That’s it for this tutorial join us next time for a look at the Event Aggregator.

Caliburn Micro Part 2: The Basics of Databinding

Welcome to the second part of this tutorial on the basics of Caliburn Micro, in the previous part we saw how to setup a new project from scratch and display a window to the user. In this next part we will go through the basics of databinding which is where the true power of Caliburn Micro comes into play. We will be building upon the example shown in the previous part of this tutorial by adding some new functionality to it.

Databinding

Lets start simple by showing some text to the user. Extend ShellViewModel as shown below by adding a string property and setting it to HelloWorld in the constructor. Notice that we are now inheriting from PropertyChangedBase and we’ve added a call to NotifyOfPropertyChange in the setter of the property. PropertyChangedBase gives us access to NotifyOfPropertyChange which tells the view that it should display the new value every time the Message property is changed. This saves us from having to implement the INotifyPropertyChanged interface in all of our ViewModels.

using Caliburn.Micro;

namespace CaliburnMicroExample
{
    public class ShellViewModel : PropertyChangedBase
    {
        private string _message;

        public string Message
        {
            get { return _message; }
            set
            {
                _message = value;
                NotifyOfPropertyChange(() => Message);
            }
        }

        public ShellViewModel()
        {
            Message = "Hello World";
        }
    }
}

Next lets add a TextBlock to ShellView so that it can display our message to the user.

<Grid>
    <TextBlock x:Name="Message" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>

Now if you run up the application you should see a small windows with the text Hello World in the centre. By just giving the TextBlock the same name as out property Caliburn Micro automatically binds them together for us. This is not the only way to do it however, you could do it the traditional way by binding to the Text property of the TextBlock.

<Grid>
    <TextBlock Text="{Binding Message}" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>

Events

Now lets look at how Caliburn Micro handles events, in order to do this we will add a button to our application that lets us change the current text. First add a new function to ShellViewModel that changes the message as shown below.

using Caliburn.Micro;

namespace CaliburnMicroExample
{
    public class ShellViewModel : PropertyChangedBase
    {
        private string _message;

        public string Message
        {
            get { return _message; }
            set
            {
                _message = value;
                NotifyOfPropertyChange(() => Message);
            }
        }

        private int _pressCount;

        public ShellViewModel()
        {
            Message = "Hello World";
            _pressCount = 0;
        }

        public void ChangeMessage()
        {
            _pressCount++;

            Message = "Presses = " + _pressCount;
        }
    }
}

Now add a button to ShellView as shown below.

<Grid>
    <Button x:Name="ChangeMessage" Content="Press Me" VerticalAlignment="Top" />
    <TextBlock x:Name="Message" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>

That’s all there is to it, if you run the application now you should see that pressing the button changes the message displayed. The binding is achieved in pretty much the same way as with the TextBlock, Caliburn Micro looks for a function in the ViewModel with the same name as the Button and binds the two together so that the function is called on the button press. There are additional ways to do this which give you more control but we’ll look at those in a future tutorial.

Event Guards

The last thing we are going to cover in this tutorial is event guards. Event guards are used to only allow the handling of an event if a certain condition is met. To demonstrate this we will prevent the user from pressing the button more than 10 times. Add a new property to ShellViewModel called CanChangeMessage and also add a new NotifyOfPropertyChange to the Message setter.

public string Message
{
    get { return _message; }
    set
    {
        _message = value;
        NotifyOfPropertyChange(() => Message);
        NotifyOfPropertyChange(() => CanChangeMessage);
    }
}

public bool CanChangeMessage
{
    get { return _pressCount < 10; }
}

Now when you run the code you should see that the button becomes disabled after it has been pressed 10 times. Every time Caliburn Micro hooks up an event is also looks for a property with the same name plus the word can before it. It then uses the Boolean result of the property to determine whether the event should be handled or not. So in this case once the press count has reached 10 the property will always return false meaning no new click events will be handled and Caliburn Micro automatically disables the button for us.

In the next part of this blog series I will go through how Actions work in Caliburn Micro.

Caliburn Micro Part 1: Getting Started

In this blog series I’ll go through the steps needed to get up and running with Caliburn Micro, we’ll be using a wpf application as an example although caliburn micro also supports Silverlight, Windows Phone and Windows Store apps.

Step 1: Initial Setup

Start by creating a new wpf application in Visual Studio and grab the Caliburn Micro nugget package using the library package manager. Since Caliburn Micro takes care of creating all windows for you, delete MainWindow.xaml and remove the StartupUri attribute from App.xaml. After doing the previous App.xaml will look like this.

<Application x:Class="CaliburnMicroExample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

Step 2: Creating a View Model

Since Caliburn Micro prefers a View-Model-First approach lets start by creating our first View Model. Add a new class to the project and call it ShellViewModel. Since we are just getting setup in this tutorial we won’t add any functionality to the VM. After you have created ShellViewModel it should look as below.

namespace CaliburnMicroExample
{
    public class ShellViewModel
    {
    }
}

Note that the names of View Models in Caliburn Micro must end with ViewModel although what you put before that is up to you.

Step 3: Creating a View

In order to display something to a user we’ll need a View to go along with the View Model, create a new wfp user control and call it ShellView. The xaml for the view you created should look as below.

<UserControl x:Class="CaliburnMicroExample.ShellView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d"
             Width="100" Height="100">
    <Grid>
            
    </Grid>
</UserControl>

Note that Views in Caliburn Micro must end with View and have the same name as the View Model, so having a View Model called MyViewModel would mean that the associating View is called MyView. This is so that Caliburn Micro can automatically bind them together.

Step 4: The Bootstrapper

Finally we need a Bootstrapper which will configure the Caliburn Micro framework and tell it what to do. Bootstrappers can do quite a lot of things beyond the scope of this tutorial so for now we will just configure one that initialises the framework and displays the first View. So create a new class and call it AppBootstrapper, then add code to make it look like the one below.

using Caliburn.Micro;

namespace CaliburnMicroExample
{
    public class AppBootstrapper : BootstrapperBase
    {
        public AppBootstrapper()
        {
            Initialize();
        }

        protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
        {
            DisplayRootViewFor<ShellViewModel>();
        }
    }
}

The last thing to do is to tell the application to use the bootstrapper on startup, to do this we need to edit App.xaml as shown below.

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

That’s all there is to it, if you run the application now you should see a small square window. You are now ready to take advantage of all the cool things that Caliburn Micro has to offer.

In the next part of this blog series I will go through how databinding and events work in Caliburn Micro.