<?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 : MEF, WP7</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/tags/MEF/WP7/default.aspx</link><description>Tags: MEF, WP7</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><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 Pt. 5 – IResult and Coroutines</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2010/08/21/caliburn-micro-soup-to-nuts-part-5-iresult-and-coroutines.aspx</link><pubDate>Sat, 21 Aug 2010 18:31:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:61612</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=61612</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2010/08/21/caliburn-micro-soup-to-nuts-part-5-iresult-and-coroutines.aspx#comments</comments><description>&lt;p&gt;Before our &lt;a target="_blank" href="http://devlicio.us/blogs/rob_eisenberg/archive/2010/08/07/caliburn-micro-soup-to-nuts-pt-4-working-with-windows-phone-7.aspx"&gt;WP7 detour&lt;/a&gt;, we were deep &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 thick of Actions&lt;/a&gt;. I mentioned that there was one more compelling feature of the Actions concept called Coroutines. If you haven&amp;rsquo;t heard that term before, here&amp;rsquo;s what &lt;a target="_blank" href="http://en.wikipedia.org/wiki/Coroutine"&gt;wikipedia&lt;/a&gt;* has to say:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In &lt;a href="http://en.wikipedia.org/wiki/Computer_science"&gt;computer science&lt;/a&gt;, &lt;strong&gt;coroutines&lt;/strong&gt; are program components that generalize &lt;a href="http://en.wikipedia.org/wiki/Subroutine"&gt;subroutines&lt;/a&gt; to allow multiple entry points for suspending and resuming execution at certain locations. Coroutines are well-suited for implementing more familiar program components such as &lt;a href="http://en.wikipedia.org/wiki/Cooperative_multitasking"&gt;cooperative tasks&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Iterator"&gt;iterators&lt;/a&gt;,&lt;a href="http://en.wikipedia.org/wiki/Lazy_evaluation"&gt;infinite lists&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Pipeline_(software)"&gt;pipes&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here&amp;rsquo;s one way you can thing about it: Imagine being able to execute a method, then pause it&amp;rsquo;s execution on some statement, go do something else, then come back and resume execution where you left off. This technique is extremely powerful in task-based programming, especially when those tasks need to run asynchronously. For example, let&amp;rsquo;s say we have a ViewModel that needs to call a web service asynchronously, then it needs to take the results of that, do some work on it and call another web service asynchronously. Finally, it must then display the result in a modal dialog and respond to the user&amp;rsquo;s dialog selection with another asynchronous task. Accomplishing this with the standard event-driven async model is not a pleasant experience. However, this is a simple task to accomplish by using coroutines. The problem&amp;hellip;C# doesn&amp;rsquo;t implement coroutines natively. Fortunately, we can (sort of) build them on top of iterators.&lt;/p&gt;
&lt;p&gt;There are two things necessary to take advantage of this feature in Caliburn.Micro: First, implement the IResult interface on some class, representing the task you wish to execute; Second, yield instances of IResult from an Action.** Let&amp;rsquo;s make this more concrete. Say we had a Silverlight application where we wanted to dynamically download and show screens not part of the main package. First we would probably want to show a &amp;ldquo;Loading&amp;rdquo; indicator, then asynchronously download the external package, next hide the &amp;ldquo;Loading&amp;rdquo; indicator and finally navigate to a particular screen inside the dynamic module. Here&amp;rsquo;s what the code would look like if your first screen wanted to use coroutines to navigate to a dynamically loaded second screen:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System.Collections.Generic;
using System.ComponentModel.Composition;

[Export(typeof(ScreenOneViewModel))]
public class ScreenOneViewModel
{
    public IEnumerable&amp;lt;IResult&amp;gt; GoForward()
    {
        yield return Loader.Show(&amp;quot;Downloading...&amp;quot;);
        yield return new LoadCatalog(&amp;quot;Caliburn.Micro.Coroutines.External.xap&amp;quot;);
        yield return Loader.Hide();
        yield return new ShowScreen(&amp;quot;ExternalScreen&amp;quot;);
    }
}&lt;/pre&gt;
&lt;p&gt;First, notice that the Action &amp;ldquo;GoForward&amp;rdquo; has a return type of IEnumerable&amp;lt;IResult&amp;gt;. This is critical for using coroutines. The body of the method has four yield statements. Each of these yields is returning an instance of IResult. The first is a result to show the &amp;ldquo;Downloading&amp;rdquo; indicator, the second to download the xap asynchronously, the third to hide the &amp;ldquo;Downloading&amp;rdquo; message and the fourth to show a new screen from the downloaded xap.&amp;nbsp; After each yield statement, the compiler will &amp;ldquo;pause&amp;rdquo; the execution of this method until that particular task completes. The first, third and fourth tasks are synchronous, while the second is asynchronous.&amp;nbsp; But the yield syntax allows you to write all the code in a sequential fashion, preserving the original workflow as a much more readable and declarative structure. To understand a bit more how this works, have a look at the IResult interface:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public interface IResult
{
    void Execute(ActionExecutionContext context);
    event EventHandler&amp;lt;ResultCompletionEventArgs&amp;gt; Completed;
}&lt;/pre&gt;
&lt;p&gt;It&amp;rsquo;s a fairly simple interface to implement. Simply write your code in the &amp;ldquo;Execute&amp;rdquo; method and be sure to raise the &amp;ldquo;Completed&amp;rdquo; event when you are done, whether it be a synchronous or an asynchronous task. Because coroutines occur inside of an Action, we provide you with an ActionExecutionContext useful in building UI-related IResult implementations. This allows the ViewModel a way to declaratively state it intentions in controlling the view without having any reference to a View or the need for interaction-based unit testing. Here&amp;rsquo;s what the ActionResultContext looks like:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class ActionExecutionContext
{
    public ActionMessage Message;
    public FrameworkElement Source;
    public object EventArgs;
    public object Target;
    public DependencyObject View;
    public MethodInfo Method;
    public Func&amp;lt;bool&amp;gt; CanExecute;
    public object this[string key];
}&lt;/pre&gt;
&lt;p&gt;And here&amp;rsquo;s an explanation of what all these properties mean:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Message &amp;ndash; The original ActionMessage that caused the invocation of this IResult.&lt;/li&gt;
&lt;li&gt;Source &amp;ndash; The FrameworkElement that triggered the execution of the Action.&lt;/li&gt;
&lt;li&gt;EventArgs &amp;ndash; Any event arguments associated with the trigger of the Action.&lt;/li&gt;
&lt;li&gt;Target &amp;ndash; The class instance on which the actual Action method exists.&lt;/li&gt;
&lt;li&gt;View &amp;ndash; The view associated with the Target.&lt;/li&gt;
&lt;li&gt;Method &amp;ndash; The MethodInfo specifying which method to invoke on the Target instance.&lt;/li&gt;
&lt;li&gt;CanExecute &amp;ndash; A function that returns true if the Action can be invoked, false otherwise.&lt;/li&gt;
&lt;li&gt;Key Index: A place to store/retrieve any additional metadata which may be used by extensions to the framework.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bearing that in mind, I wrote a naive Loader IResult that searches the VisualTree looking for the first instance of a BusyIndicator to use to display a loading message. Here&amp;rsquo;s the implementation:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System;
using System.Windows;
using System.Windows.Controls;

public class Loader : IResult
{
    readonly string message;
    readonly bool hide;

    public Loader(string message)
    {
        this.message = message;
    }

    public Loader(bool hide)
    {
        this.hide = hide;
    }

    public void Execute(ActionExecutionContext context)
    {
        var view = context.View as FrameworkElement;
        while(view != null)
        {
            var busyIndicator = view as BusyIndicator;
            if(busyIndicator != null)
            {
                if(!string.IsNullOrEmpty(message))
                    busyIndicator.BusyContent = message;
                busyIndicator.IsBusy = !hide;
                break;
            }

            view = view.Parent as FrameworkElement;
        }

        Completed(this, new ResultCompletionEventArgs());
    }

    public event EventHandler&amp;lt;ResultCompletionEventArgs&amp;gt; Completed = delegate { };

    public static IResult Show(string message = null)
    {
        return new Loader(message);
    }

    public static IResult Hide()
    {
        return new Loader(true);
    }
}&lt;/pre&gt;
&lt;p&gt;See how I took advantage of context.View? This opens up a lot of possibilities while maintaining separation between the view and the view model. Just to list a few interesting things you could do with IResult implementations: show a message box, show a VM-based modal dialog, show a VM-based Popup at the user&amp;rsquo;s mouse position, play an animation, show File Save/Load dialogs, place focus on a particular UI element based on VM properties rather than controls, etc. Of coarse, one of the biggest opportunities is calling web services. Let&amp;rsquo;s look at how you might do that, but by using a slightly different scenario, dynamically downloading a xap:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.ReflectionModel;
using System.Linq;

public class LoadCatalog : IResult
{
    static readonly Dictionary&amp;lt;string, DeploymentCatalog&amp;gt; Catalogs = new Dictionary&amp;lt;string, DeploymentCatalog&amp;gt;();
    readonly string uri;

    [Import]
    public AggregateCatalog Catalog { get; set; }

    public LoadCatalog(string relativeUri)
    {
        uri = relativeUri;
    }

    public void Execute(ActionExecutionContext context)
    {
        DeploymentCatalog catalog;

        if(Catalogs.TryGetValue(uri, out catalog))
            Completed(this, new ResultCompletionEventArgs());
        else
        {
            catalog = new DeploymentCatalog(uri);
            catalog.DownloadCompleted += (s, e) =&amp;gt;{
                if(e.Error == null)
                {
                    Catalogs[uri] = catalog;
                    Catalog.Catalogs.Add(catalog);
                    catalog.Parts
                        .Select(part =&amp;gt; ReflectionModelServices.GetPartType(part).Value.Assembly)
                        .Where(assembly =&amp;gt; !AssemblySource.Instance.Contains(assembly))
                        .Apply(x =&amp;gt; AssemblySource.Instance.Add(x));
                }
                else Loader.Hide().Execute(context);

                Completed(this, new ResultCompletionEventArgs {
                    Error = e.Error,
                    WasCancelled = false
                });
            };

            catalog.DownloadAsync();
        }
    }

    public event EventHandler&amp;lt;ResultCompletionEventArgs&amp;gt; Completed = delegate { };
}&lt;/pre&gt;
&lt;p&gt;In case it wasn&amp;rsquo;t clear, this sample is using MEF. Furthermore, we are taking advantage of the DeploymentCatalog created for Silverlight 4.&amp;nbsp; You don&amp;rsquo;t really need to know a lot about MEF or DeploymentCatalog to get the takeaway. Just take note of the fact that we wire for the DownloadCompleted event and make sure to fire the IResult.Completed event in its handler. This is what enables the async pattern to work. We also make sure to check the error and pass that along in the ResultCompletionEventArgs. Speaking of that, here&amp;rsquo;s what that class looks like:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;public class ResultCompletionEventArgs : EventArgs
{
    public Exception Error;
    public bool WasCancelled;
}&lt;/pre&gt;
&lt;p&gt;Caliburn.Micro&amp;rsquo;s enumerator checks these properties after it get&amp;rsquo;s called back from each IResult. If there is either an error or WasCancelled is set to true, we stop execution. You can use this to your advantage. Let&amp;rsquo;s say you create an IResult for the OpenFileDialog. You could check the result of that dialog, and if the user canceled it, set WasCancelled on the event args. By doing this, you can write an action that assumes that if the code following the Dialog.Show executes, the user must have selected a file. This sort of technique can simplify the logic in such situations. Obviously, you could use the same technique for the SaveFileDialog or any confirmation style message box if you so desired. My favorite part of the LoadCatalog implementation shown above, is that the original implementation was written by a CM user! Thanks janoveh for this awesome submission! As a side note, one of the things we added to the CM project site is &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/documentation"&gt;a &amp;ldquo;Recipes&amp;rdquo; section&lt;/a&gt;. We are going to be adding more common solutions such as this to that area in the coming months. So, it will be a great place to check for cool plugins and customizations to the framework.***&lt;/p&gt;
&lt;p&gt;Another thing you can do is create a series of IResult implementations built around your application&amp;rsquo;s shell. That is what the ShowScreen result used above does. Here is its implementation:&lt;/p&gt;
&lt;pre name="code" class="c#:nogutter:nocontrols"&gt;using System;
using System.ComponentModel.Composition;

public class ShowScreen : IResult
{
    readonly Type screenType;
    readonly string name;

    [Import]
    public IShell Shell { get; set; }

    public ShowScreen(string name)
    {
        this.name = name;
    }

    public ShowScreen(Type screenType)
    {
        this.screenType = screenType;
    }

    public void Execute(ActionExecutionContext context)
    {
        var screen = !string.IsNullOrEmpty(name)
            ? IoC.Get&amp;lt;object&amp;gt;(name)
            : IoC.GetInstance(screenType, null);

        Shell.ActivateItem(screen);
        Completed(this, new ResultCompletionEventArgs());
    }

    public event EventHandler&amp;lt;ResultCompletionEventArgs&amp;gt; Completed = delegate { };

    public static ShowScreen Of&amp;lt;T&amp;gt;()
    {
        return new ShowScreen(typeof(T));
    }
}&lt;/pre&gt;
&lt;p&gt;This bring up another important feature of IResult. Before CM executes a result, it passes it through the IoC.BuildUp method allowing your container the opportunity to push dependencies in through the properties. This allows you to create them normally within your view models, while still allowing them to take dependencies on application services. In this case, we depend on IShell. You could also have your container injected, but in this case I chose to use the IoC static class internally. As a general rule, you should avoid pulling things from the container directly. However, I think it is acceptable when done inside of infrastructure code such as a ShowScreen IResult.&lt;/p&gt;
&lt;p&gt;I hope this gives some explanation and creative ideas for what can be accomplished with IResult. Be sure to check out the sample application attached. There&amp;rsquo;s a few other interesting things in there as well.&lt;/p&gt;
&lt;p&gt;* When I went to look up the &amp;ldquo;official&amp;rdquo; definition on wikipedia I was interested to see what it had to say about implementations in various languages. Scrolling down to the section on C#&amp;hellip;Caliburn was listed! Fun stuff. &lt;/p&gt;
&lt;p&gt;** You can also return a single instance of IResult without using IEnuermable&amp;lt;IResult&amp;gt; if you just want a simple way to execute a single task.&lt;/p&gt;
&lt;p&gt;*** If you want a sample of a truly awesome plugin we will be adding to the recipes section soon, &lt;a target="_blank" href="http://marcoamendola.wordpress.com/2010/08/10/a-caliburn-micro-recipe-filters/"&gt;check this out!&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=61612" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.06.16.12/Caliburn.Micro.Coroutines.zip" length="26128" 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/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/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></channel></rss>