.NET & Funky Fresh

Syndication

News

  • <script type="text/javascript" src="http://ws.amazon.com/widgets/q?ServiceVersion=20070822&amp;MarketPlace=US&amp;ID=V20070822/US/bluspiconinc-20/8001/8b68bf4b-6724-40e7-99a5-a6decf6d8648"> </script>
Caliburn.Micro Soup to Nuts Part 6b – Simple Navigation with Conductors

SimpleNavigationProjectPreviously, 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:

PageTwo

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.

Stay tuned, more samples to come…


Posted 10-12-2010 11:38 AM by Rob Eisenberg

[Advertisement]

Comments

MichaelD! wrote re: Caliburn.Micro Soup to Nuts Part 6b – Simple Navigation with Conductors
on 10-13-2010 2:31 PM

Rob:

Thank you for posting this!!!  Navigation has been a big question mark for me with Caliburn.Micro.  I know that Caliburn2.0 had a Show class that as intended to be used as the navigation manager.  Are there plans to re-introduce this class/functionality for Caliburn.Micro?

I suppose the biggest scenario that is stumping me is in regards to navigating with complex views (that is a conductor within a conductor).  With MVC, it appears you can wire this functionality with a navigation trigger.  I'm curious on how this is done with Caliburn.Micro.

Let's say I have 2 mainviews (A and B), each with 2 subviews respectively (a and b).  It would be fantastic to get some pseudo-code in a future post showing how to navigate from Aa to Ba or from Aa to Bb.  That is, showing how Caliburn.Micro would switch to mainview B and then subview a or b with one action.  I hope that makes sense. :)

Keep up the great work!

MichaelD! wrote re: Caliburn.Micro Soup to Nuts Part 6b – Simple Navigation with Conductors
on 10-13-2010 2:31 PM

Rob:

Thank you for posting this!!!  Navigation has been a big question mark for me with Caliburn.Micro.  I know that Caliburn2.0 had a Show class that as intended to be used as the navigation manager.  Are there plans to re-introduce this class/functionality for Caliburn.Micro?

I suppose the biggest scenario that is stumping me is in regards to navigating with complex views (that is a conductor within a conductor).  With MVC, it appears you can wire this functionality with a navigation trigger.  I'm curious on how this is done with Caliburn.Micro.

Let's say I have 2 mainviews (A and B), each with 2 subviews respectively (a and b).  It would be fantastic to get some pseudo-code in a future post showing how to navigate from Aa to Ba or from Aa to Bb.  That is, showing how Caliburn.Micro would switch to mainview B and then subview a or b with one action.  I hope that makes sense. :)

Keep up the great work!

MichaelD! wrote re: Caliburn.Micro Soup to Nuts Part 6b – Simple Navigation with Conductors
on 12-02-2010 8:07 AM

I've answered my own question here: http://common-framework.com/

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)