<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://devlicio.us/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>.NET &amp; Funky Fresh : Tutorial, Xaml</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/Xaml/default.aspx</link><description>Tags: Tutorial, Xaml</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Caliburn.Micro Soup to Nuts Part 9–New WP7 Features</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2011/06/09/caliburn-micro-soup-to-nuts-part-9-new-wp7-features.aspx</link><pubDate>Thu, 09 Jun 2011 17:23:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:67721</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=67721</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2011/06/09/caliburn-micro-soup-to-nuts-part-9-new-wp7-features.aspx#comments</comments><description>&lt;p&gt;In version 1.0 we had pretty good support for building apps for WP7, but in v1.1 we&amp;rsquo;ve taken things up a notch. Let&amp;rsquo;s look at the same HelloWP7 sample that we did &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/wikipage?title=Working%20with%20Windows%20Phone%207&amp;amp;referringTitle=Documentation"&gt;previously&lt;/a&gt;, but see how it&amp;rsquo;s been updated to take advantage of our improved tombstoning, launcher/chooser support and strongly typed navigation. You&amp;rsquo;ll also notice that the code is cleaner overall.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bootstrapper&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the cleaned up boostrapper in v1.1.&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class HelloWP7Bootstrapper : PhoneBootstrapper {
    PhoneContainer container;

    protected override void Configure() {
        container = new PhoneContainer(RootFrame);

        container.RegisterPhoneServices();
        container.PerRequest&amp;lt;MainPageViewModel&amp;gt;();
        container.PerRequest&amp;lt;PivotPageViewModel&amp;gt;();
        container.PerRequest&amp;lt;TabViewModel&amp;gt;();

        AddCustomConventions();
    }

    static void AddCustomConventions() {
        //ellided
    }

    protected override object GetInstance(Type service, string key) {
        return container.GetInstance(service, key);
    }

    protected override IEnumerable&amp;lt;object&amp;gt; GetAllInstances(Type service) {
        return container.GetAllInstances(service);
    }

    protected override void BuildUp(object instance) {
        container.BuildUp(instance);
    }
}&lt;/pre&gt;
&lt;p&gt;There are two things to notice here. First, we&amp;rsquo;ve removed all the manual Caliburn.Micro service configuration and pushed it into the SimpleContainer. That gives you one line of code to configure the framework if you are using the OOTB container. Speaking of which, we now provide the SimpleContainer officially in the Caliburn.Micro.Extensions assembly. That helps you get started faster. You can always plug your own in, of coarse. In addition to the simplified configuration, notice that the ViewModels for pages are no longer registered using a string key. For v1.1 our ViewModelLocator has been re-implemented to pull VMs from the container by Type rather than key. It now follows the exact same naming strategies as the ViewLocator (but in reverse) and even derives possible interface names so that it resolves VMs from the container correctly. This both improves the consistency of ViewModel location as well as makes the configuration simpler.&lt;/p&gt;
&lt;p&gt;The boostrapper is added to your App.xaml as always:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;Application x:Class=&amp;quot;Caliburn.Micro.HelloWP7.App&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
             xmlns:local=&amp;quot;clr-namespace:Caliburn.Micro.HelloWP7&amp;quot;&amp;gt;
    &amp;lt;Application.Resources&amp;gt;
        &amp;lt;local:HelloWP7Bootstrapper x:Key=&amp;quot;bootstrapper&amp;quot; /&amp;gt;
    &amp;lt;/Application.Resources&amp;gt;
&amp;lt;/Application&amp;gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Important Note About App.xaml.cs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;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&amp;#39;s what the bootstrapper&amp;#39;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&amp;#39;t need both. When using CM&amp;#39;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.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;INavigationService&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s review what CM&amp;rsquo;s INavigationService&amp;nbsp; does for you. First, remember that WP7 enforces a View-First approach to UI at the platform level. Like it or not, the platform is going to create pages at will and the Frame control is going to conduct your application thusly. You don&amp;rsquo;t get to control that and there are no extensibility points, unlike the Silverlight version of the navigation framework. Rather than fight this, I&amp;rsquo;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 and a Model-First approach to coding against the navigation system. In order to bridge this gap, I&amp;rsquo;ve enabled the INavigationService to hook into the native navigation frame&amp;rsquo;s functionality and augment it with the following behaviors:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;When Navigating To a Page&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use the new ViewModelLocator to conventionally determine the Type of the VM that should be attached to the page being navigated to. Pull that VM by Type out of the container.&lt;/li&gt;
&lt;li&gt;If a VM is found, use the ViewModelBinder to connect the Page to the located ViewModel.&lt;/li&gt;
&lt;li&gt;Examine the Page&amp;rsquo;s QueryString. Look for properties on the VM that match the QueryString parameters and inject them, performing the necessary type coercion.&lt;/li&gt;
&lt;li&gt;If the ViewModel implements the IActivate interface, call its Activate method.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;When Navigating Away From a Page&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Detect whether the associated ViewModel implements the IGuardClose interface.&lt;/li&gt;
&lt;li&gt;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.&lt;sup&gt;1&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;If the ViewModel can close and implements the IDeactivate interface, call it&amp;rsquo;s Deactivate method. Always pass &amp;ldquo;false&amp;rdquo; to indicate that the VM should deactivate, but not necessarily close. This is because the phone may be deactivating, but not actually tombstoning or closing. There&amp;rsquo;s no way to know.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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 &amp;ldquo;closing&amp;rdquo; of the application (IDeactivate). All these interfaces (and a couple more) are implemented by the Screen class. 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&amp;rsquo;s code-behind.&lt;/p&gt;
&lt;p&gt;These hooks into phone navigation enable a really smooth way of interacting with the phone&amp;rsquo;s navigation lifecycle. But now that we have an improved ViewModelLocator that matches exactly the ViewLocator and works on types, we can take things further. In v1.1 we&amp;rsquo;ve introduced support for strongly-typed navigation. Here&amp;rsquo;s what the new MainPageViewModel from the sample looks like using this new feature:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class MainPageViewModel {
    readonly INavigationService navigationService;

    public MainPageViewModel(INavigationService navigationService) {
        this.navigationService = navigationService;
    }

    public void GotoPageTwo() {
        navigationService.UriFor&amp;lt;PivotPageViewModel&amp;gt;()
            .WithParam(x =&amp;gt; x.NumberOfTabs, 5)
            .Navigate();
    }
}&lt;/pre&gt;
&lt;p&gt;This allows you to specify a ViewModel to navigate to along with the query string parameters. Since this all happens using generics and lambdas, you can never miss-type a page Uri or mess up your query strings&amp;hellip;.and refactoring will work beautifully.&lt;/p&gt;
&lt;p&gt;For the sake of completeness, here&amp;rsquo;s the page that will be bound to MainPageViewModel:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;phone:PhoneApplicationPage x:Class=&amp;quot;Caliburn.Micro.HelloWP7.MainPage&amp;quot;
                            xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
                            xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
                            xmlns:phone=&amp;quot;clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone&amp;quot;
                            xmlns:shell=&amp;quot;clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone&amp;quot;
                            xmlns:cal=&amp;quot;clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro&amp;quot;
                            SupportedOrientations=&amp;quot;Portrait&amp;quot;
                            Orientation=&amp;quot;Portrait&amp;quot;
                            shell:SystemTray.IsVisible=&amp;quot;True&amp;quot;&amp;gt;
    &amp;lt;Grid Background=&amp;quot;Transparent&amp;quot;&amp;gt;
        &amp;lt;Grid.RowDefinitions&amp;gt;
            &amp;lt;RowDefinition Height=&amp;quot;Auto&amp;quot; /&amp;gt;
            &amp;lt;RowDefinition Height=&amp;quot;*&amp;quot; /&amp;gt;
        &amp;lt;/Grid.RowDefinitions&amp;gt;
        &amp;lt;StackPanel Grid.Row=&amp;quot;0&amp;quot;
                    Margin=&amp;quot;24,24,0,12&amp;quot;&amp;gt;
            &amp;lt;TextBlock Text=&amp;quot;WP7 Caliburn.Micro&amp;quot;
                       Style=&amp;#39;{StaticResource PhoneTextNormalStyle}&amp;#39; /&amp;gt;
            &amp;lt;TextBlock Text=&amp;#39;Main Page&amp;#39;
                       Margin=&amp;#39;-3,-8,0,0&amp;#39;
                       Style=&amp;#39;{StaticResource PhoneTextTitle1Style}&amp;#39; /&amp;gt;
        &amp;lt;/StackPanel&amp;gt;

        &amp;lt;Grid Grid.Row=&amp;#39;1&amp;#39;&amp;gt;
            &amp;lt;Button x:Name=&amp;#39;GotoPageTwo&amp;#39;
                    Content=&amp;#39;Goto Page Two&amp;#39; /&amp;gt;
        &amp;lt;/Grid&amp;gt;
    &amp;lt;/Grid&amp;gt;

    &amp;lt;phone:PhoneApplicationPage.ApplicationBar&amp;gt;
        &amp;lt;shell:ApplicationBar IsVisible=&amp;#39;True&amp;#39;&amp;gt;
            &amp;lt;shell:ApplicationBar.Buttons&amp;gt;
                &amp;lt;cal:AppBarButton IconUri=&amp;#39;ApplicationIcon.png&amp;#39;
                                  Text=&amp;#39;Page Two&amp;#39;
                                  Message=&amp;#39;GotoPageTwo&amp;#39; /&amp;gt;
            &amp;lt;/shell:ApplicationBar.Buttons&amp;gt;
        &amp;lt;/shell:ApplicationBar&amp;gt;
    &amp;lt;/phone:PhoneApplicationPage.ApplicationBar&amp;gt;
&amp;lt;/phone:PhoneApplicationPage&amp;gt;&lt;/pre&gt;
&lt;p&gt;There&amp;rsquo;s really nothing new here in v1.1. But I just wanted to remind you that Caliburn.Micro supports Actions on the AppBar&amp;nbsp; as long as you use CM&amp;rsquo;s AppBarButton and AppBarMenuItem :) &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IPhoneService&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The IPhoneService wraps the phone&amp;rsquo;s frame and provides access to important information and events. We had this service in v1.0 but we&amp;rsquo;ve expanded it in v1.1 to expose a better event model. Those familiar with WP7 know that the phone has a series of events that fire in different circumstances: Launching, Activated, Deactivated and Closing. Unfortunately, these events obscure whether the phone is actually resurrecting from a tombstoned state or simply continuing execution. The current SDK does not make it easy for the developer to actually determine this, so Caliburn.Micro does the heavy lifting for you and provides the following event model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Launching - Occurs when a fresh instance of the application is launching.&lt;/li&gt;
&lt;li&gt;Activated - Occurs when a previously paused/tombstoned app is resumed/resurrected.&lt;/li&gt;
&lt;li&gt;Deactivated - Occurs when the application is being paused or tombstoned.&lt;/li&gt;
&lt;li&gt;Closing - Occurs when the application is closing.&lt;/li&gt;
&lt;li&gt;Continuing -&amp;nbsp; Occurs when the app is continuing from a temporarily paused state.&lt;/li&gt;
&lt;li&gt;Continued - Occurs after the app has continued from a temporarily paused state.&lt;/li&gt;
&lt;li&gt;Resurrecting - Occurs when the app is &amp;quot;resurrecting&amp;quot; from a tombstoned state.&lt;/li&gt;
&lt;li&gt;Resurrected - Occurs after the app has &amp;quot;resurrected&amp;quot; from a tombstoned state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using these new events, you can more intelligently make decisions about whether or not you need to restore data. In the forthcoming Mango release, the platform will provide us information on whether the app is continuing or resurrecting. However, developers working with Caliburn.Micro can have that information now and when Mango arrives, we&amp;rsquo;ll update our implementation to use the new bits. Your code won&amp;rsquo;t have to change.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tombstoning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As you might imagine, our new tombstoning mechanism takes advantage of the new events so that it can more reliably and accurately save/restore important data. Let&amp;rsquo;s have a look at the PivotPageViewModel to see how it interacts with the tombstoning mechanism.&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class PivotPageViewModel : Conductor&amp;lt;IScreen&amp;gt;.Collection.OneActive {
    readonly Func&amp;lt;TabViewModel&amp;gt; createTab;

    public PivotPageViewModel(Func&amp;lt;TabViewModel&amp;gt; createTab) {
        this.createTab = createTab;
    }

    public int NumberOfTabs { get; set; }

    protected override void OnInitialize() {
        Enumerable.Range(1, NumberOfTabs).Apply(x =&amp;gt; {
            var tab = createTab();
            tab.DisplayName = &amp;quot;Item &amp;quot; + x;
            Items.Add(tab);
        });

        ActivateItem(Items[0]);
    }
}&lt;/pre&gt;
&lt;p&gt;The PivotPageViewModel will receive the number of pivot items to create through it&amp;rsquo;s NumberOfTabs property, which is pushed in from the query string, as mentioned above. It will then add these items to the conductor and activate the first one. If you&amp;rsquo;re familiar with the Pivot and CM&amp;rsquo;s previous sample, you&amp;rsquo;ll notice that our PivotFix is gone. Pivot has a horrible bug that will crash your application if you try to set the SelectedItem or SelectedIndex to an item 3 or greater from either end of the pivot collection, while the Pivot itself is not visible. This makes it really hard to restore this control from a tombstoned state because you have to set the value at the exact right time. Previously we used a PivotFix hack to work around the control&amp;rsquo;s bug, but the new tombstoning mechanism is powerful and extensible enough to just make it work. You&amp;rsquo;ll notice that there are no attributes describing tombstoning behavior. They&amp;rsquo;ve been removed in favor of a poco model inspired by Fluent NHibhernate. If you would rather have the attributes, you can actually build them on top of the new system. The new system is also more reliable than previously and has a lot more options for storage. Let&amp;rsquo;s see the class that describes the tombstoning behavior for PivotPageViewModel:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class PivotPageModelStorage : StorageHandler&amp;lt;PivotPageViewModel&amp;gt; {
    public override void Configure() {
        this.ActiveItemIndex()
            .InPhoneState()
            .RestoreAfterViewLoad();
    }
}&lt;/pre&gt;
&lt;p&gt;All you&amp;nbsp; have to do to make a class participate in tombstoning is to inherit from StorageHandler&amp;lt;T&amp;gt;. The PhoneContainer will auto-register anything of this type in the assembly. Just override the Configure method and declare the tombstoning instructions. I&amp;rsquo;ve created some extension methods for common scenarios. Here&amp;rsquo;s what the above declaration states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-Persist the Conductor&amp;rsquo;s ActiveItem&amp;rsquo;s index&lt;/li&gt;
&lt;li&gt;-Store the index in PhoneState&lt;/li&gt;
&lt;li&gt;-Restore the value after the associated view has been loaded.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;rsquo;s look at the storage handler for the TabViewModel to see some more options:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class TabViewModelStorage : StorageHandler&amp;lt;TabViewModel&amp;gt; {
    public override void Configure() {
        Id(x =&amp;gt; x.DisplayName);

        Property(x =&amp;gt; x.Text)
            .InPhoneState()
            .RestoreAfterActivation();
    }
}&lt;/pre&gt;
&lt;p&gt;Here we are specifying an Id because we actually need to persist multiple instances of the same VM. When we restore, we&amp;rsquo;ll need to know how to map the properties back. We&amp;rsquo;re also storing the data in PhoneState, but this time we&amp;rsquo;re not waiting for the view to load, but just waiting for the TabViewModel to be activated by its owning Conductor.&lt;/p&gt;
&lt;p&gt;Out of the box, we also support storing data in AppSettings. For example, if you wanted to same tab to be selected *across application restarts* not just when tombstoned, you could define the PivotPageModelStorage like this:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class PivotPageModelStorage : StorageHandler&amp;lt;PivotPageViewModel&amp;gt; {
    public override void Configure() {
        this.ActiveItemIndex()
            .InAppSettings()
            .RestoreAfterViewLoad();
    }
}&lt;/pre&gt;
&lt;p&gt;Pretty easy? All this works by collaborating with the IoC container and keying off of the new event model exposed by the IPhoneService. It&amp;rsquo;s pretty powerful and extensible. You can add your own storage mechanism or define your own restore timing. You can even implement IStorageHandler directly to write completely custom code on a class by class basis. You could easily add a version that inspected classes for custom attributes and built up the configuration, if you like the attribute model better. You can also store whole instances, not just their properties, and have them rehydrated properly and available for ctor injection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Launchers and Choosers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Launchers and Choosers are painful to work with if you want to do MVVM. In v1.0 we provided a solution to this. I wasn&amp;rsquo;t happy with its implementation&amp;hellip;it was unpredictable in certain scenarios. Once we established the new phone events, better IoC integration and new tombstoning mechanism, I realized I could build a better launcher/chooser system. Let&amp;rsquo;s take a look at the updated version of TabViewModel in order to see how it works:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class TabViewModel : Screen, IHandle&amp;lt;TaskCompleted&amp;lt;PhoneNumberResult&amp;gt;&amp;gt; {
    string text;
    readonly IEventAggregator events;

    public TabViewModel(IEventAggregator events) {
        this.events = events;
    }

    public string Text {
        get { return text; }
        set {
            text = value;
            NotifyOfPropertyChange(() =&amp;gt; Text);
        }
    }

    public void Choose() {
        events.RequestTask&amp;lt;PhoneNumberChooserTask&amp;gt;();
    }

    public void Handle(TaskCompleted&amp;lt;PhoneNumberResult&amp;gt; message) {
        MessageBox.Show(&amp;quot;The result was &amp;quot; + message.Result.TaskResult, DisplayName, MessageBoxButton.OK);
    }

    protected override void OnActivate() {
        events.Subscribe(this);
        base.OnActivate();
    }

    protected override void OnDeactivate(bool close) {
        events.Unsubscribe(this);
        base.OnDeactivate(close);
    }
}&lt;/pre&gt;
&lt;p&gt;The most significant architectural change I made was to re-implement the launcher/chooser mechanism to work on top of the IEventAggregator. Take a look at the Choose method. The RequestTask method is just an extension method of the IEventAggregator that publishes a special event that the framework is subscribed to. The framework then starts the task. When it&amp;rsquo;s completed, the framework publishes an event TaskCompleted&amp;lt;T&amp;gt; where T is the result the the chooser returns. You can register for this in the same VM that published the chooser event or in an entirely different one if you like. In the case of our sample, we have 5 TabViewModels that can launch the same chooser. That&amp;rsquo;s probably not normal, but you can handle this situation in three ways. In our case, the VMs are in a Conductor, and only one of them can be active at a time, so we just Subscribe/Unsubscribe based on the Screen lifecycle so that only the active VM will receive the result. This is a version of &lt;a target="_blank" href="http://codebetter.com/jeremymiller/2007/07/02/build-your-own-cab-12-rein-in-runaway-events-with-the-quot-latch-quot/"&gt;the Latch pattern&lt;/a&gt;. The second way to handle this is through the event state. When you call the RequestTask method you can pass a state object which you can use for identification purposes later. Yes, this will be present even if the chooser causes a tombstone event. The final way is to have a single object that registers for the completed event, decoupling the launching from the completion. Thus multiple VM could launch the same chooser, but only one class would handle the result.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IWindowManager&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The IWindowManager was actually in v1.0, as a last minute addition. It&amp;rsquo;s a really easy way to show native-looking, custom message boxes or modal dialogs. You can also use it to show popups. We&amp;rsquo;ll talk more about the window manager, on all platforms, in the next post.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Referenced Samples&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Caliburn.Micro.HelloWP7&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Even though the IGuardClose interface was designed to handle async scenarios, you must use it synchronously in WP7. This is due to a flaw in the design of Silverlight Navigation Framework which doesn&amp;rsquo;t account for async shutdown scenarios.&lt;/li&gt;
&lt;/ol&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=67721" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/DSL/default.aspx">DSL</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WP7/default.aspx">WP7</category></item><item><title>Caliburn.Micro Soup to Nuts Part 8–The EventAggregator</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2011/05/30/caliburn-micro-soup-to-nuts-part-8-the-eventaggregator.aspx</link><pubDate>Mon, 30 May 2011 16:06:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:67406</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=67406</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2011/05/30/caliburn-micro-soup-to-nuts-part-8-the-eventaggregator.aspx#comments</comments><description>&lt;p&gt;In Caliburn.Micro we have a series of supporting services for building presentation tiers. Among them is the EventAggregator, a service which supports in-process publish/subscribe. There are various implementations of this pattern available in other frameworks, but I think you&amp;rsquo;ll find that Caliburn.Micro&amp;rsquo;s implementation sports the cleanest API and the richest set of features. Let&amp;rsquo;s start by having a look at the IEventAggregator interface:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public interface IEventAggregator {
    void Subscribe(object instance);
    void Unsubscribe(object instance);
    void Publish(object message, Action&amp;lt;System.Action&amp;gt; marshal = null);
}&lt;/pre&gt;
&lt;p&gt;Below we&amp;rsquo;ll dig into how the default implementation of this interface (EventAggregator) works.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Subscribe&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With the Caliburn.Micro EventAggregator we don&amp;rsquo;t actually leverage events under the covers. Events are prone to memory leaks and it&amp;rsquo;s extremely difficult to avoid them or to write a flawless weak event implementation. Instead, we allow you to subscribe an object instance. Under the covers we hold a weak reference. That makes things quite simple. But, how do we know what messages to subscribe to and what methods to use as callbacks? Well, we follow a declarative model by requiring subscribers to implement an interface which states which message they are interested in and provides the callback method. The interface looks like this:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public interface IHandle&amp;lt;TMessage&amp;gt; : IHandle {
    void Handle(TMessage message);
}&lt;/pre&gt;
&lt;p&gt;And it&amp;rsquo;s used like this:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class MyViewModel : IHandle&amp;lt;SomeMessage&amp;gt;{
    public void Handle(SomeMessage message){
        //do something with the message
    }
}&lt;/pre&gt;
&lt;p&gt;Because we use an interface, you can implement IHandle&amp;lt;T&amp;gt; as many times as you want on a given class. This approach keeps things declarative, strongly-typed and free from memory leaks. You can even use explicit interface implementations to hide the handlers if you desire.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unsubscribe&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s not too much to say about this. When you call this method, we search our list of subscribers and remove the specified instance. You may be wondering why this is even necessary if subscribers are held with weak references to begin with. It turns out that there are a number of cases where you want to control the subscription&amp;rsquo;s activation. Imagine you have a Screen Collection and only the Active Screen is supposed to receive events. In this case, you&amp;rsquo;d want to subscribe when the screen was activated and unsubscribe when it was deactivated. See the v1.1 HelloWP7 sample for an example of how this works with the new Launcher/Choosers mechanism.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Publish&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As you might expect, calling Publish actually sends a message to all it&amp;rsquo;s subscribers. Here&amp;rsquo;s how you might use it:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class MyOtherViewModel{
    IEventAggregator events;

    public MyOtherViewModel(IEventAggregator events){
        this.events = events;
    }

    public void DoSomething(){
        events.Publish(new SomeMessage{
            SomeNumber = 5,
            SomeString = &amp;quot;Blah...&amp;quot;
        });
    }
}&lt;/pre&gt;
&lt;p&gt;Here, we get an instance of the IEventAggregator service via constructor injection. Then, when the DoSomething method is invoked, we publish the SomeMessage message along with its data. Assuming MyViewMododel above had subscribed itself to the aggregator, it would then have it&amp;#39;s Handle method called with the SomeMessage instance. So how does this work? We do this by iterating our list of subscribers to see if any of them implement IHandle&amp;lt;T&amp;gt; where T is assignable from the message that is being published. All the matches that are found then have their handlers called on the UI thread.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marker Interface&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;IHandle&amp;lt;T&amp;gt; inherits from a marker interface IHandle. This allows the use of casting to determine if an object instance subscribes to any events. This enables simple auto-subscribing if you integrate with an IoC container. Most IoC containers (including the SimpleContainer) provide a hook for being called when a new instance is created. Simply wire for your container&amp;rsquo;s callback, inspect the instance being created to see if it implement IHandle, and if it does, call Subscribe on the event aggregator. Just remember, you probably don&amp;rsquo;t want to use this technique if you need conditional subscription as I described above.&lt;/p&gt;
&lt;h2&gt;New in v1.1&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Custom Publication Marshaling&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Those familiar with v1.0 may notice a few interesting differences in the interface. Among them is the optional &amp;ldquo;marshal&amp;rdquo; parameter of the Publish method. By default messages will be automatically published synchronously on the UI thread. However, this is not always desirable. The optional parameter allows you to provide an action which marshals the publication to a custom thread. By using this extension point, a developer could easily write extension methods such as: PublishOnCurrentThread, PublishOnBackgroundThread or PublishOnUIThreadAsync.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Polymorphic Event Subscriptions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Above I stated that during publication we check for handlers &amp;ldquo;where T is assignable from the message being published.&amp;rdquo; We do this with reflection in v1.1 rather than casting (v1.0) in order to enable polymorphic event subscriptions. Let me explain what this means by providing an example:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public interface ICustomerMessage{
    //implementation here
}

public interface ICustomerCreated : ICustomerMessage{
    //implementation here
}

public interface ICustomerDeleted : ICustomerMessage{
    //implementation here
}

public class AnUnrelatedMessage{
    //implementation here
}

public class MyObserver :
    IHandle&amp;lt;object&amp;gt;, 
    IHandle&amp;lt;ICustomerMessage&amp;gt;, 
    IHandle&amp;lt;ICustomerDeleted&amp;gt; {
    
    public void Handle(object message){
        //will handle every message in the application
    }

    public void Handle(ICustomerMessage message){
        //handles ICustomerCreated and ICustomerDeleted
    }

    public void Handle(ICustomerDeleted message){
        //handles only ICustomerDeleted
    }
}&lt;/pre&gt;
&lt;p&gt;This turns out to be very powerful, especially when you need to evolve a system over time.&lt;/p&gt;
&lt;p&gt;You can see the EventAggregator in action and step through some code by opening up the HelloEventAggregator sample under source. This sample creates a ShellViewModel with two child view models. Each child publishes a message that the other child is subscribed to. The ShellViewModel is subscribed to all messages via the polymorphic features of the aggregator. Here&amp;rsquo;s a screen shot after some messages have been published:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/HelloEventAggregator_5F00_775C276C.png"&gt;&lt;img height="370" width="501" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/HelloEventAggregator_5F00_thumb_5F00_1D51D7C3.png" alt="HelloEventAggregator" border="0" title="HelloEventAggregator" style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=67406" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WP7/default.aspx">WP7</category></item><item><title>Caliburn.Micro Soup to Nuts Part 7 - All About Conventions</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2010/12/16/caliburn-micro-soup-to-nuts-part-7-all-about-conventions.aspx</link><pubDate>Thu, 16 Dec 2010 20:49:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:63987</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=63987</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2010/12/16/caliburn-micro-soup-to-nuts-part-7-all-about-conventions.aspx#comments</comments><description>&lt;p&gt;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&amp;rsquo;s why CM&amp;rsquo;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&amp;rsquo;s good to know what those conventions are and how they work. That&amp;rsquo;s the subject of this article.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;View Resolution (ViewModel-First)&lt;/h2&gt;
&lt;h3&gt;Basics&lt;/h3&gt;
&lt;p&gt;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 UserControl&lt;sup&gt;1&lt;/sup&gt; that it should bind to the ViewModel and display. So, what is that pattern? Let&amp;rsquo;s just take a look at ViewLocator.LocateForModelType to find out:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public static Func&amp;lt;Type, DependencyObject, object, UIElement&amp;gt; LocateForModelType = (modelType, displayLocation, context) =&amp;gt;{
    var viewTypeName = modelType.FullName.Replace(&amp;quot;Model&amp;quot;, string.Empty);
    if(context != null)
    {
        viewTypeName = viewTypeName.Remove(viewTypeName.Length - 4, 4);
        viewTypeName = viewTypeName + &amp;quot;.&amp;quot; + 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(&amp;quot;{0} not found.&amp;quot;, viewTypeName) }
        : GetOrCreateViewType(viewType);
};&lt;/pre&gt;
&lt;p&gt;Let&amp;rsquo;s ignore the &amp;ldquo;context&amp;rdquo; variable at first. To derive the view, we make an assumption that you are using the text &amp;ldquo;ViewModel&amp;rdquo; in the naming of your VMs, so we just change that to &amp;ldquo;View&amp;rdquo; everywhere that we find it by removing the word &amp;ldquo;Model&amp;rdquo;. 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&amp;rsquo;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.&lt;sup&gt;2&lt;/sup&gt; If we find the type, we create an instance (or get one from the IoC container if it&amp;rsquo;s registered) and return it to the caller. If we don&amp;rsquo;t find the type, we generate a view with an appropriate &amp;ldquo;not found&amp;rdquo; message.&lt;/p&gt;
&lt;p&gt;Now, back to that &amp;ldquo;context&amp;rdquo; 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 &amp;ldquo;View&amp;rdquo; from the end and appending the context instead. So, given a context of &amp;ldquo;Master&amp;rdquo; our ViewModels.CustomerViewModel would become Views.Customer.Master.&lt;/p&gt;
&lt;h3&gt;Other Things To Know&lt;/h3&gt;
&lt;p&gt;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&amp;rsquo;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&amp;rsquo;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&amp;rsquo;s type to LocateForModelType.&lt;/p&gt;
&lt;h3&gt;Customization&lt;/h3&gt;
&lt;p&gt;The out-of-the-box convention is pretty simple and based on a number of patterns we&amp;rsquo;ve used and seen others use in the real world. However, by no means are you limited to these simple patterns. You&amp;rsquo;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.&lt;sup&gt;3&lt;/sup&gt;&lt;/p&gt;
&lt;h3&gt;Framework Usage&lt;/h3&gt;
&lt;p&gt;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&amp;lt;T&amp;gt;. Here, your root ViewModel is passed to the locator in order to determine how your application&amp;rsquo;s shell should be rendered.&amp;nbsp; 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&amp;hellip; 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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;ViewModel Resolution (View-First) &lt;/h2&gt;
&lt;h3&gt;Basics&lt;/h3&gt;
&lt;p&gt;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&amp;rsquo;s take a look at ViewModelLocator.LocateForViewType:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public static Func&amp;lt;Type, object&amp;gt; LocateForViewType = viewType =&amp;gt;{
    var typeName = viewType.FullName;

    if(!typeName.EndsWith(&amp;quot;View&amp;quot;))
        typeName += &amp;quot;View&amp;quot;;

    var viewModelName = typeName.Replace(&amp;quot;View&amp;quot;, &amp;quot;ViewModel&amp;quot;);
    var key = viewModelName.Substring(viewModelName.LastIndexOf(&amp;quot;.&amp;quot;) + 1);

    return IoC.GetInstance(null, key);
};&lt;/pre&gt;
&lt;p&gt;While with View location we change instances of &amp;ldquo;ViewModel&amp;rdquo; to &amp;ldquo;View&amp;rdquo;, with ViewModel location we change &amp;ldquo;View&amp;rdquo; to &amp;ldquo;ViewModel.&amp;rdquo; 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&amp;rsquo;t pull them from the container by type. Instead we pull them by key, using just the derived name, minus all the namespace stuff.&lt;/p&gt;
&lt;h3&gt;Other Things To Know&lt;/h3&gt;
&lt;p&gt;ViewModelLocator.LocateForViewType is actually never called directly by the framework. It&amp;rsquo;s called internally by ViewModelLocator.LocateForView. LocateForView first checks your View instance&amp;rsquo;s DataContext to see if you&amp;rsquo;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.&lt;/p&gt;
&lt;h3&gt;Customization&lt;/h3&gt;
&lt;p&gt;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&amp;rsquo;t really require that much code to map one thing to another.&lt;/p&gt;
&lt;h3&gt;Framework Usage&lt;/h3&gt;
&lt;p&gt;The ViewModelLocator is only used by the WP7 version of the framework. It&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;ViewModelBinder&lt;/h2&gt;
&lt;h3&gt;Basics&lt;/h3&gt;
&lt;p&gt;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.&lt;sup&gt;4&lt;/sup&gt; 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.&lt;/p&gt;
&lt;h3&gt;Other Things To Know&lt;/h3&gt;
&lt;p&gt;On the WP7 platform, if the View you are binding is a PhoneApplicationPage, this service is responsible for wiring up actions to the ApplicationBar&amp;rsquo;s Buttons and Menus. See the &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/wikipage?title=Working%20with%20Windows%20Phone%207&amp;amp;referringTitle=Documentation"&gt;WP7 specific docs&lt;/a&gt; for more information on that.&lt;/p&gt;
&lt;h3&gt;Customization&lt;/h3&gt;
&lt;p&gt;Should you decide that you don&amp;rsquo;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&amp;rsquo;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.&lt;/p&gt;
&lt;h3&gt;Framework Usage&lt;/h3&gt;
&lt;p&gt;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&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Element Location&lt;/h2&gt;
&lt;h3&gt;Basics&lt;/h3&gt;
&lt;p&gt;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 &amp;ldquo;searches the UI for a list of &lt;em&gt;element candidates&lt;/em&gt; for bindings/actions and compares that against the properties and methods of your ViewModel.&amp;rdquo; 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.&lt;sup&gt;5&lt;/sup&gt; 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 &amp;ldquo;outer&amp;rdquo; borders of the scope, it begins it&amp;rsquo;s second task: locating all elements in that scope that have names. The search is careful to respect an &amp;ldquo;inner&amp;rdquo; 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.&lt;/p&gt;
&lt;h3&gt;Other Things To Know&lt;/h3&gt;
&lt;p&gt;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&amp;rsquo;t in the visual tree or one of these special locations won&amp;rsquo;t get found when trying to apply conventions.&lt;/p&gt;
&lt;h3&gt;Customization&lt;/h3&gt;
&lt;p&gt;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&amp;rsquo;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&amp;rsquo;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&amp;rsquo;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.&lt;sup&gt;6&lt;/sup&gt;&lt;/p&gt;
&lt;h3&gt;Framework Usage&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Action Matching&lt;/h2&gt;
&lt;h3&gt;Basics&lt;/h3&gt;
&lt;p&gt;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&amp;rsquo;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.&lt;/p&gt;
&lt;h3&gt;Other Things To Know&lt;/h3&gt;
&lt;p&gt;The conventional actions are created by setting the Message.Attach attached property on the element. Let&amp;rsquo;s look at how that is built up:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;var message = method.Name;
var parameters = method.GetParameters();

if(parameters.Length &amp;gt; 0)
{
    message += &amp;quot;(&amp;quot;;

    foreach(var parameter in parameters)
    {
        var paramName = parameter.Name;
        var specialValue = &amp;quot;$&amp;quot; + paramName.ToLower();

        if(MessageBinder.SpecialValues.Contains(specialValue))
            paramName = specialValue;

        message += paramName + &amp;quot;,&amp;quot;;
    }

    message = message.Remove(message.Length - 1, 1);
    message += &amp;quot;)&amp;quot;;
}

Log.Info(&amp;quot;Added convention action for {0} as {1}.&amp;quot;, method.Name, message);
Message.SetAttach(foundControl, message);&lt;/pre&gt;
&lt;p&gt;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 &amp;ldquo;$&amp;rdquo; to it so that it will be recognized correctly by the Parser and later by the MessageBinder when the action is invoked.&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;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&amp;rsquo;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.&lt;/p&gt;
&lt;h3&gt;Customization&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;Framework Usage&lt;/h3&gt;
&lt;p&gt;BindActions is used exclusively by the ViewModelBinder.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Property Matching&lt;/h2&gt;
&lt;h3&gt;Basics&lt;/h3&gt;
&lt;p&gt;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&amp;rsquo;s called SetBinding and looks like this:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public static Func&amp;lt;Type, string, PropertyInfo, FrameworkElement, ElementConvention, bool&amp;gt; SetBinding =
    (viewModelType, path, property, element, convention) =&amp;gt; {
        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;
    };&lt;/pre&gt;
&lt;p&gt;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&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another important aspect to property matching that I haven&amp;rsquo;t yet mentioned. We can match on deep property paths by convention as well. So, let&amp;rsquo;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 &amp;ldquo;Customer_FirstName&amp;rdquo; 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&amp;rsquo;s ApplyBinding func.&lt;/p&gt;
&lt;h3&gt;Other Things To Know&lt;/h3&gt;
&lt;p&gt;I mentioned above that &amp;ldquo;CM defines a basic implementation of ApplyBinding for most elements.&amp;rdquo; 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&amp;rsquo;t specified a renderer for the items, it should add one conventionally.&lt;sup&gt;7&lt;/sup&gt; So, we set the ItemTemplate to a default DataTemplate. Here&amp;rsquo;s what it looks like:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;DataTemplate xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
              xmlns:cal=&amp;quot;clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro&amp;quot;&amp;gt;
    &amp;lt;ContentControl cal:View.Model=&amp;quot;{Binding}&amp;quot; 
                    VerticalContentAlignment=&amp;quot;Stretch&amp;quot;
                    HorizontalContentAlignment=&amp;quot;Stretch&amp;quot; /&amp;gt;
&amp;lt;/DataTemplate&amp;gt;&lt;/pre&gt;
&lt;p&gt;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&amp;rsquo;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&amp;rsquo;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&amp;rsquo;s name. In this case &amp;ldquo;Items&amp;rdquo; becomes &amp;ldquo;Item&amp;rdquo; Then we call ConventionManager.DerivePotentialSelectionNames which prepends &amp;ldquo;Active&amp;rdquo; &amp;ldquo;Selected&amp;rdquo; and &amp;ldquo;Current&amp;rdquo; to &amp;ldquo;Item&amp;rdquo; 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.&lt;sup&gt;8&lt;/sup&gt; It takes on all the conventions of Selector (setting it&amp;rsquo;s ContentTemplate instead of ItemTemplate to the DefaultDataTemplate), plus an additional convention for the tab header&amp;rsquo;s content. If the TabControl&amp;rsquo;s DisplayMemberPath is not set and the ViewModel implements IHaveDisplayName, then we set it&amp;rsquo;s ItemTemplate to the DefaultHeaderTemplate, which looks like this:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;DataTemplate xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;&amp;gt;
    &amp;lt;TextBlock Text=&amp;quot;{Binding DisplayName, Mode=TwoWay}&amp;quot; /&amp;gt;
&amp;lt;/DataTemplate&amp;gt;&lt;/pre&gt;
&lt;p&gt;So, for a named WPF TabControl we can conventionally bind in the list of tabs (ItemsSource), the tab item&amp;rsquo;s name (ItemTemplate), the content for each tab (ContentTemplate) and keep the selected tab synchronized with the model (SelectedItem). That&amp;rsquo;s not bad for one line of Xaml like this:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;TabControl x:Name=&amp;quot;Items&amp;quot; /&amp;gt;&lt;/pre&gt;
&lt;p&gt;In addition to the special cases listed above, we have one more that is important: ContentControl. In this case, we don&amp;rsquo;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&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;I hope you will find that these special cases make sense when you think about them. As always, if you don&amp;rsquo;t like them, you can change them&amp;hellip;&lt;/p&gt;
&lt;h3&gt;Customization&lt;/h3&gt;
&lt;p&gt;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&amp;rsquo;t do anything. However, it&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;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:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;ConventionManager.AddElementConvention&amp;lt;Pivot&amp;gt;(Pivot.ItemsSourceProperty, &amp;quot;SelectedItem&amp;quot;, &amp;quot;SelectionChanged&amp;quot;).ApplyBinding =
    (viewModelType, path, property, element, convention) =&amp;gt; {
        ConventionManager
            .GetElementConvention(typeof(ItemsControl))
            .ApplyBinding(viewModelType, path, property, element, convention);
        ConventionManager
            .ConfigureSelectedItem(element, Pivot.SelectedItemProperty, viewModelType, path);
        ConventionManager
            .ApplyHeaderTemplate(element, Pivot.HeaderTemplateProperty, viewModelType);
    };&lt;/pre&gt;
&lt;p&gt;Pretty cool?&lt;/p&gt;
&lt;h3&gt;Framework Usage&lt;/h3&gt;
&lt;p&gt;BindProperties is used exclusively by the ViewModelBinder.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;ConventionManager&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;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:&lt;/p&gt;
&lt;h3&gt;Properties&lt;/h3&gt;
&lt;p&gt;BooleanToVisibilityConverter &amp;ndash; The default IValueConverter used for converting Boolean to Visibility and back. Used by ApplyValueConverter.&lt;/p&gt;
&lt;p&gt;IncludeStaticProperties - Indicates whether or not static properties should be included during convention name matching. False by default.&lt;/p&gt;
&lt;p&gt;DefaultItemTemplate &amp;ndash; Used when an ItemsControl or ContentControl needs a DataTemplate.&lt;/p&gt;
&lt;p&gt;DefaultHeaderTemplate &amp;ndash; Used by ApplyHeaderTemplate when the TabControl needs a header template.&lt;/p&gt;
&lt;h3&gt;Funcs&lt;/h3&gt;
&lt;p&gt;Singularize &amp;ndash; Turns a word from its plural form to its singular form. The default implementation is really basic and just strips the trailing &amp;lsquo;s&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;DerivePotentialSelectionNames &amp;ndash; Given a base collection name, returns a list of possible property names representing the selection. Uses Singularize.&lt;/p&gt;
&lt;p&gt;SetBinding &amp;ndash; 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:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HasBinding - Determines whether a particular dependency property already has a binding on the provided element. If a binding already exists, SetBinding is aborted.&lt;/li&gt;
&lt;li&gt;ApplyBindingMode - Applies the appropriate binding mode to the binding.&lt;/li&gt;
&lt;li&gt;ApplyValidation - Determines whether or not and what type of validation to enable on the binding.&lt;/li&gt;
&lt;li&gt;ApplyValueConverter - Determines whether a value converter is is needed and applies one to the binding. It only checks for BooleanToVisibility conversion by default.&lt;/li&gt;
&lt;li&gt;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 &amp;quot;{0:MM/dd/yyyy}&amp;quot;.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Methods&lt;/h3&gt;
&lt;p&gt;AddElementConvention &amp;ndash; Adds or replaces an ElementConvention.&lt;/p&gt;
&lt;p&gt;GetElementConvention &amp;ndash; Gets the convention for a particular element type. If not found, searches the type hierarchy for a match.&lt;/p&gt;
&lt;p&gt;ConfigureSelectedItem &amp;ndash; Configures the SelectedItem convention on an element.&lt;/p&gt;
&lt;p&gt;ApplyHeaderTemplate &amp;ndash; Applies the header template convention to an element.&lt;/p&gt;
&lt;p&gt;ApplySilverlightTriggers &amp;ndash; For TextBox and PasswordBox, wires the appropriate events to binding updates in order to simulate WPF&amp;rsquo;s UpdateSourceTrigger=PropertyChanged.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;ElementConvention&lt;/h2&gt;
&lt;p&gt;ElementConventions can be added or replaced through ConventionManager.AddElementConvention. But, it&amp;rsquo;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:&lt;/p&gt;
&lt;h3&gt;Properties&lt;/h3&gt;
&lt;p&gt;ElementType &amp;ndash; The type of element to which the convention applies.&lt;/p&gt;
&lt;p&gt;ParameterProperty &amp;ndash; 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:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;TextBox x:Name=&amp;quot;something&amp;quot; /&amp;gt;
&amp;lt;Button cal:Message.Attach=&amp;quot;MyMethod(something)&amp;quot; /&amp;gt;&lt;/pre&gt;
&lt;p&gt;When the Button&amp;rsquo;s ActionMessage is created, we look up &amp;ldquo;something&amp;rdquo;, which is a TextBox. We get the ElementConvention for TextBox which has its ParameterProperty set to &amp;ldquo;Text.&amp;rdquo; Therefore, we create the parameter for MyMethod from something.Text.&lt;/p&gt;
&lt;h3&gt;Funcs&lt;/h3&gt;
&lt;p&gt;GetBindableProperty &amp;ndash; Gets the property for the element which should be used in convention binding.&lt;/p&gt;
&lt;p&gt;CreateTrigger &amp;ndash; 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&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;ApplyBinding &amp;ndash; As described above, when conventional databinding occurs, the element we are binding has its ElementConvention looked up and it&amp;rsquo;s ApplyBinding func is called. By default this just passes through to ConventionManager.SetBinding. But certain elements (see above&amp;hellip;or below) customize this in order to enable more powerful composition scenarios.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Footnotes&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;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. &lt;/li&gt;
&lt;li&gt;The bootstrapper is responsible for making sure that your application&amp;rsquo;s assembly is added to the AssemblySource, but you can add any additional assemblies by overriding the Bootstrapper&amp;rsquo;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. &lt;/li&gt;
&lt;li&gt;This pattern is borrowed from Javascript and I felt it generally made extensibility simpler for the most common use cases. &lt;/li&gt;
&lt;li&gt;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. &lt;/li&gt;
&lt;li&gt;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. &lt;/li&gt;
&lt;li&gt;Well, I assume this would work. I haven&amp;rsquo;t actually tried it though. &lt;/li&gt;
&lt;li&gt;If your item is a ValueType or a String we don&amp;rsquo;t generate a default DataTemplate. We assume that you want to use the default ToString rendering that the platform provides.&lt;/li&gt;
&lt;li&gt;We don&amp;rsquo;t have this convention in Silverlight because A. TabControl is not part of the core framework and B. Silverlight&amp;rsquo;s TabControl is broken for databinding and has been for two versions of the framework without a fix. Please vote this issue up &lt;a href="http://silverlight.codeplex.com/workitem/3604"&gt;http://silverlight.codeplex.com/workitem/3604&lt;/a&gt; It was reported about a year and a half ago and is not yet fixed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Out-Of-The-Box Element Conventions&lt;/h2&gt;
&lt;p&gt;Following is the full code-listing showing how the built-in controls have their ElementConventions configured out-of-the-box:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;#if SILVERLIGHT
AddElementConvention&amp;lt;HyperlinkButton&amp;gt;(HyperlinkButton.ContentProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Click&amp;quot;);
AddElementConvention&amp;lt;PasswordBox&amp;gt;(PasswordBox.PasswordProperty, &amp;quot;Password&amp;quot;, &amp;quot;PasswordChanged&amp;quot;);
#else
AddElementConvention&amp;lt;PasswordBox&amp;gt;(PasswordBox.DataContextProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;PasswordChanged&amp;quot;);
AddElementConvention&amp;lt;Hyperlink&amp;gt;(Hyperlink.DataContextProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Click&amp;quot;);
AddElementConvention&amp;lt;RichTextBox&amp;gt;(RichTextBox.DataContextProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;TextChanged&amp;quot;);
AddElementConvention&amp;lt;Menu&amp;gt;(Menu.ItemsSourceProperty,&amp;quot;DataContext&amp;quot;, &amp;quot;Click&amp;quot;);
AddElementConvention&amp;lt;MenuItem&amp;gt;(MenuItem.ItemsSourceProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Click&amp;quot;);
AddElementConvention&amp;lt;Label&amp;gt;(Label.ContentProperty, &amp;quot;Content&amp;quot;, &amp;quot;DataContextChanged&amp;quot;);
AddElementConvention&amp;lt;Slider&amp;gt;(Slider.ValueProperty, &amp;quot;Value&amp;quot;, &amp;quot;ValueChanged&amp;quot;);
AddElementConvention&amp;lt;Expander&amp;gt;(Expander.IsExpandedProperty, &amp;quot;IsExpanded&amp;quot;, &amp;quot;Expanded&amp;quot;);
AddElementConvention&amp;lt;StatusBar&amp;gt;(StatusBar.ItemsSourceProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Loaded&amp;quot;);
AddElementConvention&amp;lt;ToolBar&amp;gt;(ToolBar.ItemsSourceProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Loaded&amp;quot;);
AddElementConvention&amp;lt;ToolBarTray&amp;gt;(ToolBarTray.VisibilityProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Loaded&amp;quot;);
AddElementConvention&amp;lt;TreeView&amp;gt;(TreeView.ItemsSourceProperty, &amp;quot;SelectedItem&amp;quot;, &amp;quot;SelectedItemChanged&amp;quot;);
AddElementConvention&amp;lt;TabControl&amp;gt;(TabControl.ItemsSourceProperty, &amp;quot;ItemsSource&amp;quot;, &amp;quot;SelectionChanged&amp;quot;)
    .ApplyBinding = (viewModelType, path, property, element, convention) =&amp;gt; {
        if(!SetBinding(viewModelType, path, property, element, convention))
            return;

        var tabControl = (TabControl)element;
        if(tabControl.ContentTemplate == null &amp;amp;&amp;amp; tabControl.ContentTemplateSelector == null &amp;amp;&amp;amp; property.PropertyType.IsGenericType) {
            var itemType = property.PropertyType.GetGenericArguments().First();
            if(!itemType.IsValueType &amp;amp;&amp;amp; !typeof(string).IsAssignableFrom(itemType))
                tabControl.ContentTemplate = DefaultItemTemplate;
        }

        ConfigureSelectedItem(element, Selector.SelectedItemProperty, viewModelType, path);

        if(string.IsNullOrEmpty(tabControl.DisplayMemberPath))
            ApplyHeaderTemplate(tabControl, TabControl.ItemTemplateProperty, viewModelType);
    };
AddElementConvention&amp;lt;TabItem&amp;gt;(TabItem.ContentProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;DataContextChanged&amp;quot;);
AddElementConvention&amp;lt;Window&amp;gt;(Window.DataContextProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Loaded&amp;quot;);
#endif
AddElementConvention&amp;lt;UserControl&amp;gt;(UserControl.VisibilityProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Loaded&amp;quot;);
AddElementConvention&amp;lt;Image&amp;gt;(Image.SourceProperty, &amp;quot;Source&amp;quot;, &amp;quot;Loaded&amp;quot;);
AddElementConvention&amp;lt;ToggleButton&amp;gt;(ToggleButton.IsCheckedProperty, &amp;quot;IsChecked&amp;quot;, &amp;quot;Click&amp;quot;);
AddElementConvention&amp;lt;ButtonBase&amp;gt;(ButtonBase.ContentProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Click&amp;quot;);
AddElementConvention&amp;lt;TextBox&amp;gt;(TextBox.TextProperty, &amp;quot;Text&amp;quot;, &amp;quot;TextChanged&amp;quot;);
AddElementConvention&amp;lt;TextBlock&amp;gt;(TextBlock.TextProperty, &amp;quot;Text&amp;quot;, &amp;quot;DataContextChanged&amp;quot;);
AddElementConvention&amp;lt;Selector&amp;gt;(Selector.ItemsSourceProperty, &amp;quot;SelectedItem&amp;quot;, &amp;quot;SelectionChanged&amp;quot;)
    .ApplyBinding = (viewModelType, path, property, element, convention) =&amp;gt; {
        if (!SetBinding(viewModelType, path, property, element, convention))
            return;

        ConfigureSelectedItem(element, Selector.SelectedItemProperty,viewModelType, path);
        ConfigureItemsControl((ItemsControl)element, property);
    };
AddElementConvention&amp;lt;ItemsControl&amp;gt;(ItemsControl.ItemsSourceProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Loaded&amp;quot;)
    .ApplyBinding = (viewModelType, path, property, element, convention) =&amp;gt; {
        if (!SetBinding(viewModelType, path, property, element, convention))
            return;

        ConfigureItemsControl((ItemsControl)element, property);
    };
AddElementConvention&amp;lt;ContentControl&amp;gt;(ContentControl.ContentProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Loaded&amp;quot;).GetBindableProperty =
    delegate(DependencyObject foundControl) {
        var element = (ContentControl)foundControl;
#if SILVERLIGHT
        return element.ContentTemplate == null &amp;amp;&amp;amp; !(element.Content is DependencyObject)
            ? View.ModelProperty
            : ContentControl.ContentProperty;
#else
        return element.ContentTemplate == null &amp;amp;&amp;amp; element.ContentTemplateSelector == null &amp;amp;&amp;amp; !(element.Content is DependencyObject)
            ? View.ModelProperty
            : ContentControl.ContentProperty;
#endif
    };
AddElementConvention&amp;lt;Shape&amp;gt;(Shape.VisibilityProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;MouseLeftButtonUp&amp;quot;);
AddElementConvention&amp;lt;FrameworkElement&amp;gt;(FrameworkElement.VisibilityProperty, &amp;quot;DataContext&amp;quot;, &amp;quot;Loaded&amp;quot;);&lt;/pre&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=63987" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/databinding/default.aspx">databinding</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WP7/default.aspx">WP7</category></item><item><title>Caliburn.Micro Soup to Nuts Part 6d – A “Billy Hollis” Hybrid Shell</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2010/11/18/caliburn-micro-soup-to-nuts-part-6d-a-billy-hollis-hybrid-shell.aspx</link><pubDate>Thu, 18 Nov 2010 21:36:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:63478</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>13</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=63478</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2010/11/18/caliburn-micro-soup-to-nuts-part-6d-a-billy-hollis-hybrid-shell.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/HelloScreensSolution_5F00_567419C1.jpg"&gt;&lt;img height="484" width="246" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/HelloScreensSolution_5F00_thumb_5F00_41F15AF4.jpg" align="right" alt="HelloScreensSolution" border="0" title="HelloScreensSolution" style="background-image:none;border-right-width:0px;margin:0px 6px 6px 0px;padding-left:0px;padding-right:0px;display:inline;float:right;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" /&gt;&lt;/a&gt;Up until now I&amp;rsquo;ve been focusing on fairly simple usage of Screens and Conductors. In this article, I want to show something a bit more sophisticated. This sample is based loosely on the ideas demonstrated by Billy Hollis in &lt;a target="_blank" href="http://www.dnrtv.com/default.aspx?showNum=115"&gt;this well-known DNR TV episode&lt;/a&gt;.&amp;nbsp; Rather than take the time to explain what the UI does, &lt;a target="_blank" href="http://vimeo.com/16975621"&gt;have a look at this short video for a brief visual explanation&lt;/a&gt; (apologies for the audio level).&lt;/p&gt;
&lt;p&gt;Ok, now that you&amp;rsquo;ve seen what it does, let&amp;rsquo;s look at how it&amp;rsquo;s put together. As you can see from the screenshot, I&amp;rsquo;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 &amp;ldquo;technical&amp;rdquo; groupings, such as Views and ViewModels. If I have a complex feature, then I might break that down into those areas.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not going to go line-by-line through this sample. It&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ViewModel Composition&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One of the most important features of Screens and Conductors in Caliburn.Micro is that they are an implementation of &lt;a target="_blank" href="http://en.wikipedia.org/wiki/Composite_pattern"&gt;the Composite Pattern&lt;/a&gt;, 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&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Editing a Customer&amp;rsquo;s Address&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/Composition_5F00_03F7CA36.png"&gt;&lt;img height="484" width="621" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/Composition_5F00_thumb_5F00_5BE7ABC7.png" alt="Composition" border="0" title="Composition" style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Editing a Customer&amp;rsquo;s Address (3D Breakout)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/Composition_2D00_3d_2D00_01_5F00_54CB0000.png"&gt;&lt;img height="484" width="621" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/Composition_2D00_3d_2D00_01_5F00_thumb_5F00_687A7A45.png" alt="Composition-3d-01" border="0" title="Composition-3d-01" style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this application, the ShellViewModel is a Conductor&amp;lt;IWorkspace&amp;gt;.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&amp;rsquo;s view is shown at that location. In this case, it&amp;rsquo;s the CustomerWorkspaceViewModel that is active.&amp;nbsp; It so happens that the CustomerWorkspaceViewModel inherits from Conductor&amp;lt;CustomerViewModel&amp;gt;.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&amp;rsquo;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&amp;rsquo;s ActiveItem is not null. In the state depicted above, the DialogConductor&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multiple Views over the Same ViewModel&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;s injection site. Here&amp;rsquo;s an example from the default CustomerWorkspaceView:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;clt:TransitioningContentControl cal:View.Context=&amp;quot;{Binding State, Mode=TwoWay}&amp;quot;
                                 cal:View.Model=&amp;quot;{Binding}&amp;quot; 
                                 Style=&amp;#39;{StaticResource specialTransition}&amp;#39;/&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;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 &amp;ldquo;Master&amp;rdquo; view, where it displays all open CustomerViewModels, a search UI and a New button, to a &amp;ldquo;Detail&amp;rdquo; view, where it displays the currently activated CustomerViewModel along with it&amp;rsquo;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 &amp;ldquo;View&amp;rdquo; and &amp;ldquo;Model&amp;rdquo;, 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&amp;rsquo;s going to look for Caliburn.Micro.HelloScreens.Customers.CustomersWorkspace.Detail That&amp;rsquo;s the out-of-the-box naming convention. If that doesn&amp;rsquo;t work for you, you can simply customize the ViewLocator.LocateForModelType func.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Custom IConductor Implementation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Although Caliburn.Micro provides the developer with default implementations of IScreen and IConductor. It&amp;rsquo;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&amp;lt;T&amp;gt; would work, but I discovered I needed to fine-tune shutdown sequence, so I implemented my own. Let&amp;rsquo;s take a look at that:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;[Export(typeof(IDialogManager)), PartCreationPolicy(CreationPolicy.NonShared)]
public class DialogConductorViewModel : PropertyChangedBase, IDialogManager, IConductor {
    readonly Func&amp;lt;IMessageBox&amp;gt; createMessageBox;

    [ImportingConstructor]
    public DialogConductorViewModel(Func&amp;lt;IMessageBox&amp;gt; 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&amp;lt;IConductor&amp;gt;;
        if(child != null)
            child.Parent = this;

        if(ActiveItem != null)
            ActiveItem.Activate();

        NotifyOfPropertyChange(() =&amp;gt; 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 =&amp;gt; {
                if(result)
                    CloseActiveItemCore();
            });
        }
        else CloseActiveItemCore();
    }

    object IConductor.ActiveItem {
        get { return ActiveItem; }
        set { ActivateItem(value); }
    }

    public event EventHandler&amp;lt;ActivationProcessedEventArgs&amp;gt; ActivationProcessed = delegate { };

    public void ShowDialog(IScreen dialogModel) {
        ActivateItem(dialogModel);
    }

    public void ShowMessageBox(string message, string title = null, MessageBoxOptions options = MessageBoxOptions.Ok, Action&amp;lt;IMessageBox&amp;gt; callback = null) {
        var box = createMessageBox();

        box.DisplayName = title ?? &amp;quot;Hello Screens&amp;quot;;
        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);
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Strictly speaking, I didn&amp;rsquo;t actually need to implement IConductor to make this work (since I&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Custom ICloseStrategy&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;s MainWindow.Closing event to call IShell.CanClose:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;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(() =&amp;gt; {
        var shell = IoC.Get&amp;lt;IShell&amp;gt;();

        shell.CanClose(result =&amp;gt; {
            if(result) {
                actuallyClosing = true;
                mainWindow.Close();
            }
        });
    });
}&lt;/pre&gt;
&lt;p&gt;The ShellViewModel inherits this functionality through its base class Conductor&amp;lt;IWorkspace&amp;gt;.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&amp;rsquo;s how we plug in our custom strategy:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;[Export(typeof(IShell))]
public class ShellViewModel : Conductor&amp;lt;IWorkspace&amp;gt;.Collection.OneActive, IShell
{
    readonly IDialogManager dialogs;

    [ImportingConstructor]
    public ShellViewModel(IDialogManager dialogs, [ImportMany]IEnumerable&amp;lt;IWorkspace&amp;gt; workspaces) {
        this.dialogs = dialogs;
        Items.AddRange(workspaces);
        CloseStrategy = new ApplicationCloseStrategy();
    }

    public IDialogManager Dialogs {
        get { return dialogs; }
    }
}&lt;/pre&gt;
&lt;p&gt;And here&amp;rsquo;s the implementation of that strategy:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class ApplicationCloseStrategy : ICloseStrategy&amp;lt;IWorkspace&amp;gt; {
    IEnumerator&amp;lt;IWorkspace&amp;gt; enumerator;
    bool finalResult;
    Action&amp;lt;bool, IEnumerable&amp;lt;IWorkspace&amp;gt;&amp;gt; callback;

    public void Execute(IEnumerable&amp;lt;IWorkspace&amp;gt; toClose, Action&amp;lt;bool, IEnumerable&amp;lt;IWorkspace&amp;gt;&amp;gt; callback) {
        enumerator = toClose.GetEnumerator();
        this.callback = callback;
        finalResult = true;

        Evaluate(finalResult);
    }

    void Evaluate(bool result)
    {
        finalResult = finalResult &amp;amp;&amp;amp; result;

        if (!enumerator.MoveNext() || !result)
            callback(finalResult, new List&amp;lt;IWorkspace&amp;gt;());
        else
        {
            var current = enumerator.Current;
            var conductor = current as IConductor;
            if (conductor != null)
            {
                var tasks = conductor.GetConductedItems()
                    .OfType&amp;lt;IHaveShutdownTask&amp;gt;()
                    .Select(x =&amp;gt; x.GetShutdownTask())
                    .Where(x =&amp;gt; x != null);

                var sequential = new SequentialResult(tasks.GetEnumerator());
                sequential.Completed += (s, e) =&amp;gt; {
                    if(!e.WasCancelled)
                    Evaluate(!e.WasCancelled);
                };
                sequential.Execute(new ActionExecutionContext());
            }
            else Evaluate(true);
        }
    }
}&lt;/pre&gt;
&lt;p&gt;The interesting thing I did here was to reuse the IResult functionality for async shutdown of the application. Here&amp;rsquo;s how the custom strategy uses it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check each IWorkspace to see if it is an IConductor.&lt;/li&gt;
&lt;li&gt;If true, grab all the conducted items which implement the application-specific interface IHaveShutdownTask.&lt;/li&gt;
&lt;li&gt;Retrieve the shutdown task by calling GetShutdownTask. It will return null if there is no task, so filter those out.&lt;/li&gt;
&lt;li&gt;Since the shutdown task is an IResult, pass all of these to a SequentialResult and begin enumeration.&lt;/li&gt;
&lt;li&gt;The IResult can set ResultCompletionEventArgs.WasCanceled to true to cancel the application shutdown.&lt;/li&gt;
&lt;li&gt;Continue through all workspaces until finished or cancellation occurs.&lt;/li&gt;
&lt;li&gt;If all IResults complete successfully, the application will be allowed to close.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;This concludes our short mini-series on Screens and Conductors. I hope I have provided enough theory, documentation and samples to get you going in the right direction. That said, if you don&amp;rsquo;t understand these concepts or don&amp;rsquo;t see the problems in your app that these were intended to solve, then don&amp;rsquo;t use them. Screens/Conductors are best used when you encounter the sorts of engineering difficulties that they were intended for. Simply inheriting willy-nilly from these base classes will likely add unnecessary complexity to your application. As always, use every feature &lt;em&gt;intentionally&lt;/em&gt; to solve a specific problem&amp;hellip;not just because it&amp;rsquo;s there &lt;img src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/wlEmoticon_2D00_smile_5F00_33707BC6.png" alt="Smile" class="wlEmoticon wlEmoticon-smile" style="border-bottom-style:none;border-left-style:none;border-top-style:none;border-right-style:none;" /&gt; If in doubt, avoid Screens/Conductors. When the need arises, you&amp;rsquo;ll know what they are and where to use them.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Next Up: All About Conventions&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=63478" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.06.34.78/Caliburn.Micro.HelloScreens.zip" length="206682" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/databinding/default.aspx">databinding</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MEF/default.aspx">MEF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WP7/default.aspx">WP7</category></item><item><title>Caliburn.Micro Soup to Nuts Part 6c – Simple MDI with Screen Collections</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2010/10/19/caliburn-micro-soup-to-nuts-part-6c-simple-mdi-with-screen-collections.aspx</link><pubDate>Tue, 19 Oct 2010 20:51:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:62933</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=62933</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2010/10/19/caliburn-micro-soup-to-nuts-part-6c-simple-mdi-with-screen-collections.aspx#comments</comments><description>&lt;p&gt;Let&amp;rsquo;s look at another example: this time a simple MDI shell that uses &amp;ldquo;Screen Collections.&amp;rdquo; As you can see, once again, I have kept things pretty small and simple:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/SimpleMdiProject_5F00_35A88333.jpg"&gt;&lt;img height="162" width="244" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/SimpleMdiProject_5F00_thumb_5F00_1E7D08B5.jpg" alt="SimpleMdiProject" border="0" title="SimpleMdiProject" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a screenshot of the application when it&amp;rsquo;s running:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/SimpleMdiScreenshot_5F00_24C3DF43.jpg"&gt;&lt;img height="210" width="244" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/SimpleMdiScreenshot_5F00_thumb_5F00_1FE12B87.jpg" alt="SimpleMdiScreenshot" border="0" title="SimpleMdiScreenshot" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Here we have a simple WPF application with a series of tabs. Clicking the &amp;ldquo;Open Tab&amp;rdquo; button does the obvious. Clicking the &amp;ldquo;X&amp;rdquo; inside the tab will close that particular tab (also, probably obvious). Let&amp;rsquo;s dig into the code by looking at our ShellViewModel:    &lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class ShellViewModel : Conductor&amp;lt;IScreen&amp;gt;.Collection.OneActive {
    int count = 1;

    public void OpenTab() {
        ActivateItem(new TabViewModel {
            DisplayName = &amp;quot;Tab &amp;quot; + count++
        });
    }
}&lt;/pre&gt;
&lt;p&gt;Since we want to maintain a list of open items, but only keep one item active at a time, we use &lt;em&gt;Conductor&amp;lt;T&amp;gt;.Collection.OneActive&lt;/em&gt; as our base class. Note that, different from our previous example, I am actually constraining the type of the conducted item to &lt;em&gt;IScreen&lt;/em&gt;. There&amp;rsquo;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 &lt;em&gt;DisplayName&lt;/em&gt; property (from &lt;em&gt;IScreen&lt;/em&gt;) so that it has a human-readable, unique name. Let&amp;rsquo;s think through the logic for the interaction between the conductor and its screens in several key scenarios:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Opening the First Item&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Adds the item to the Items collection.&lt;/li&gt;
&lt;li&gt;Checks the item for IActivate and invokes it if present.&lt;/li&gt;
&lt;li&gt;Sets the item as the ActiveItem.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Opening an Additional Item&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Checks the current ActiveItem for IDeactivate and invokes if present. &lt;em&gt;False &lt;/em&gt;is passed to indicate that it should be deactivated only, and not closed.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;Checks the item for IActivate and invokes if present.&lt;/li&gt;
&lt;li&gt;Sets the new item as the ActiveItem.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Closing an Existing Item&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;Checks to see if the closing item is the current ActiveItem. If so, determine which item to activate next and follow steps from &amp;ldquo;Opening an Additional Item.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Checks to see if the closing item is IDeactivate. If so, invoke with &lt;em&gt;true&lt;/em&gt; to indicate that it should be deactivated and closed.&lt;/li&gt;
&lt;li&gt;Remove the item from the Items collection.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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&amp;rsquo;s see how the ShellView renders:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;Window x:Class=&amp;quot;Caliburn.Micro.SimpleMDI.ShellView&amp;quot;
        xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
        xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
        xmlns:cal=&amp;quot;http://www.caliburnproject.org&amp;quot;
        Width=&amp;quot;640&amp;quot;
        Height=&amp;quot;480&amp;quot;&amp;gt;
    &amp;lt;DockPanel&amp;gt;
        &amp;lt;Button x:Name=&amp;quot;OpenTab&amp;quot;
                Content=&amp;quot;Open Tab&amp;quot; 
                DockPanel.Dock=&amp;quot;Top&amp;quot; /&amp;gt;
        &amp;lt;TabControl x:Name=&amp;quot;Items&amp;quot;&amp;gt;
            &amp;lt;TabControl.ItemTemplate&amp;gt;
                &amp;lt;DataTemplate&amp;gt;
                    &amp;lt;StackPanel Orientation=&amp;quot;Horizontal&amp;quot;&amp;gt;
                        &amp;lt;TextBlock Text=&amp;quot;{Binding DisplayName}&amp;quot; /&amp;gt;
                        &amp;lt;Button Content=&amp;quot;X&amp;quot;
                                cal:Message.Attach=&amp;quot;CloseItem($dataContext)&amp;quot; /&amp;gt;
                    &amp;lt;/StackPanel&amp;gt;
                &amp;lt;/DataTemplate&amp;gt;
            &amp;lt;/TabControl.ItemTemplate&amp;gt;
        &amp;lt;/TabControl&amp;gt;
    &amp;lt;/DockPanel&amp;gt;
&amp;lt;/Window&amp;gt;&lt;/pre&gt;
&lt;p&gt;As you can see we are using a WPF TabControl. CM&amp;rsquo;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&amp;rsquo;ve opted to override that by supplying my own to enable closing the tabs. We&amp;rsquo;ll talk more in depth about conventions in a later article. For completeness, here are the trivial implementations of TabViewModel along with its view:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;namespace Caliburn.Micro.SimpleMDI {
    public class TabViewModel : Screen {}
}&lt;/pre&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.SimpleMDI.TabView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&amp;gt;
    &amp;lt;StackPanel Orientation=&amp;quot;Horizontal&amp;quot;&amp;gt;
        &amp;lt;TextBlock Text=&amp;quot;This is the view for &amp;quot;/&amp;gt;
        &amp;lt;TextBlock x:Name=&amp;quot;DisplayName&amp;quot; /&amp;gt;
        &amp;lt;TextBlock Text=&amp;quot;.&amp;quot; /&amp;gt;
    &amp;lt;/StackPanel&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;ve tried to keep it simple so far, but that&amp;rsquo;s not the case for our next sample. In preparation, you might want to at least think through or try to do these things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get rid of the generic TabViewModel. You wouldn&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;Rebuild this sample in Silverlight. Unfortunately, Silverlight&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;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&amp;rsquo;t require explicit code in the OnDeactivate override. HINT: Use the events.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;/ol&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=62933" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.06.29.33/Caliburn.Micro.SimpleMDI.zip" length="10739" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/databinding/default.aspx">databinding</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WP7/default.aspx">WP7</category></item><item><title>Caliburn.Micro Soup to Nuts Part 6b – Simple Navigation with Conductors</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2010/10/12/caliburn-micro-soup-to-nuts-part-6b-simple-navigation-with-conductors.aspx</link><pubDate>Tue, 12 Oct 2010 15:38:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:62792</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=62792</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2010/10/12/caliburn-micro-soup-to-nuts-part-6b-simple-navigation-with-conductors.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/SimpleNavigationProject_5F00_67C2FB8A.jpg"&gt;&lt;img height="222" width="244" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/SimpleNavigationProject_5F00_thumb_5F00_3EBAED3F.jpg" align="right" alt="SimpleNavigationProject" border="0" title="SimpleNavigationProject" style="border-right-width:0px;margin:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt;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&amp;lt;T&amp;gt; and two &amp;ldquo;Page&amp;rdquo; 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&amp;rsquo;m not even using an IoC container with the Bootstrapper. Let&amp;rsquo;s look at the ShellViewModel first. It inherits from Conductor&amp;lt;object&amp;gt; and is implemented as follows:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class ShellViewModel : Conductor&amp;lt;object&amp;gt; {
    public ShellViewModel() {
        ShowPageOne();
    }

    public void ShowPageOne() {
        ActivateItem(new PageOneViewModel());
    }

    public void ShowPageTwo() {
        ActivateItem(new PageTwoViewModel());
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Here is the corresponding ShellView:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.SimpleNavigation.ShellView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
             xmlns:tc=&amp;quot;clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit&amp;quot;&amp;gt;
    &amp;lt;tc:DockPanel&amp;gt;
        &amp;lt;StackPanel Orientation=&amp;quot;Horizontal&amp;quot;
                    HorizontalAlignment=&amp;quot;Center&amp;quot;
                    tc:DockPanel.Dock=&amp;quot;Top&amp;quot;&amp;gt;
            &amp;lt;Button x:Name=&amp;quot;ShowPageOne&amp;quot;
                    Content=&amp;quot;Show Page One&amp;quot; /&amp;gt;
            &amp;lt;Button x:Name=&amp;quot;ShowPageTwo&amp;quot;
                    Content=&amp;quot;Show Page Two&amp;quot; /&amp;gt;
        &amp;lt;/StackPanel&amp;gt;

        &amp;lt;ContentControl x:Name=&amp;quot;ActiveItem&amp;quot; /&amp;gt;
    &amp;lt;/tc:DockPanel&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt;Notice that the ShellViewModel has two methods, each of which passes a view model instance to the &lt;em&gt;ActivateItem&lt;/em&gt; method. Recall from our earlier discussion that &lt;em&gt;ActivateItem&lt;/em&gt; is a method on &lt;em&gt;Conductor&amp;lt;T&amp;gt;&lt;/em&gt; which will switch the &lt;em&gt;ActiveItem&lt;/em&gt; 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 &lt;em&gt;IActivate&lt;/em&gt;). Recall also, that if &lt;em&gt;ActiveItem&lt;/em&gt; is already set to an instance, then before the new instance is set, the previous instance will be checked for an implementation of &lt;em&gt;IGuardClose&lt;/em&gt; which may or may not cancel switching of the &lt;em&gt;ActiveItem&lt;/em&gt;. Assuming the current &lt;em&gt;ActiveItem&lt;/em&gt; can close, the conductor will then push it through the deactivation stage of the lifecycle, passing true to the &lt;em&gt;Deactivate&lt;/em&gt; 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 &lt;em&gt;ActiveItem&lt;/em&gt; of the conductor represents the &amp;ldquo;current page&amp;rdquo; 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&amp;rsquo;s child view models that are driving the navigation and not the &amp;ldquo;views.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Once the basic Conductor structure is in place, it&amp;rsquo;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 &amp;ldquo;ActiveItem&amp;rdquo; 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&amp;rsquo;s custom attached property: View.Model. This property causes CM&amp;rsquo;s &lt;em&gt;ViewLocator&lt;/em&gt; to look up the appropriate view for the view model and CM&amp;rsquo;s &lt;em&gt;ViewModelBinder&lt;/em&gt; to bind the two together. Once that is complete, we pop the view into the ContentControl&amp;rsquo;s Content property. This single convention is what enables the powerful, yet simple ViewModel-First composition in the framework.&lt;/p&gt;
&lt;p&gt;For completeness, let&amp;rsquo;s take a look at the PageOneViewModel and PageTwoViewModel:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class PageOneViewModel {}

public class PageTwoViewModel : Screen {
    protected override void OnActivate() {
        MessageBox.Show(&amp;quot;Page Two Activated&amp;quot;); //Don&amp;#39;t do this in a real VM.
        base.OnActivate();
    }
}&lt;/pre&gt;
&lt;p&gt;Along with their views:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.SimpleNavigation.PageOneView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&amp;gt;
    &amp;lt;TextBlock FontSize=&amp;quot;32&amp;quot;&amp;gt;Page One&amp;lt;/TextBlock&amp;gt;
&amp;lt;/UserControl&amp;gt;

&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.SimpleNavigation.PageTwoView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&amp;gt;
    &amp;lt;TextBlock FontSize=&amp;quot;32&amp;quot;&amp;gt;Page Two&amp;lt;/TextBlock&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;ve intentionally kept this bare bones so that it&amp;rsquo;s easy to play around with and see how these pieces work together. It&amp;rsquo;s not the slightest bit impressive, but here&amp;rsquo;s what it looks like:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/PageTwo_5F00_4501C3CD.jpg"&gt;&lt;img height="228" width="244" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/PageTwo_5F00_thumb_5F00_752B9F41.jpg" alt="PageTwo" border="0" title="PageTwo" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like to point out a few final things. Notice that PageOneViewModel is just a POCO, but PageTwoViewModel inherits from &lt;em&gt;Screen&lt;/em&gt;. Remember that the conductors in CM don&amp;rsquo;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 &lt;em&gt;ActivateItem&lt;/em&gt; is called for PageTwoViewModel, it will first check PageOneViewModel to see if it implements &lt;em&gt;IGuardClose&lt;/em&gt;. Since it does not, it will attempt to close it. It will then check to see if it implements &lt;em&gt;IDeactivate&lt;/em&gt;. Since it does not, it will just proceed to activate the new item. First it checks if the new item implements &lt;em&gt;IChild&amp;lt;IConductor&amp;gt;.&lt;/em&gt; Since &lt;em&gt;Screen&lt;/em&gt; does, it hooks up the hierarchical relationship. Next, it will check PageTwoViewModel to see if it implements &lt;em&gt;IActivate&lt;/em&gt;. Since &lt;em&gt;Screen&lt;/em&gt; does, the code in my &lt;em&gt;OnActivate&lt;/em&gt; method will then run. Finally, it will set the &lt;em&gt;ActiveItem&lt;/em&gt; property on the conductor and raise the appropriate events. Here&amp;rsquo;s an important consequence of this that should be remembered: The activation is a ViewModel-specific lifecycle process and doesn&amp;rsquo;t guarantee anything about the state of the View. Many times, even though your ViewModel has been activated, it&amp;rsquo;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 &lt;em&gt;Screen.OnViewLoaded&lt;/em&gt; instead of/in combination with &lt;em&gt;OnActivate&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned, more samples to come&amp;hellip;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=62792" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.06.27.92/Caliburn.Micro.SimpleNavigation.zip" length="8209" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/databinding/default.aspx">databinding</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WP7/default.aspx">WP7</category></item><item><title>Caliburn.Micro Soup to Nuts Pt. 4 – Working with Windows Phone 7</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2010/08/07/caliburn-micro-soup-to-nuts-pt-4-working-with-windows-phone-7.aspx</link><pubDate>Sun, 08 Aug 2010 02:42:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:61412</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=61412</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2010/08/07/caliburn-micro-soup-to-nuts-pt-4-working-with-windows-phone-7.aspx#comments</comments><description>&lt;p&gt;Hopefully, previous articles have you up to speed on &lt;a target="_blank" href="http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/04/mvvm-study-segue-introducing-caliburn-micro.aspx"&gt;what Caliburn.Micro is&lt;/a&gt;, &lt;a target="_blank" href="http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/06/caliburn-micro-soup-to-nuts-pt-1-configuration-actions-and-conventions.aspx"&gt;its basic configuration&lt;/a&gt;, and how to take advantage of &lt;a target="_blank" href="http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/17/caliburn-micro-soup-to-nuts-pt-3-all-about-actions.aspx"&gt;a few of its features&lt;/a&gt;. In this part, I want to talk about some WP7 specifics issues. It&amp;rsquo;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&amp;rsquo;t make WP7 development a snap. Microsoft still has a long ways to go in making &amp;ldquo;three screens and the cloud&amp;rdquo; 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 and Launchers/Choosers.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bootstrapper&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;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&amp;rsquo;s how the bootstrapper for our WP7 sample application looks:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;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), &amp;quot;MainPageViewModel&amp;quot;, typeof(MainPageViewModel));
        container.RegisterSingleton(typeof(PageTwoViewModel), &amp;quot;PageTwoViewModel&amp;quot;, 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&amp;lt;PhoneNumberChooserTask, PhoneNumberResult&amp;gt;();
        container.Activator.InstallLauncher&amp;lt;EmailComposeTask&amp;gt;();
    }

    protected override object GetInstance(Type service, string key)
    {
        return container.GetInstance(service, key);
    }

    protected override IEnumerable&amp;lt;object&amp;gt; GetAllInstances(Type service)
    {
        return container.GetAllInstances(service);
    }

    protected override void BuildUp(object instance)
    {
        container.BuildUp(instance);
    }
}&lt;/pre&gt;
&lt;p&gt;For WP7, there are less IoC container options available. In this case, I&amp;rsquo;ve written a simple container myself. You can &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/wikipage?title=SimpleContainer&amp;amp;referringTitle=Documentation"&gt;get the full code for SimpleContainer&lt;/a&gt; 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&amp;rsquo;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&amp;rsquo;s what they should look like:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;Application x:Class=&amp;quot;Caliburn.Micro.HelloWP7.App&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
             xmlns:local=&amp;quot;clr-namespace:Caliburn.Micro.HelloWP7&amp;quot;&amp;gt;
    &amp;lt;Application.Resources&amp;gt;
        &amp;lt;local:HelloWP7Bootstrapper x:Key=&amp;quot;bootstrapper&amp;quot; /&amp;gt;
    &amp;lt;/Application.Resources&amp;gt;
&amp;lt;/Application&amp;gt;&lt;/pre&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System.Windows;

public partial class App : Application
{
    public App()
    {
        InitializeComponent();
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;INavigationService&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;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&amp;rsquo;t) the platform is going to create pages at will and the Frame control is going to conduct your application thusly. You don&amp;rsquo;t get to control that and there are no extensibility points, unlike the Silverlight version of the navigation framework. Rather than fight this, I&amp;rsquo;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&amp;rsquo;ve enabled the FrameAdapter to hook into the native navigation frame&amp;rsquo;s functionality and augment it with the following behaviors:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;When Navigating To a Page&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;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. &lt;/li&gt;
&lt;li&gt;If a VM is found, use the ViewModelBinder to connect the Page to the located ViewModel. &lt;/li&gt;
&lt;li&gt;Examine the Page&amp;rsquo;s QueryString. Look for properties on the VM that match the QueryString parameters and inject them, performing the necessary type coercion. &lt;/li&gt;
&lt;li&gt;If the ViewModel implements the IActivate interface, call its Activate method. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;When Navigating Away From a Page&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Detect whether the associated ViewModel implements the IGuardClose interface. &lt;/li&gt;
&lt;li&gt;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.* &lt;/li&gt;
&lt;li&gt;If the ViewModel can close and implements the IDeactivate interface, call it&amp;rsquo;s Deactivate method. &lt;/li&gt;
&lt;li&gt;If the application is being tombstoned or closed, pass &amp;ldquo;true&amp;rdquo; to the Deactivate method indicating that the ViewModel should permanently close. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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 &amp;ldquo;closing&amp;rdquo; of the application (IDeactivate). All these interfaces (and a couple more) are implemented by the Screen class. I haven&amp;rsquo;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&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IPhoneService&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;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&amp;rsquo;t add any additional behavior.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Now that we have the basic service explanations over with, let&amp;rsquo;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&amp;rsquo;ll use that, but change the Xaml to this:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;phone:PhoneApplicationPage x:Class=&amp;quot;Caliburn.Micro.HelloWP7.MainPage&amp;quot;
                            xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
                            xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
                            xmlns:phone=&amp;quot;clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone&amp;quot;
                            xmlns:shell=&amp;quot;clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone&amp;quot;
                            SupportedOrientations=&amp;quot;Portrait&amp;quot;
                            Orientation=&amp;quot;Portrait&amp;quot;
                            shell:SystemTray.IsVisible=&amp;quot;True&amp;quot;&amp;gt;
    &amp;lt;Grid Background=&amp;quot;Transparent&amp;quot;&amp;gt;
        &amp;lt;Grid.RowDefinitions&amp;gt;
            &amp;lt;RowDefinition Height=&amp;quot;Auto&amp;quot; /&amp;gt;
            &amp;lt;RowDefinition Height=&amp;quot;*&amp;quot; /&amp;gt;
        &amp;lt;/Grid.RowDefinitions&amp;gt;
        &amp;lt;StackPanel Grid.Row=&amp;quot;0&amp;quot;
                    Margin=&amp;quot;24,24,0,12&amp;quot;&amp;gt;
            &amp;lt;TextBlock Text=&amp;quot;WP7 Caliburn.Micro&amp;quot;
                       Style=&amp;#39;{StaticResource PhoneTextNormalStyle}&amp;#39; /&amp;gt;
            &amp;lt;TextBlock Text=&amp;#39;Main Page&amp;#39;
                       Margin=&amp;#39;-3,-8,0,0&amp;#39;
                       Style=&amp;#39;{StaticResource PhoneTextTitle1Style}&amp;#39; /&amp;gt;
        &amp;lt;/StackPanel&amp;gt;

        &amp;lt;Grid Grid.Row=&amp;#39;1&amp;#39;&amp;gt;
            &amp;lt;Button x:Name=&amp;#39;GotoPageTwo&amp;#39;
                    Content=&amp;#39;Goto Page Two&amp;#39; /&amp;gt;
        &amp;lt;/Grid&amp;gt;
    &amp;lt;/Grid&amp;gt;
&amp;lt;/phone:PhoneApplicationPage&amp;gt;&lt;/pre&gt;
&lt;p&gt;The only noteworthy thing I have done here is to add a single Button to the page in order to demonstrate navigation. Here&amp;rsquo;s what the MainPageViewModel looks like:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System;

public class MainPageViewModel
{
    readonly INavigationService navigationService;

    public MainPageViewModel(INavigationService navigationService)
    {
        this.navigationService = navigationService;
    }

    public void GotoPageTwo()
    {
        navigationService.Navigate(new Uri(&amp;quot;/PageTwo.xaml?NumberOfTabs=5&amp;quot;, UriKind.RelativeOrAbsolute));
    }
}&lt;/pre&gt;
&lt;p&gt;Here&amp;rsquo;s what it would look like if we could run it at this point:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/PageOne_5F00_6146C5F9.jpg"&gt;&lt;img height="244" width="132" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/PageOne_5F00_thumb_5F00_755FE282.jpg" alt="PageOne" border="0" title="PageOne" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;It&amp;rsquo;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&amp;rsquo;t implemented any interfaces or inherited from any base classes. We don&amp;rsquo;t really care about lifecycle. Take a look at the GotoPageTwo method (conventionally wired to the big button). 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:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System;
using System.Collections.Generic;
using System.Linq;

[SurviveTombstone]
public class PageTwoViewModel : Conductor&amp;lt;IScreen&amp;gt;.Collection.OneActive
{
    readonly Func&amp;lt;TabViewModel&amp;gt; createTab;

    public PageTwoViewModel(Func&amp;lt;TabViewModel&amp;gt; createTab)
    {
        this.createTab = createTab;
    }

    public int NumberOfTabs { get; set; }

    protected override void OnInitialize()
    {
        Enumerable.Range(1, NumberOfTabs).Apply(x =&amp;gt;{
            var tab = createTab();
            tab.DisplayName = &amp;quot;Item &amp;quot; + x;
            Items.Add(tab);
        });

        ActivateItem(Items[0]);
    }
}&lt;/pre&gt;
&lt;p&gt;The value of the the QueryString parameter &amp;ldquo;NumberOfTabs&amp;rdquo; 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&amp;rsquo;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 &amp;ldquo;Activates&amp;rdquo; the first one. The Items collection and Activation capabilities come from the Conductor base class. Just to remind you, I&amp;rsquo;m going to cover Screens and Conductors much more thoroughly in a future article. Also, take note of the [SurviveTombstone] attribute. We&amp;rsquo;ll get to that soon. First, here&amp;rsquo;s the view that this is bound to:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;phone:PhoneApplicationPage x:Class=&amp;quot;Caliburn.Micro.HelloWP7.PageTwo&amp;quot;
                            xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
                            xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
                            xmlns:phone=&amp;quot;clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone&amp;quot;
                            xmlns:shell=&amp;quot;clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone&amp;quot;
                            SupportedOrientations=&amp;quot;Portrait&amp;quot;
                            Orientation=&amp;quot;Portrait&amp;quot;
                            shell:SystemTray.IsVisible=&amp;quot;True&amp;quot;&amp;gt;
    &amp;lt;Grid Background=&amp;quot;Transparent&amp;quot;&amp;gt;
        &amp;lt;Grid.RowDefinitions&amp;gt;
            &amp;lt;RowDefinition Height=&amp;quot;Auto&amp;quot; /&amp;gt;
            &amp;lt;RowDefinition Height=&amp;quot;*&amp;quot; /&amp;gt;
        &amp;lt;/Grid.RowDefinitions&amp;gt;

        &amp;lt;StackPanel Grid.Row=&amp;quot;0&amp;quot;
                    Margin=&amp;quot;24,24,0,12&amp;quot;&amp;gt;
            &amp;lt;TextBlock Text=&amp;quot;WP7 Caliburn.Micro&amp;quot;
                       Style=&amp;#39;{StaticResource PhoneTextNormalStyle}&amp;#39; /&amp;gt;
            &amp;lt;TextBlock Text=&amp;#39;Page Two&amp;#39;
                       Margin=&amp;#39;-3,-8,0,0&amp;#39;
                       Style=&amp;#39;{StaticResource PhoneTextTitle1Style}&amp;#39; /&amp;gt;
        &amp;lt;/StackPanel&amp;gt;

        &amp;lt;Grid Grid.Row=&amp;#39;1&amp;#39;&amp;gt;
            &amp;lt;Grid.RowDefinitions&amp;gt;
                &amp;lt;RowDefinition Height=&amp;#39;Auto&amp;#39; /&amp;gt;
                &amp;lt;RowDefinition Height=&amp;#39;*&amp;#39; /&amp;gt;
            &amp;lt;/Grid.RowDefinitions&amp;gt;

            &amp;lt;ListBox x:Name=&amp;#39;Items&amp;#39;&amp;gt;
                &amp;lt;ListBox.ItemTemplate&amp;gt;
                    &amp;lt;DataTemplate&amp;gt;
                        &amp;lt;TextBlock Text=&amp;#39;{Binding DisplayName}&amp;#39;
                                   Margin=&amp;#39;2 0 12 0&amp;#39; 
                                   FontSize=&amp;#39;30&amp;#39; /&amp;gt;
                    &amp;lt;/DataTemplate&amp;gt;
                &amp;lt;/ListBox.ItemTemplate&amp;gt;
                &amp;lt;ListBox.ItemsPanel&amp;gt;
                    &amp;lt;ItemsPanelTemplate&amp;gt;
                        &amp;lt;StackPanel Orientation=&amp;#39;Horizontal&amp;#39; /&amp;gt;
                    &amp;lt;/ItemsPanelTemplate&amp;gt;
                &amp;lt;/ListBox.ItemsPanel&amp;gt;
            &amp;lt;/ListBox&amp;gt;

            &amp;lt;ContentControl x:Name=&amp;#39;ActiveItem&amp;#39; 
                            HorizontalContentAlignment=&amp;#39;Stretch&amp;#39;
                            VerticalContentAlignment=&amp;#39;Stretch&amp;#39;
                            Grid.Row=&amp;#39;1&amp;#39; /&amp;gt;
        &amp;lt;/Grid&amp;gt;
    &amp;lt;/Grid&amp;gt;
&amp;lt;/phone:PhoneApplicationPage&amp;gt;&lt;/pre&gt;
&lt;p&gt;It looks like this when running:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/PageTwo_5F00_30B34841.jpg"&gt;&lt;img height="244" width="130" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/PageTwo_5F00_thumb_5F00_59BDE73D.jpg" alt="PageTwo" border="0" title="PageTwo" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;This view is a bit more complex, but you only need concern yourself with the ListBox and the ContentControl. Here, we are using these two controls to create a Tabbed UI. The ListBox plays the part of the TabHeaders. It&amp;rsquo;s name causes it to automatically have its ItemsSource bound to the Items collection on the VM and its SelectedItem bound to the ActiveItem on the VM (these properties come from Conductor base class). The ContentControl has its Content property automatically bound to the ActiveItem property on the View and it is done using the View.Model attached property I discussed &lt;a target="_blank" href="http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/17/caliburn-micro-soup-to-nuts-pt-3-all-about-actions.aspx"&gt;in the previous article&lt;/a&gt;. This allows the ActiveItem to be conventionally wired up to it&amp;rsquo;s view, enabling the display of the &amp;ldquo;Tab Content&amp;rdquo;. And yes, I am going to cover conventions in more depth in a future article as well. But, I want you to get a taste of how conventions, composition and conductors all play together. What we&amp;rsquo;ve just created is an MDI interface inside this particular page completely driven by the ViewModel. Let&amp;rsquo;s take a look at that TabViewModel and it&amp;rsquo;s corresponding View. First the VM:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System;
using System.Windows;
using Microsoft.Phone.Tasks;

[SurviveTombstone]
public class TabViewModel : Screen, ILaunchChooser&amp;lt;PhoneNumberResult&amp;gt;
{
    string text;

    [SurviveTombstone]
    public string Text
    {
        get { return text; }
        set
        {
            text = value;
            NotifyOfPropertyChange(() =&amp;gt; Text);
        }
    }

    public void Choose()
    {
        TaskLaunchRequested(this, TaskLaunchEventArgs.For&amp;lt;PhoneNumberChooserTask&amp;gt;());
    }

    public event EventHandler&amp;lt;TaskLaunchEventArgs&amp;gt; TaskLaunchRequested = delegate { };

    public void Handle(PhoneNumberResult message)
    {
        MessageBox.Show(&amp;quot;The result was &amp;quot; + message.TaskResult, DisplayName, MessageBoxButton.OK); //You should abstract this&amp;hellip;
    }
}&lt;/pre&gt;
&lt;p&gt;Now you should be noticing some interesting tidbits here. I&amp;rsquo;ll be coming back to those in a minute. Let&amp;rsquo;s take a look at the last piece in our application&amp;rsquo;s UI, the view for these tabs:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.HelloWP7.TabView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&amp;gt;
    &amp;lt;StackPanel Background=&amp;quot;{StaticResource PhoneChromeBrush}&amp;quot;&amp;gt;
        &amp;lt;TextBlock x:Name=&amp;quot;DisplayName&amp;quot;
                   Margin=&amp;quot;8 0 0 0&amp;quot;
                   FontFamily=&amp;quot;{StaticResource PhoneFontFamilyNormal}&amp;quot;
                   FontSize=&amp;quot;{StaticResource PhoneFontSizeNormal}&amp;quot;
                   Foreground=&amp;quot;{StaticResource PhoneForegroundBrush}&amp;quot; /&amp;gt;
        &amp;lt;TextBox x:Name=&amp;quot;Text&amp;quot; /&amp;gt;
        &amp;lt;Button Content=&amp;quot;Choose&amp;quot;
                x:Name=&amp;quot;Choose&amp;quot; /&amp;gt;
    &amp;lt;/StackPanel&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt;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&amp;rsquo;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 &amp;ldquo;activation&amp;rdquo; 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&amp;rsquo;s a bit different for each container, but it&amp;rsquo;s a powerful extensibility point. By plugging in CMs InstanceActivator class, we will make launchers/chooser so much easier for you. For now, I&amp;rsquo;ll show you what the PhoneContainer looks like. We&amp;rsquo;ll get to the launcher/chooser bit a little later:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System;

public class PhoneContainer : SimpleContainer
{
    public PhoneContainer()
    {
        Activator = new InstanceActivator(type =&amp;gt; GetInstance(type, null));
    }

    public InstanceActivator Activator { get; private set; }

    protected override object ActivateInstance(Type type, object[] args)
    {
        return Activator.ActivateInstance(base.ActivateInstance(type, args));
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tombstoning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now that we have all the pieces, I can explain why I&amp;rsquo;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&amp;rsquo;s OS remembers the page you were on and Navigates to it automatically (read more &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ff817008(v=VS.92).aspx"&gt;here&lt;/a&gt;). 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&amp;rsquo;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&amp;rsquo;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 &amp;ldquo;Choose&amp;rdquo; button (we are going to talk about choosers next). After the chooser launches, press the phone&amp;rsquo;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.** Here&amp;rsquo;s what you should see:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/PageTwoPostChooser_5F00_191B9ACE.jpg"&gt;&lt;img height="244" width="131" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/PageTwoPostChooser_5F00_thumb_5F00_62414687.jpg" alt="PageTwoPostChooser" border="0" title="PageTwoPostChooser" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Launchers and Choosers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One unique aspect to WP7 development is &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ff769542(v=VS.92).aspx"&gt;Tasks&lt;/a&gt;. 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&amp;hellip;the WP7 API for Choosers is a software design &lt;em&gt;abomination&lt;/em&gt;. 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, &amp;ldquo;But what if I am using a Chooser? How do I get the results back into my application?&amp;rdquo; 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.&amp;nbsp; 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&amp;rsquo;s going to play nice with MVVM&amp;hellip;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&amp;rsquo;t work. You wired the event too early. It&amp;rsquo;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&amp;rsquo;s not clearly defined by their API. If you do it in your page&amp;rsquo;s constructor, it should work though. But should you handle the event in the constructor? Probably not, especially since your main UI isn&amp;rsquo;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&amp;rsquo;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&amp;rsquo;s how it works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First, developers register the Launcher/Chooser types they intend to use with the Activator. If you look back at the sample&amp;rsquo;s bootstrapper, you will see that I used the methods InstallLauncher and InstallChooser.&lt;/li&gt;
&lt;li&gt;Each instance that is created by the IoC container will be inspected by the Activator to see if it implements certain interfaces.&lt;/li&gt;
&lt;li&gt;If the instance implements ILaunchTask or ILaunchChooser&amp;lt;TResult&amp;gt;, the activator will wire itself to the event defined by the interface.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;The infrastructure is notified of the event and then determines if the sender implements IConfigureTask&amp;lt;TTask&amp;gt;. If it does, the task instance is passed to the sender&amp;rsquo;s Configure method. (Some tasks have parameters which must be set, but the sample above does not.)&lt;/li&gt;
&lt;li&gt;Next, the infrastructure &amp;ldquo;records&amp;rdquo; the sender of the event so that it knows who to call back after resurrection.&lt;/li&gt;
&lt;li&gt;The infrastructure now calls Show on the task and your application is Tombstoned.&lt;/li&gt;
&lt;li&gt;When, your application resurrects, it should put itself back in the state it was before tombstoning.&lt;/li&gt;
&lt;li&gt;Since all instances come from the IoC container, we inspect each instance that is created to see if it was the one we &amp;ldquo;recorded&amp;rdquo; as the sender of the task launch.&lt;/li&gt;
&lt;li&gt;When we find a match, we attempt to call ILaunchChooser&amp;lt;TResult&amp;gt;.Handle with the Chooser result at the &amp;ldquo;latest possible time.&amp;rdquo; The latest possible time is evaluated based on the features of the class. If it is IViewAware, we call handle after the View&amp;rsquo;s Loaded event fires. If it isn&amp;rsquo;t but implements IActivate, we call Handle after the class is activated (assuming it isn&amp;rsquo;t already activated.) If these conditions aren&amp;rsquo;t met, we call Handle immediately.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It sounds complicated. That&amp;rsquo;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&amp;rsquo;s View is shown.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;*Even though the IGuardClose interface was designed to handle async scenarios, you must use it synchronously in WP7. This is due to a flaw in the design of Silverlight Navigation Framework.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;**Sometimes the first time I do this, the debugger does not re-attach correctly and the application never resurrects at all. If this happens to you, just try it again ;)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=61412" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.06.14.12/Caliburn.Micro.HelloWP7.zip" length="304744" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WP7/default.aspx">WP7</category></item><item><title>Caliburn.Micro Soup to Nuts Pt. 3 – All About Actions</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/17/caliburn-micro-soup-to-nuts-pt-3-all-about-actions.aspx</link><pubDate>Sat, 17 Jul 2010 16:04:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:61112</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=61112</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/17/caliburn-micro-soup-to-nuts-pt-3-all-about-actions.aspx#comments</comments><description>&lt;p&gt;We briefly introduced actions in &lt;a target="_blank" href="http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/06/caliburn-micro-soup-to-nuts-pt-1-configuration-actions-and-conventions.aspx"&gt;Pt. 1&lt;/a&gt;, but there is so much more to know. To begin our investigation, we&amp;rsquo;ll take our simple &amp;ldquo;Hello&amp;rdquo; example and see what it looks like when we explicitly create the actions rather than use conventions. Here&amp;rsquo;s the Xaml:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.Hello.ShellView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
             xmlns:i=&amp;quot;clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity&amp;quot;
             xmlns:cal=&amp;quot;http://www.caliburnproject.org&amp;quot;&amp;gt;
    &amp;lt;StackPanel&amp;gt;
        &amp;lt;TextBox x:Name=&amp;quot;Name&amp;quot; /&amp;gt;
        &amp;lt;Button Content=&amp;quot;Click Me&amp;quot;&amp;gt;
            &amp;lt;i:Interaction.Triggers&amp;gt;
                &amp;lt;i:EventTrigger EventName=&amp;quot;Click&amp;quot;&amp;gt;
                    &amp;lt;cal:ActionMessage MethodName=&amp;quot;SayHello&amp;quot; /&amp;gt;
                &amp;lt;/i:EventTrigger&amp;gt;
            &amp;lt;/i:Interaction.Triggers&amp;gt;
        &amp;lt;/Button&amp;gt;
    &amp;lt;/StackPanel&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As you can see, the Actions feature leverages System.Windows.Interactivity for it&amp;rsquo;s trigger mechanism. This means that you can use anything that inherits from System.Windows.Interactivity.TriggerBase to trigger the sending of an ActionMessage.*&amp;nbsp; 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.&amp;nbsp; ActionMessage is, of coarse, the Caliburn.Micro-specific part of this markup. It indicates that when the trigger occurs, we should send a message of &amp;ldquo;SayHello.&amp;rdquo;&amp;nbsp; So, why do I use the language &amp;ldquo;send a message&amp;rdquo; instead of &amp;ldquo;execute a method&amp;rdquo; when describing this functionality? That&amp;rsquo;s the interesting and powerful part.&amp;nbsp; 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 &amp;ldquo;SayHello&amp;rdquo; method, the framework will continue to bubble until it finds one, throwing an exception if no &amp;ldquo;handler&amp;rdquo; is found.** 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 &amp;ldquo;SayHello&amp;rdquo; message, it will check to see if that class also has either a property or a method named &amp;ldquo;CanSayHello.&amp;rdquo; 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&amp;rsquo;ll discuss method guards in further detail below.&lt;/p&gt;
&lt;p&gt;Now you&amp;rsquo;re probably wondering how to specify the target of an ActionMessage. Looking at the markup above, there&amp;rsquo;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 &amp;ldquo;handler&amp;rdquo; 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.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how we would apply this to achieve MVVM using a View-First technique (gasp!) Here&amp;rsquo;s how we would change our bootstrapper:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class MefBootstrapper : Bootstrapper
{
    //same as before

    protected override void DisplayRootView()
    {
        Application.Current.RootVisual = new ShellView();
    }

    //same as before
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Because we are using View-First, we&amp;rsquo;ve inherited from the non-generic Bootstrapper. The MEF configuration is the same as seen previously, so I have left that out for brevity&amp;rsquo;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&amp;rsquo;ll slightly alter how we are exporting our ShellViewModel, by adding an explicitly named contract:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;[Export(&amp;quot;Shell&amp;quot;, typeof(IShell))]
public class ShellViewModel : PropertyChangedBase, IShell
{
    //same as before
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Finally, we will alter our view to pull in the VM and perform all bindings:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.ViewFirst.ShellView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
             xmlns:cal=&amp;quot;http://www.caliburnproject.org&amp;quot;
             cal:Bind.Model=&amp;quot;Shell&amp;quot;&amp;gt;
    &amp;lt;StackPanel&amp;gt;
        &amp;lt;TextBox x:Name=&amp;quot;Name&amp;quot; /&amp;gt;
        &amp;lt;Button x:Name=&amp;quot;SayHello&amp;quot;
                Content=&amp;quot;Click Me&amp;quot; /&amp;gt;
    &amp;lt;/StackPanel&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;s a summary of the available attached properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Action.Target &amp;ndash; 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. &lt;/li&gt;
&lt;li&gt;Action.TargetWithoutContext &amp;ndash; Sets only the Action.Target property to the specified instance. String values are used to resolve an instance from the IoC container. &lt;/li&gt;
&lt;li&gt;Bind.Model &amp;ndash; View-First - Set&amp;rsquo;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. &lt;/li&gt;
&lt;li&gt;View.Model &amp;ndash; ViewModel-First &amp;ndash; 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. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s take a look at another interesting aspect of ActionMessage: Parameters. To see this in action, let&amp;rsquo;s switch back to our original ViewModel-First bootstrapper, etc. and begin by changing our ShellViewModel to look like this: &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;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(&amp;quot;Hello {0}!&amp;quot;, name));
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;s have a look at the Xaml:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.HelloParameters.ShellView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
             xmlns:i=&amp;quot;clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity&amp;quot;
             xmlns:cal=&amp;quot;http://www.caliburnproject.org&amp;quot;&amp;gt;
    &amp;lt;StackPanel&amp;gt;
        &amp;lt;TextBox x:Name=&amp;quot;Name&amp;quot; /&amp;gt;
        &amp;lt;Button Content=&amp;quot;Click Me&amp;quot;&amp;gt;
            &amp;lt;i:Interaction.Triggers&amp;gt;
                &amp;lt;i:EventTrigger EventName=&amp;quot;Click&amp;quot;&amp;gt;
                    &amp;lt;cal:ActionMessage MethodName=&amp;quot;SayHello&amp;quot;&amp;gt;
                        &amp;lt;cal:Parameter Value=&amp;quot;{Binding ElementName=Name, Path=Text}&amp;quot; /&amp;gt;
                    &amp;lt;/cal:ActionMessage&amp;gt;
                &amp;lt;/i:EventTrigger&amp;gt;
            &amp;lt;/i:Interaction.Triggers&amp;gt;
        &amp;lt;/Button&amp;gt;
    &amp;lt;/StackPanel&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;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?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/ActionsInBlend_5F00_363545A1.jpg"&gt;&lt;img height="161" width="244" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/ActionsInBlend_5F00_thumb_5F00_0CC10461.jpg" alt="ActionsInBlend" border="0" title="ActionsInBlend" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;One thing that is nice about this is that every time the value of a parameter changes, we&amp;rsquo;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&amp;rsquo;ll see that it behaves the same as in previous examples.&lt;/p&gt;
&lt;p&gt;In addition to literal values and Binding Expressions, there are a number of helpful &amp;ldquo;special&amp;rdquo; values that you can use with parameters. These allow you a convenient way to access common contextual information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$eventArgs &amp;ndash; Passes the Trigger&amp;rsquo;s EventArgs or input parameter to your Action. Note: This will be null for guard methods since the trigger hasn&amp;rsquo;t actually occurred. &lt;/li&gt;
&lt;li&gt;$dataContext &amp;ndash; 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. &lt;/li&gt;
&lt;li&gt;$source &amp;ndash; The actual FrameworkElement that triggered the ActionMessage to be sent. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You must start the variable with a &amp;ldquo;$&amp;rdquo; but the name is treated in a case-insensitive way by CM.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Word to the Wise&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Now, do you want to see something truly wicked? Change your Xaml back to this:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.HelloParameters.ShellView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&amp;gt;
    &amp;lt;StackPanel&amp;gt;
        &amp;lt;TextBox x:Name=&amp;quot;Name&amp;quot; /&amp;gt;
        &amp;lt;Button x:Name=&amp;quot;SayHello&amp;quot; 
                Content=&amp;quot;Click Me&amp;quot; /&amp;gt;
    &amp;lt;/StackPanel&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Running the application will confirm for you that CM&amp;rsquo;s conventions even understand ActionMessage parameters. We&amp;rsquo;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 &amp;ldquo;special&amp;rdquo; values.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Now, lets look at a simple Master/Detail scenario that demonstrates ActionMessage bubbling, but let&amp;rsquo;s do it with a shorthand syntax that is designed to be more developer friendly. We&amp;rsquo;ll start by adding a simple new class named Model:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System;

public class Model
{
    public Guid Id { get; set; }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;And then we&amp;rsquo;ll change our ShellViewModel to this:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System;
using System.ComponentModel.Composition;

[Export(typeof(IShell))]
public class ShellViewModel : IShell
{
    public BindableCollection&amp;lt;Model&amp;gt; Items { get; private set; }

    public ShellViewModel()
    {
        Items = new BindableCollection&amp;lt;Model&amp;gt;{
            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);
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;s update the ShellView:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.BubblingAction.ShellView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
             xmlns:cal=&amp;quot;http://www.caliburnproject.org&amp;quot;&amp;gt;
    &amp;lt;StackPanel&amp;gt;
        &amp;lt;ItemsControl x:Name=&amp;quot;Items&amp;quot;&amp;gt;
            &amp;lt;ItemsControl.ItemTemplate&amp;gt;
                &amp;lt;DataTemplate&amp;gt;
                    &amp;lt;StackPanel Orientation=&amp;quot;Horizontal&amp;quot;&amp;gt;
                        &amp;lt;Button Content=&amp;quot;Remove&amp;quot;
                                cal:Message.Attach=&amp;quot;Remove($dataContext)&amp;quot; /&amp;gt;
                        &amp;lt;TextBlock Text=&amp;quot;{Binding Id}&amp;quot; /&amp;gt;
                    &amp;lt;/StackPanel&amp;gt;
                &amp;lt;/DataTemplate&amp;gt;
            &amp;lt;/ItemsControl.ItemTemplate&amp;gt;
        &amp;lt;/ItemsControl&amp;gt;
        &amp;lt;Button Content=&amp;quot;Add&amp;quot;
                cal:Message.Attach=&amp;quot;Add&amp;quot; /&amp;gt;
    &amp;lt;/StackPanel&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;ve seen previously. If you work primarily in the Xaml editor and not in the designer, you&amp;rsquo;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&amp;rsquo;s Click. You can always be explicit of coarse. Here&amp;rsquo;s what the full syntax for our Remove message would look like if we were declaring everything:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;Button Content=&amp;quot;Remove&amp;quot;
        cal:Message.Attach=&amp;quot;[Event Click] = [Action Remove($dataContext)]&amp;quot; /&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Suppose we were to re-write our parameterized SayHello action with the Message.Attach syntax. It would look like this:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;Button Content=&amp;quot;Click Me&amp;quot;
        cal:Message.Attach=&amp;quot;[Event Click] = [Action SayHello(Name.Text)]&amp;quot; /&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;But we could also leverage some smart defaults of the parser and do it like this:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;Button Content=&amp;quot;Click Me&amp;quot;
        cal:Message.Attach=&amp;quot;SayHello(Name)&amp;quot; /&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;You can specify literals as parameters as well and even declare multiple actions by separating them with a semicolon:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;Button Content=&amp;quot;Let&amp;#39;s Talk&amp;quot;
        cal:Message.Attach=&amp;quot;[Event MouseEnter] = [Action Talk(&amp;#39;Hello&amp;#39;, Name.Text)];
                            [Event MouseLeave] = [Action Talk(&amp;#39;Goodbye&amp;#39;, Name.Text)]&amp;quot; /&amp;gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;WARNING: Those developers who ask me to expand this functionality into a full-blown expression parser will be taken out back and&amp;hellip;dealt with. Message.Attach is not about cramming code into Xaml. It&amp;rsquo;s purpose is to provide a streamlined syntax for declaring when/what messages to send to the ViewModel. Please don&amp;rsquo;t abuse this.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;If you haven&amp;rsquo;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.&lt;/p&gt;
&lt;p&gt;So, we&amp;rsquo;ve discussed using Interaction.Triggers with ActionMessage, including the use of Parameters with literals, element bindings*** and special values. We&amp;rsquo;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&amp;rsquo;ve looked at various examples of conventions in action too. Now, there&amp;rsquo;s one final killer feature of ActionMessage we haven&amp;rsquo;t discussed yet&amp;hellip;Coroutines. But, that will have to wait until next time.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;*Currently, the full version of Caliburn is not based on System.Windows.Interactivity. Caliburn&amp;rsquo;s trigger mechanism was around long before Blend&amp;rsquo;s.&amp;nbsp; 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.&lt;/p&gt;
&lt;p&gt;**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.&lt;/p&gt;
&lt;p&gt;***One important detail about ElementName Bindings that I didn&amp;rsquo;t mention&amp;hellip;It doesn&amp;rsquo;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.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=61112" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.06.11.12/Samples.zip" length="30486" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/databinding/default.aspx">databinding</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MEF/default.aspx">MEF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category></item><item><title>Caliburn.Micro Soup to Nuts Pt. 2 – Customizing The Bootstrapper</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/08/caliburn-micro-soup-to-nuts-pt-2-customizing-the-bootstrapper.aspx</link><pubDate>Fri, 09 Jul 2010 00:28:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:61031</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=61031</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/08/caliburn-micro-soup-to-nuts-pt-2-customizing-the-bootstrapper.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/06/caliburn-micro-soup-to-nuts-pt-1-configuration-actions-and-conventions.aspx" target="_blank"&gt;In the last part&lt;/a&gt; we discussed the most basic configuration for &lt;a href="http://caliburnmicro.codeplex.com/" target="_blank"&gt;Caliburn.Micro&lt;/a&gt; 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&amp;rsquo;s begin by configuring our application to use an IoC container. We&amp;rsquo;ll use MEF for this example, but Caliburn.Micro will work well with any container. First, go ahead and &lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.06.09.93/Caliburn.Micro.Hello.zip" target="_blank"&gt;grab the code from Part 1&lt;/a&gt;. 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&amp;rsquo;s functionality.* Now, let&amp;rsquo;s create a new Bootstrapper called MefBootstrapper. Use the following code:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="c#:nogutter:nocontrols" name="code"&gt;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&amp;lt;IShell&amp;gt;
{
    private CompositionContainer container;

    protected override void Configure()
    {
        container = CompositionHost.Initialize(
            new AggregateCatalog(
                AssemblySource.Instance.Select(x =&amp;gt; new AssemblyCatalog(x)).OfType&amp;lt;ComposablePartCatalog&amp;gt;()
                )
            );

        var batch = new CompositionBatch();

        batch.AddExportedValue&amp;lt;IWindowManager&amp;gt;(new WindowManager());
        batch.AddExportedValue&amp;lt;IEventAggregator&amp;gt;(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&amp;lt;object&amp;gt;(contract);

        if (exports.Count() &amp;gt; 0)
            return exports.First();

        throw new Exception(string.Format(&amp;quot;Could not locate any instances of contract {0}.&amp;quot;, contract));
    }

    protected override IEnumerable&amp;lt;object&amp;gt; GetAllInstances(Type serviceType)
    {
        return container.GetExportedValues&amp;lt;object&amp;gt;(AttributedModelServices.GetContractName(serviceType));
    }

    protected override void BuildUp(object instance)
    {
        container.SatisfyImportsOnce(instance);
    }
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all the code to integrate MEF.&amp;nbsp; 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&amp;rsquo;m taking advantage of Silverlight&amp;rsquo;s CompositionHost to setup the CompositionContainer. You can just instantiate the container directly if you are working with .NET. Then, I&amp;rsquo;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:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="c#:nogutter:nocontrols" name="code"&gt;protected override IEnumerable&amp;lt;Assembly&amp;gt; SelectAssemblies()
{
    return new[] {
        Assembly.GetExecutingAssembly()
    };
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;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&amp;rsquo;ll need to make sure they get registered with your IoC container and the AssemblySoure.Instance when they are loaded. &lt;/p&gt;
&lt;p&gt;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&amp;rsquo;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).&lt;/p&gt;
&lt;p&gt;After we configure the container, we need to tell Caliburn.Micro how to use it.&amp;nbsp; That is the purpose of the three overrides that follow. &amp;ldquo;GetInstance&amp;rdquo; and &amp;ldquo;GetAllInstances&amp;rdquo; are required by the framework. &amp;ldquo;BuildUp&amp;rdquo; is optionally used to supply property dependencies to instances of IResult that are executed by the framework. &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Word to the Wise&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While Caliburn.Micro does provide ServiceLocator functionality through the Bootstrapper&amp;rsquo;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&amp;rsquo;ll also demonstrate some solutions.**&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;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&amp;rsquo;t specifically handled by your application code.&amp;nbsp; The last override, DisplayRootView, is unique. Let&amp;rsquo;s look at how it is implemented in Bootstrapper&amp;lt;TRootModel&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="c#:nogutter:nocontrols" name="code"&gt;protected override void DisplayRootView() 
{
    var viewModel = IoC.Get&amp;lt;TRootModel&amp;gt;();
#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.Current.RootVisual = view;
#else
    new WindowManager().Show(viewModel);
#endif
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;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 &amp;ldquo;activate&amp;rdquo; 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&amp;rsquo;t like it, perhaps because you prefer view-first MVVM, then this is the method you want to override to change that behavior.&lt;/p&gt;
&lt;p&gt;Now that you understand all about the Bootstrapper, let&amp;rsquo;s get our sample working. We need to add the IShell interface. In our case, it&amp;rsquo;s just a marker interface. But, in a real application, you would&amp;nbsp; have some significant shell-related functionality baked into this contract. Here&amp;rsquo;s the code:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="c#:nogutter:nocontrols" name="code"&gt;public interface IShell
{
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Now, we need to implement the interface and decorate our ShellViewModel with the appropriate MEF attributes:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="c#:nogutter:nocontrols" name="code"&gt;[Export(typeof(IShell))]
public class ShellViewModel : PropertyChangedBase, IShell
{
   ...implementation is same as before...
}&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it! Your up and running with your bootstrapper configured for MEF.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;*If you are using .NET, you will only need to reference System.ComponentModel.Composition.&lt;/p&gt;
&lt;p&gt;**I&amp;rsquo;m quite guilty of this myself, but I&amp;rsquo;m trying to be more conscious of it.&amp;nbsp; I&amp;rsquo;m also excited to see that modern IoC containers as well as Caliburn.Micro provide some very nice ways to avoid this situation.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=61031" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.06.10.31/Caliburn.Micro.HelloMef.zip" length="7463" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/databinding/default.aspx">databinding</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MEF/default.aspx">MEF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category></item><item><title>Caliburn.Micro Soup to Nuts Pt. 1 – Configuration, Actions and Conventions</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/06/caliburn-micro-soup-to-nuts-pt-1-configuration-actions-and-conventions.aspx</link><pubDate>Tue, 06 Jul 2010 17:47:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:60993</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>18</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=60993</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/06/caliburn-micro-soup-to-nuts-pt-1-configuration-actions-and-conventions.aspx#comments</comments><description>&lt;p&gt;In this tutorial we will learn a few of the basics of &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt;. Let&amp;rsquo;s start by getting the framework.&amp;nbsp; Head on over to &lt;a href="http://caliburnmicro.codeplex.com/SourceControl/list/changesets" title="http://caliburnmicro.codeplex.com/SourceControl/list/changesets"&gt;http://caliburnmicro.codeplex.com/SourceControl/list/changesets&lt;/a&gt;&amp;nbsp; Either use Mercurial to clone the repo or click on the link for the latest change set, then click on the download link. I recommend that you go ahead and get setup with TortoiseHG for Mercurial. You can read &lt;a target="_blank" href="http://codeplex.codeplex.com/wikipage?title=Using%20TortoiseHG%20with%20CodePlex&amp;amp;referringTitle=Source%20control%20clients&amp;amp;ProjectName=codeplex"&gt;here&lt;/a&gt; and/or watch a free TekPub video &lt;a target="_blank" href="http://tekpub.com/codeplex"&gt;here&lt;/a&gt; for information on that.&amp;nbsp; Once you have the source downloaded, navigate to the &amp;ldquo;src&amp;rdquo; folder. Open the &amp;ldquo;Caliburn.Micro.sln&amp;rdquo; Pess Ctrl-Shift-B (or use the Build menu) to build the solution in Visual Studio. Now that we have the framework and it&amp;rsquo;s been successfully built, let&amp;rsquo;s create a simple application.&lt;/p&gt;
&lt;p&gt;Open Visual Studio and create a new Silverlight 4 Application called &amp;ldquo;Caliburn.Micro.Hello&amp;rdquo;. You don&amp;rsquo;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 &amp;ldquo;MainPage.xaml&amp;rdquo; and clean up your &amp;ldquo;App.xaml.cs&amp;rdquo; so that it looks like this:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;namespace Caliburn.Micro.Hello
{
    using System.Windows;

    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
        }
    }
}&lt;/pre&gt;
&lt;p&gt;Since Caliburn.Micro prefers a View-Model-First approach, let&amp;rsquo;s start there. Create your first VM and call it ShellViewModel. Use the following code for the implementation:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;namespace Caliburn.Micro.Hello
{
    using System.Windows;

    public class ShellViewModel : PropertyChangedBase
    {
        string name;

        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                NotifyOfPropertyChange(() =&amp;gt; Name);
                NotifyOfPropertyChange(() =&amp;gt; CanSayHello);
            }
        }

        public bool CanSayHello
        {
            get { return !string.IsNullOrWhiteSpace(Name); }
        }

        public void SayHello()
        {
            MessageBox.Show(string.Format(&amp;quot;Hello {0}!&amp;quot;, Name)); //Don&amp;#39;t do this.
        }
    }
}&lt;/pre&gt;
&lt;p&gt;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 :)&lt;/p&gt;
&lt;p&gt;Now that we have our VM, let&amp;rsquo;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:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;namespace Caliburn.Micro.Hello
{
    public class HelloBootstrapper : Bootstrapper&amp;lt;ShellViewModel&amp;gt; {}
}&lt;/pre&gt;
&lt;p&gt;There are two Bootsrappers available in Caliburn.Micro. This version allows you to specify the type of &amp;ldquo;root view model&amp;rdquo; via the generic type. The &amp;ldquo;root view mdoel&amp;rdquo; 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:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;Application xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;
             xmlns:local=&amp;quot;clr-namespace:Caliburn.Micro.Hello&amp;quot;
             x:Class=&amp;quot;Caliburn.Micro.Hello.App&amp;quot;&amp;gt;
    &amp;lt;Application.Resources&amp;gt;
        &amp;lt;local:HelloBootstrapper x:Key=&amp;quot;bootstrapper&amp;quot; /&amp;gt;
    &amp;lt;/Application.Resources&amp;gt;
&amp;lt;/Application&amp;gt;&lt;/pre&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/ViewNotFound_5F00_4648EFC7.jpg"&gt;&lt;img height="134" width="244" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/ViewNotFound_5F00_thumb_5F00_5657BE7E.jpg" alt="ViewNotFound" border="0" title="ViewNotFound" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Caliburn.Micro creates the ShellViewModel, but doesn&amp;rsquo;t know how to render it. So, let&amp;rsquo;s create a view. Create a new Silverlight User Control named ShellView. Use the following xaml:&lt;/p&gt;
&lt;pre name="code" class="xml:nogutter:nocontrols"&gt;&amp;lt;UserControl x:Class=&amp;quot;Caliburn.Micro.Hello.ShellView&amp;quot;
             xmlns=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;quot;
             xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml&amp;quot;&amp;gt;
    &amp;lt;StackPanel&amp;gt;
        &amp;lt;TextBox x:Name=&amp;quot;Name&amp;quot; /&amp;gt;
        &amp;lt;Button x:Name=&amp;quot;SayHello&amp;quot;
                Content=&amp;quot;Click Me&amp;quot; /&amp;gt;
    &amp;lt;/StackPanel&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/pre&gt;
&lt;p&gt;Run the application again. You should now see the UI:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/ViewFound_5F00_35D07ECC.jpg"&gt;&lt;img height="135" width="244" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/ViewFound_5F00_thumb_5F00_65FA5A40.jpg" alt="ViewFound" border="0" title="ViewFound" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Typing something in the TextBox will enable the Button and clicking it will show a message:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/ViweWithData_5F00_45731A8E.jpg"&gt;&lt;img height="244" width="243" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/ViweWithData_5F00_thumb_5F00_409066D2.jpg" alt="ViweWithData" border="0" title="ViweWithData" style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Caliburn.Micro uses a simple naming convention to locate Views for ViewModels.&amp;nbsp; Essentially, it takes the FullName and removes &amp;ldquo;Model&amp;rdquo; 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=&amp;rdquo;Name&amp;rdquo; is bound to the &amp;ldquo;Name&amp;rdquo; property on the VM. You can also see that the Button with x:Name=&amp;rdquo;SayHello&amp;rdquo; is bound to the method with the same name on the VM.&amp;nbsp; The &amp;ldquo;CanSayHello&amp;rdquo; property is guarding access to the &amp;ldquo;SayHello&amp;rdquo; action by disabling the Button. These are the basics of Caliburn.Micro&amp;rsquo;s ActionMessage and Conventions functionality. There&amp;rsquo;s much more to show. But, next time I want to show how we can integrate an IoC container such as MEF. This sample is attached below.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;*All the functionality described in this article works identically for both Caliburn.Micro and Caliburn&amp;hellip;with one exception. Caliburn does not have a Bootstrapper currently. At this time, you would inherit from CaliburnApplication and override CreateRootModel. In the coming months, Caliburn&amp;rsquo;s custom application class will be replaced by a bootstrapper mechanism similar to Caliburn.Micro.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=60993" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.06.09.93/Caliburn.Micro.Hello.zip" length="6350" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/databinding/default.aspx">databinding</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category></item><item><title>MVVM Study – Segue - Introducing Caliburn.Micro</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/04/mvvm-study-segue-introducing-caliburn-micro.aspx</link><pubDate>Sun, 04 Jul 2010 20:45:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:60979</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>12</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=60979</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/04/mvvm-study-segue-introducing-caliburn-micro.aspx#comments</comments><description>&lt;p&gt;When my &lt;a target="_blank" href="http://live.visitmix.com/MIX10/Sessions/EX15"&gt;&amp;ldquo;Build Your Own MVVM Framework&amp;rdquo;&lt;/a&gt; talk was chosen for Mix10, I put a temporary hold on this series of blog posts. I wanted to dedicate significant time to working on a sample framework and demo that would make a top notch Mix presentation. 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 &amp;ldquo;official&amp;rdquo; version of what I had shown. That, coupled with the coming of Windows Phone 7, impressed upon me a need to have a more &amp;ldquo;lean and mean&amp;rdquo; framework. As a result, I&amp;rsquo;ve spent my spare time over the last six weeks building just that. My vision was to take 90% of Caliburn&amp;rsquo;s features and squash them into 10% of the code. I also hoped I could fit it in about 50k, give or take. 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. I call this new framework &lt;strong&gt;&lt;a target="_blank" href="http://caliburnmicro.codeplex.com/"&gt;Calburn.Micro&lt;/a&gt;&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;&lt;a target="_blank" href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt; consists of one ~50k assembly 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,000 LOC total, so you can easily go through the whole codebase in an afternoon and hold it in your head. That&amp;rsquo;s less than 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. So, it looks like I was able to meat my code quantity and size goals.&amp;nbsp; But 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&amp;rsquo;s a brief list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ActionMessages&lt;/strong&gt; &amp;ndash; The Action mechanism allows you to &amp;ldquo;bind&amp;rdquo; UI triggers, such as a Button&amp;rsquo;s &amp;ldquo;Click&amp;rdquo; 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&amp;rsquo;s signature. This mechanism also allows the &amp;ldquo;Action.Target&amp;rdquo; 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 &amp;ldquo;message&amp;rdquo; 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 &amp;ldquo;bubbling&amp;rdquo; nature of Acton Messages is extremely powerful and very helpful especially in master/detail scenarios. In addition to invocation, the mechanism supports a &amp;ldquo;CanExecute&amp;rdquo; guard. If the Action has a corresponding Property or Method with the same name, but precede by the word &amp;ldquo;Can,&amp;rdquo; the invocation of the Action will be blocked and the UI will be disabled. Actions also support Coroutines (see below). That&amp;rsquo;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&amp;rsquo;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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action Conventions&lt;/strong&gt; &amp;ndash; 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 &amp;ldquo;Save&amp;rdquo; on your ViewModel and a Button named &amp;ldquo;Save&amp;rdquo; in your UI, we will automatically create an EventTrigger for the &amp;ldquo;Click&amp;rdquo; event and assign an ActionMessage for the &amp;ldquo;Save&amp;rdquo; method. Furthermore, we will inspect the method&amp;rsquo;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 &amp;ldquo;MouseMove&amp;rdquo; instead of &amp;ldquo;Click&amp;rdquo; if you really wanted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Binding Conventions&lt;/strong&gt; &amp;ndash; 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 &lt;em&gt;and&lt;/em&gt; the SelectedItem of a Selector based on naming patterns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Screens and Conductors &amp;ndash; &lt;/strong&gt;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&amp;rsquo;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&amp;rsquo;ll find that Caliburn.Micro&amp;rsquo;s screen implementation is quite thorough and even handles asynchronous shutdown scenarios with ease.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Event Aggregator&lt;/strong&gt; &amp;ndash; Coming in at about 75LOC, Caliburn.Micro&amp;rsquo;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&amp;lt;TMessage&amp;gt;. References to handlers are held weakly and publication occurs on the UI thread.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coroutines&lt;/strong&gt; &amp;ndash; Any action can optionally choose to return IResult or IEnumerable&amp;lt;IResult&amp;gt;, 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&amp;rsquo;s View without needing to hold a reference to it at any time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ViewLocator&lt;/strong&gt; &amp;ndash; 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=&amp;rdquo;Master&amp;rdquo; we would search for MyApplication.Views.Shell.Master. Of coarse, all this is customizable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WindowManager&lt;/strong&gt; &amp;ndash; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PropertyChangedBase and BindableCollection&lt;/strong&gt; &amp;ndash; 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&amp;lt;T&amp;gt;, but that ensures that all its events are raised on the UI thread as well.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bootstrapper&lt;/strong&gt; &amp;ndash; What&amp;rsquo;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&amp;rsquo;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&amp;rsquo;s pretty simple. You&amp;rsquo;ll see how that works in my next blog post.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logging&lt;/strong&gt; &amp;ndash; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MVVM and MVP&lt;/strong&gt; &amp;ndash; In case it isn&amp;rsquo;t obvious, this framework enables MVVM. MVVM isn&amp;rsquo;t hard on it&amp;rsquo;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&amp;hellip;and we want it to be easy to do so. That&amp;rsquo;s what this is about. If you prefer using Supervising Controller and PassiveView to MVVM, go right ahead. You&amp;rsquo;ll find that Caliburn.Micro can help you a lot, particularly it&amp;rsquo;s Screen/ScreenConductor implementation.*** If you are &lt;em&gt;not&lt;/em&gt; interested in any of the goals I just mentioned, you&amp;rsquo;d best move along. This framework isn&amp;rsquo;t for you.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just to be clear, this isn&amp;rsquo;t a toy framework. I&amp;rsquo;m using it on two Silverlight 4 applications that I&amp;rsquo;m building right now. The experience has been good and I haven&amp;rsquo;t had a need for anything beyond what it provides. As I said, I really focused on supporting the core and most commonly used features from Caliburn v2. In fact, &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt; is going to be my default framework moving forward and I recommend that if you are starting a new project you begin with &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/"&gt;the Micro framework&lt;/a&gt;. I&amp;rsquo;ve been careful to keep the application developer API consistent with the full version of &lt;a target="_blank" href="http://caliburn.codeplex.com/"&gt;Caliburn&lt;/a&gt;. In fact, some of the improvements I made in Caliburn.Micro are going to be folded back into Caliburn v2 in the coming months. What&amp;rsquo;s the good part about that? You can start developing with &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt;, then if you hit edge cases or have some other need to move to &lt;a target="_blank" href="http://caliburn.codeplex.com/"&gt;Caliburn&lt;/a&gt;, you will be able to do so with little or no changes in your application.**&lt;/p&gt;
&lt;p&gt;In the coming months I&amp;rsquo;ll be blogging extensively about &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt;. In fact, I&amp;rsquo;m planning to take you on a tour of the entire codebase. Keeping with the spirit of &amp;ldquo;Build Your Own&amp;hellip;&amp;rdquo; I want developers to understand how this little framework works, inside and out. I&amp;rsquo;ve intentionally chosen Mercurial for source control, because I want developers to take ownership. While I&amp;rsquo;ve done some work to make the most important parts of the framework extensible, I&amp;rsquo;m hoping to see many Forks, each with their own customizations &lt;em&gt;unique to their application&amp;rsquo;s needs&lt;/em&gt;. &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;*When compressed into a .xap, Caliburn.Micro is about 24k. Also, it can be built for WPF3.5 and SL3. Though the SL3 version will be short one feature at runtime (ActionMessage Parameters databound to Elements) due to unfinished work in the SL3 DependencyObject/DepencenyProperty system. That&amp;rsquo;s actually true for the current WP7 build as well.&lt;/p&gt;
&lt;p&gt;**What are the differences between Caliburn and Caliburn.Micro? Caliburn has more features and supports a lot of edge cases. Also, the configuration and extensibility models are different. I&amp;rsquo;ll be talking about this in more detail in the future.&lt;/p&gt;
&lt;p&gt;***The whole ScreenConductor piece is actually a Supervising Controller implementation&amp;hellip;shshshsh&amp;hellip;don&amp;rsquo;t tell anyone&amp;hellip;but I almost always use a combination of MVVM and Supervising Controller (and other patterns). I like to use the best tool for the job.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=60979" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/databinding/default.aspx">databinding</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVVM/default.aspx">MVVM</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/UI+Architecture/default.aspx">UI Architecture</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn+Micro/default.aspx">Caliburn Micro</category></item><item><title>Caliburn Silverlight Navigation Walkthrough: Introduction</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2009/12/03/caliburn-silverlight-navigation-walkthrough-introduction.aspx</link><pubDate>Fri, 04 Dec 2009 03:08:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:54310</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=54310</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2009/12/03/caliburn-silverlight-navigation-walkthrough-introduction.aspx#comments</comments><description>&lt;p&gt;Over the next several months I am going to be releasing various starter kits/samples for Caliburn.&amp;nbsp; Each sample will demonstrate a different application style.&amp;nbsp; I&amp;rsquo;ve factored each sample so that it has a reusable mini-framework, allowing developers to easily take the shell and start plugging in their own content.&amp;nbsp; Each sample will also be accompanied by several blog posts explaining the architecture, use of Caliburn and various points of interest. The samples will be progressive in nature.&amp;nbsp; I&amp;rsquo;ll talk about more &amp;ldquo;getting started with Caliburn&amp;rdquo; type material with the first sample than I will with later samples; those will focus more on various problem/solution topics.&lt;/p&gt;
&lt;p&gt;The first sample I am releasing is a Silverlight Navigation Shell.&amp;nbsp; &lt;a href="http://caliburn.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34985"&gt;Go on and get the source code.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Features&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MVVM Approach &lt;/li&gt;
&lt;li&gt;Static Modules &lt;/li&gt;
&lt;li&gt;Lazy Modules (on demand load from Server) &lt;/li&gt;
&lt;li&gt;IoC Integration (using Unity but works equally with 7 containers without changing application code) &lt;/li&gt;
&lt;li&gt;Deep Linking (Browser History, Forward/Back Button and direct Url support; including lazy modules) &lt;/li&gt;
&lt;li&gt;Modal Dialogs &lt;/li&gt;
&lt;li&gt;Message Boxes &lt;/li&gt;
&lt;li&gt;Loader UI &lt;/li&gt;
&lt;li&gt;Actions &lt;/li&gt;
&lt;li&gt;An IResult Library      
&lt;ul&gt;
&lt;li&gt;Modals &lt;/li&gt;
&lt;li&gt;Navigations (including composite navigations) &lt;/li&gt;
&lt;li&gt;File Dialogs &lt;/li&gt;
&lt;li&gt;Message Boxes &lt;/li&gt;
&lt;li&gt;Loader &lt;/li&gt;
&lt;li&gt;WebClient &lt;/li&gt;
&lt;li&gt;Animation &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Customizable Dialog Chrome &lt;/li&gt;
&lt;li&gt;Resource Management &lt;/li&gt;
&lt;li&gt;Screen Lifecycle &lt;/li&gt;
&lt;li&gt;Passing Data to View Models &lt;/li&gt;
&lt;li&gt;Custom Screen Shutdown &lt;/li&gt;
&lt;li&gt;Convention over Configuration &lt;/li&gt;
&lt;li&gt;Hierarchical View Models &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Solution Structure&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; &lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/Solution_5F00_572F8537.gif"&gt;&lt;img height="1038" width="465" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/Solution_5F00_thumb_5F00_51E09E86.gif" alt="Solution" border="0" title="Solution" style="border-right-width:0px;display:block;float:none;border-top-width:0px;border-bottom-width:0px;margin-left:auto;border-left-width:0px;margin-right:auto;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Above you can see an image of the interesting parts of the solution.&amp;nbsp; The Framework project contains all the reusable components of the sample.&amp;nbsp; All modules depend upon this framework, but have no dependency on the shell itself.&amp;nbsp; The Baz project is an example of a lazy module.&amp;nbsp; It only references the Framework, is not referenced by the shell and is downloaded on demand at runtime.&amp;nbsp; Within the NavigationShell, however, you will find two static modules: Foo and Bar.&amp;nbsp; Although they are part of the shell project, they actually have no dependencies on the shell&amp;rsquo;s implementation details, which is confined to the Shell namespace.&lt;/p&gt;
&lt;p&gt;This solution is designed to be used as a starting point for navigation style applications. Simply remove the sample modules and begin adding your own.&amp;nbsp; In the future, it will be included as part of the Caliburn source download and I will keep it up to date with future versions of the framework as well as extend it with additional functionality.&lt;/p&gt;
&lt;p&gt;As I mentioned above, I am going to do several posts on this shell. You can look forward to digging into a few interesting details of the implementation and techniques soon.&lt;/p&gt;
&lt;p&gt;What are you waiting for?&amp;nbsp; &lt;a href="http://caliburn.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34985"&gt;Get the code.&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=54310" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/RIA/default.aspx">RIA</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category></item><item><title>Caliburn Tutorial Part 2</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2008/06/05/caliburn-tutorial-part-2.aspx</link><pubDate>Thu, 05 Jun 2008 14:42:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:40885</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=40885</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2008/06/05/caliburn-tutorial-part-2.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://blog.hightech.ir/"&gt;Hadi &lt;/a&gt;has just posted &lt;a href="http://blog.hightech.ir/2008/06/wpf-composite-application-with-caliburn.html"&gt;part 2&lt;/a&gt; of his tutorial on building composite applications with Caliburn.&amp;nbsp; In this post he covers basic usage of the EventBroker, ActionMessages and shows one way of putting the pieces together by using the PresenterHost control.&amp;nbsp; Great job!&lt;br /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=40885" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/.NET+3.0/default.aspx">.NET 3.0</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/databinding/default.aspx">databinding</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF_2F00_e/default.aspx">WPF/e</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category></item><item><title>Caliburn Tutorials are on their way!</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2008/06/01/caliburn-tutorials-are-on-their-way.aspx</link><pubDate>Sun, 01 Jun 2008 23:55:36 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:40832</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=40832</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2008/06/01/caliburn-tutorials-are-on-their-way.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://blog.hightech.ir/"&gt;Hadi Eskandari&lt;/a&gt; has begun blogging about Caliburn.&amp;#160; He&amp;#39;s putting together a multi-part series detailing the steps necessary to get started building your first application.&amp;#160; Thanks for this great contribution Hadi!&amp;#160; You can read the first post in his series &lt;a href="http://blog.hightech.ir/2008/05/wpf-composite-application-with-caliburn.html"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=40832" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/WPF/default.aspx">WPF</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/.NET+3.0/default.aspx">.NET 3.0</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Xaml/default.aspx">Xaml</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Caliburn/default.aspx">Caliburn</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Tutorial/default.aspx">Tutorial</category></item></channel></rss>