Basic Navigation with Caliburn.Micro

** There is an excellent blog on Navigation with  detailed information on each class and different styles @ devlicio.us for CM **

In the previous blog we look at how to do page navigation with Jounce. Today we will look at how to implement the same thing in Caliburn.Micro. The requirement is same.

I. Create a web page with two buttons and a container panel. The first buttons says ‘Hello World’ and second button says ‘Hello World1’.

II. Create two pages, with one page says ‘Hello world’ and the second page says ‘Hello World’.

III. Wire up the button events in such a way, when a user click the ‘Hello World’, it displays the page with ‘Hello World’ in the container panel. When the user presses ‘Hello World1’ button, it replaces the ‘Hello World’ page with ‘Hello World1’ page.

This is exactly the same requirement of our Jounce example. So how would we go about doing it? We start from what we learned from our ‘Hello World’ example.

I.Create web page with its contents:

Follow the steps specified in ‘Hello World’ example and create the simple Caliburn application. Make sure it compiles and runs. Lets add the button and content control to hold the panel to host the dynamic page by adding the following code to the ShellView.xaml

<Grid Background="White" d:DataContext="{d:DesignInstance sampleData:SampleShellViewModel, IsDesignTimeCreatable=True}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="161*" />
            <ColumnDefinition Width="194*" />
            <ColumnDefinition Width="163*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="34*" />
            <RowDefinition Height="253*" />
        </Grid.RowDefinitions>
        <Button Content="Hello World" Name="HelloWorldButton" Grid.Row="0" Grid.Column="0"/>
        <Button Content="Hello World1" Name="HelloWorld1Button" Grid.Row="0" Grid.Column="2"/>
        <ContentControl Grid.Row="1" Grid.ColumnSpan="3" Name="ActiveItem"/>
    </Grid>

 

We have added two buttons, in row 0, column 0 and 2. First button shows ‘Hello World’ and the second one shows ‘Hello World1’ as the requirement. The third control we added is ‘ContentControl to show a single content. It is named as ‘ActiveItem’. This name is important and we will come to that soon. Other than that, there is nothing special in here, the button have Name associated with it, which is nothing but caliburn convention to bind to a method for click event  in the view model. With XAML added your design time screen should look like the following

image

II. Create two pages to display ‘Hello World’ and ‘Hello Word1’:

Add two new Silverlight Pages (you can also use Silverlight User Controls if you want). Call it Page1View and Page2View. Remember, it is important to end all the view with ‘View’ and ViewModels with ‘ViewModels’. Caliburn uses convention to find and bind the View with ViewModels. Add a text block in each of the page to distinguish which page it is. So the page1view XAML would look like the following

<Grid x:Name="LayoutRoot">
        <TextBlock Text="Hello World"/>
    </Grid>

While the Page2view.xaml would look like this

<Grid x:Name="LayoutRoot">
        <TextBlock Text="Hello World1"/>
    </Grid>

Now that we have views, it is not over. Caliburn relies on ViewModel to do the routing, so create two classes with Page1ViewModel and Page2ViewModel. Both will be nothing but empty classes. You do not need to add any code. There is also different way to approach this same two screens, since I want to keep it simple, I am not going to discuss about them here yet.

III. Wireup the events to load pages:

Now that we have Shell to display the main page, two separate pages which display ‘Hello World’ and ‘Hello World1’. We need to wire up the button click events to activate appropriate page and display them in the content panel named ‘ActiveItem’.  As you know by now, when you click a button, Caliburn will look for a method name with exact name of the Button. So Lets look at the button name of ‘Hello World’, it is called ‘HelloWorld’ (with out space between hello and world). We need to write a method in the shell view model to activate the page1 and display it. To do that. we write the HelloWorld method as follows in the ShellViewModel.cs.

[Export(typeof(IShell))]
    public class ShellViewModel : Conductor<object>, IShell 
    {       

        public void HelloWorldButton()
        {
            ActivateItem(new Page1ViewModel());
        }

        public void HelloWorld1Button()
        {
            ActivateItem(new Page2ViewModel());
        }
    }

That’s it. Now if you would run the application, you will get to the main page

image

now if you would press ‘Hello World’ button, it displays the Page1View in the content panel

image

If you would press ‘Hello World1’ it displays

image

 

So if you notice, we did not write lot of code to achieve the simple page navigation. In fact, the pages we created to display the ‘Hello World’ and ‘Hello World1’ do not have any clue about this will be placed on a particular panel or the page by itself did not say anything about it is being used to display somewhere. All the navigation work is done at the Shell level and nothing at the page level.  Couple of important points here

1. If you notice, the ShellViewModel is derived from Conductor<object>, which is responsible for orchestrating the navigation.

2. To create and place an item on a panel, all you have to do is ActivateItem(viewmodel).

3. When ActivateItem is called, the screen instance is created and placed on ‘ActiveItem’ in the ShellView.

4. There is a whole a lot you can do during the navigation process and I barely touched the surface. We will look at more features in the navigation in later posts.

Step into Caliburn.Micro World

This is my first attempt at Caliburn so this might be little crude. After some very busy time, I thought I will give it a go on Caliburn.Micro. To my surprise ‘Hello World’ was not that complicated as I thought it would be. So in this blog, we are going to look at writing simple Hello World program to understand the following

I. What are all the things required to build an application.

II. MVVM.

III. Simple data binding.

IV. Design time data or Blendability.

V. Distribution file size.

To create a simple application, I followed this introduction link and got the Hello World working in no time. The steps are simple.

1. Create a brand new silverlight application.

2. If you do not have NuGet please go get it, with NuGet in place. Go to Tools->Library Package Manager –> Manage NuGet Packages and install Caliburn.Micro.

Once you install, not only it brings down the required dll, but also it creates the shell template with View, ViewModel and interface for the view model.

3. Follow the steps in the links mentioned to clean up App.XAML and make sure you delete the MainPage.XAML and run the program. You will see Hello World.

4. In this process we really did not use ViewModel. If you look at the ShellViewModel.cs, there is no code. Lets modify the code little bit to have small taste of MVVM.

5. Go to ShellView.XAML and change the textblock as follows;

<TextBlock Name="HelloWorld"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   FontSize="20" />

What we did here is that, instead of passing the constant now we named the TextBlock so that it can get some data from view model.

6. Go to IShell.cs and add the following

public interface IShell 
    {
        string HelloWorld { get; }
    }

Same as Jounce, I am creating the variable in here so that I can use it for design time data.

7. Modify the SheViewModel.cs as follows

[Export(typeof(IShell))]
    public class ShellViewModel : IShell 
    {
        #region IShell Members

        public string HelloWorld
        {
            get { return "Hello Unni"; }
        }

        #endregion
    }

 

8. Now if you run the code, it will show ‘Hello Unni’ instead of hello word from Caliburn. We will look at how binding happened in a second.

 

In this process you deleted lot of code and added few lines.

I. What are all the things required to build an application.

With our first program running, lets look at the components required to write Silverlight using Caliburn. You need two dlls, the first one, of course is Calburn.Micro.dll and the second one is System.Interactivity.dll. If you use blend then this dll will be available in GAC for you, you need to add the reference to your solution.

II. MVVM.

Caliurn uses simple convention to identify View and ViewModels, it is pretty cool. All your view have to end with ‘View’ and the view model as you guessed it, it should end with ‘ViewModel’, thats about it. So in the ’HelloWorld’, our main View is Shell and is called ‘ShellView’ and its corresponding view model is ‘ShellViewModel’. but if you would look at the app.xaml.cs we did not say which one is our starting page. It is done in the bootstrapper. If you look at the class definition of bootstrapper

public class AppBootstrapper : Bootstrapper<IShell>

 

So if you want to specify a different page, all you have to do is to bootstrap off of its view mode.

III. Simple data binding.

Data Binding is super simple. In our Hello word program the TextBlock name was ‘HelloWorld’ and if you look at the view model, we have a property called ‘HelloWord’. So binding is done through Name in XAML and associated property in the view model.

IV. Design time data or Blendability.

Unfortunately, so far I am not successful in enabling design time data. Here is what I attempted. Created a new class called SampleShellViewModel.cs as follows

namespace HelloWorld
{
    public class SampleShellViewModel:IShell
    {

        #region IShell Members

        public string HelloWorld
        {
            get { return "Hello World"; }
        }

        #endregion
    }
}

Modified the ShellView.XAML as follows

<UserControl x:Class="HelloWorld.ShellView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             xmlns:sampleData="clr-namespace:HelloWorld"
             d:DesignHeight="287" d:DesignWidth="518"
             >

    <Grid Background="White" d:DataContext="{d:DesignInstance sampleData:SampleShellViewModel, IsDesignTimeCreatable=True}">
        <TextBlock Name="HelloWorld"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   FontSize="20" />
    </Grid>

</UserControl>

But view does not recognizes the design time data object. I will continue work on it and see what am I doing wrong here and update the post once I find the answer.

** By default Caliburn Micro naming convention will not work with design time data. So instead of using Name=”Hello World”, do Content=”{Binding HelloWorld"}” will do run time binding and design time data binding.”

V. Distribution file size.

The distribution dll for Caliburn is only 41K compressed.

 

This is my baby steps into Caliburn and so far what I found is that it is easy to use.

Comparing to Jounce, here are some of my observations;

1. Compare to Jounce the distribution dll, Caliburn is only 6K more, it is not a big deal.

2. Caliburn uses convention to do data binding and View, View Model binding while in Jounce, for every view, you have to write the ViewModelRoute binding.

3. Jounce is attribute based development, while Caliburn is convention based development.

4. Since I do not have definite answer on Blendability, I am not going to comment on it yet.

4. By default the convention binding will not work on Blendabilty. If you want design time data, add or replace Name with normal Binding.

5. You have to have a bootstrapper for Caliburn, while Jounce it is build in.

6. Caliburn can use any IoC container, while Jounce is build on top of MEF.

I will go more about binding, MEF and other features in a later blog.

MVVM Frameworks Compare and Contrast – 1

This subject will never be accurate, regardless I am going to take a stab at it. The question is, if it is not going to accurate why do it? Well, first to educate myself with all available framework. I am sure by looking at different framework, learn some neat stuff on coding and patterns. One last thing, by putting it out in it blog if I am wrong, I will know and correct myself. One last point, some of the items become out-of-date soon so I will be very clear on which version and build I am using as I do this blog.

Before I go any further, I would love to hear from you, which framework are you using and if you could explain why you choose that will help me a lot.

Couple of things I need to tell upfront;

  1. This is purely for Silverlight, sorry no WPF or WP7.
  2. I have been using Jounce for a while and I love it. So I might have bias towards Jounce so if you see it please correct me.
  3. I might not cover all the features in all the frame works, so if you think I might have missed something, please let me know.

Now for the MVVM Framework comparison, I am going to use the follow common frameworks available.

I am thinking of covering following subject on each of the frameworks. If you can think of some feature I need to add here, please let me know as well.

  • Documentation and samples.
  • Simple Hello World
  • Event Aggregation
  • Commanding
  • Region Management
  • Navigation
  • Working with Multiple XAP files.
  • Design Time data and Blentability.
  • and more