<?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 : WP7, databinding, MVVM</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/tags/WP7/databinding/MVVM/default.aspx</link><description>Tags: WP7, databinding, MVVM</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Today….All Your Wildest Dreams Come True</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2012/08/02/today-all-your-wildest-dreams-come-true.aspx</link><pubDate>Thu, 02 Aug 2012 20:07:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:70251</guid><dc:creator>Rob Eisenberg</dc:creator><slash:comments>20</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/rob_eisenberg/rsscomments.aspx?PostID=70251</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2012/08/02/today-all-your-wildest-dreams-come-true.aspx#comments</comments><description>&lt;p&gt;If you fit into any one (or more) of these three categories&amp;hellip;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You like tabletop RPGs&lt;/li&gt;
&lt;li&gt;You build Xaml applications&lt;/li&gt;
&lt;li&gt;You build Html/JS applications&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;1. RPGWithMe&lt;/h2&gt;
&lt;p&gt;For some time I&amp;rsquo;ve been cranking away building my company&amp;rsquo;s first real product. I&amp;rsquo;m very excited to officially announce to you today that &lt;a target="_blank" href="http://www.rpgwithme.com/"&gt;RPGWithMe&lt;/a&gt; is live!&amp;nbsp; &lt;a target="_blank" href="http://www.rpgwithme.com/"&gt;RPGWithMe&lt;/a&gt; is a web-based platform centered around tabletop RPGs. If you play these games&amp;hellip;you are going to like this a lot. RPGWithMe provides four main feature areas in its initial launch:&lt;/p&gt;
&lt;h3&gt;Character Sheets&lt;/h3&gt;
&lt;p&gt;The industry&amp;rsquo;s most beautiful character sheets, fully interactive and free: Use them at the gametable on your tablet or laptop. They&amp;rsquo;re also fully integrated into our play-by-post and virtual tabletop experience. It&amp;#39;s as simple as uploading DDI or Hero Lab &lt;sup&gt;&amp;reg;&lt;/sup&gt; files. Custom character creation is coming soon&amp;hellip;&lt;/p&gt;
&lt;h3&gt;Campaign Management&lt;/h3&gt;
&lt;p&gt;We provide gorgeous home pages for your campaigns. Use our live-previewing editor to write wiki articles and pin them to your home page. Chronicle your adventure and automatically have your content indexed for later. Plus, access our enormous, high quality art library for use in your wiki or upload your own art.&lt;/p&gt;
&lt;h3&gt;Play-by-Post&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ve built our system from the ground up to support PbP. It fully integrates your player&amp;rsquo;s character sheets and your campaign wiki. It snapshots roll, magic, power and feat data and provides multiple views over your campaign&amp;rsquo;s activity feed with the ability to bookmark and integrate your character&amp;rsquo;s journals too.&lt;/p&gt;
&lt;h3&gt;Virtual Tabletop&lt;/h3&gt;
&lt;p&gt;Build maps, play out combat and track NPC stats. Our virtual table can be used to enhance PbP beyond anything you&amp;rsquo;ve seen. Of course, you can always use it as a realtime virtual table on it&amp;#39;s own and feel the power of integrated character sheets, rich activity feeds and campaign management.&lt;/p&gt;
&lt;div class="wlWriterEditableSmartContent" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:cab0da76-f4b8-44a2-a32b-bb0f199d7ae0" style="padding-bottom:0px;margin:0px auto;padding-left:0px;width:448px;padding-right:0px;display:block;float:none;padding-top:15px;"&gt;
&lt;div&gt;&lt;a target="_new" href="http://www.youtube.com/watch?v=ikKPz-zqe5U&amp;amp;feature=plcp"&gt;&lt;img style="border-style:none;" src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rob_5F00_eisenberg/videoe28113b8579a_5F00_5DA2CAC7.jpg" alt="" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style="width:448px;clear:both;font-size:.8em;"&gt;RPGWithMe Teaser&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;2. Caliburn.Micro WinRT&lt;/h2&gt;
&lt;p&gt;Thanks to the fantastic work of &lt;a target="_blank" href="http://compiledexperience.com/"&gt;Nigel Sampson&lt;/a&gt; and &lt;a target="_blank" href="http://www.markermetro.com/2012/08/technical/caliburn-micro-for-winrt-mvvm-magic-pixie-dust-for-everyone/"&gt;Keith Patton&lt;/a&gt; we now have support for &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/SourceControl/list/changesets"&gt;the full Caliburn.Micro feature set on WinRT&lt;/a&gt;. This is he initial port&amp;hellip;and its not an official release yet, so there&amp;rsquo;s bound to be bugs. But if you want to use CM to build your WinRT app, please start using this code and help us iron out the kinks&amp;hellip;.and naturally start enjoying the CM way of building apps on WinRT.&lt;/p&gt;
&lt;h2&gt;3. Durandal&lt;/h2&gt;
&lt;p&gt;Durandal is the essence of Caliburn.Micro re-imagined for HTML and Javascript. A very early version of the code is now &lt;a target="_blank" href="https://github.com/EisenbergEffect/Durandal"&gt;available on github&lt;/a&gt;. It is a very small amount of code built on top of three existing and established Javascript libraries: &lt;a target="_blank" href="http://jquery.com/"&gt;jQuery&lt;/a&gt;, &lt;a target="_blank" href="http://knockoutjs.com/"&gt;Knockout&lt;/a&gt; and &lt;a target="_blank" href="http://requirejs.org/"&gt;Require&lt;/a&gt;. Features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fully modularize your html and js the same way you would when building Caliburn.Micro applications. ie. Shell.js automatically locates Shell.html, binds and gets composed into the dom. Naturally you can change the conventions&amp;hellip;&lt;/li&gt;
&lt;li&gt;Leverage promises everywhere as the API uses no callbacks, but has CommonJS promises plumbed throughout&lt;/li&gt;
&lt;li&gt;Experience the first html/js framework where &lt;strong&gt;Composition&lt;/strong&gt; is embraced at the very core. The view/view-model composition features of Durandal are even more powerful than Caliburn.Micro.&lt;/li&gt;
&lt;li&gt;A simple app model provides you with an app start lifecycle, modal dialogs, message boxes and an event aggregator.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a pre-pre-pre-alpha version. There are no docs and just one sample at the moment. But, I wanted to get it out there so you could dig into the code, start playing with it and give me feedback. Of course I&amp;rsquo;ll add docs, more samples, tests, etc. Just in case you are wondering though, Durandal is already being used in production as the framework for RPGWithMe&amp;rsquo;s virtual tabletop. Various versions/pieces of it are being used by some of my clients&amp;hellip;details not available right now, but I hope to share more later.&lt;/p&gt;
&lt;p&gt;Things I would like to do with Durandal in the future:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Remove the Knockout dependency. I don&amp;rsquo;t like how knockout bindings work in html and I don&amp;rsquo;t like how observables invade your model code. Both are ugly, tedious and obscure the readability of the code.&amp;nbsp; I have a plan to fix both of these, but it&amp;rsquo;s non-trivial. I chose to put together this initial version based on knockout since it was already in heavy use and it was quick and easy. In the future I hope we can improve on that.&lt;/li&gt;
&lt;li&gt;Remove the jQuery dependency. Durandal only uses a few features of jQuery. So, eventually, I&amp;rsquo;d like to have an alternate solution without an external dependency. You can always use jQuery if you want to, but in the long term, I don&amp;rsquo;t want to force it on developers.&lt;/li&gt;
&lt;li&gt;Create a component model for building reusable controls. This should work similar to Xaml in that controls should have a distinct view written in html which can be replaced globally or on a per use basis. Controls should also support templated parts with the same characteristics.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ok. That&amp;rsquo;s enough news for today. Enjoy. Now&amp;hellip;I&amp;rsquo;m going to rest for a bit.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=70251" 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/game+development/default.aspx">game development</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/Control+Templates/default.aspx">Control Templates</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/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>Boo-yah!!! Caliburn.Micro v1.3 RTW is Here</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2012/01/20/boo-yah-caliburn-micro-v1-3-rtw-is-here.aspx</link><pubDate>Sat, 21 Jan 2012 01:32:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:69352</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=69352</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2012/01/20/boo-yah-caliburn-micro-v1-3-rtw-is-here.aspx#comments</comments><description>&lt;p&gt;I&amp;rsquo;m extremely pleased to announce &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/releases/view/80884"&gt;the release of Caliburn.Micro v1.3&lt;/a&gt;.&amp;nbsp; This is a great release with many bug fixes and several API improvements. We also support several new platforms. Here&amp;rsquo;s the highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for WP7 Mango&lt;/li&gt;
&lt;li&gt;Support for Silverlight 5&lt;/li&gt;
&lt;li&gt;Basic MVVM Support for WinRT/Metro&lt;/li&gt;
&lt;li&gt;Awesome improvements to ViewModelLocator/ViewLocator which allow easier customization of conventions.&lt;/li&gt;
&lt;li&gt;Improved Design-Time Support for Conventions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks to the great community who provided awesome feedback during this release cycle. Thanks also to those who spent time to provide fixes and pull requests for bugs as well as for API improvements. I&amp;rsquo;d like to add a special thanks to Chin Bae for excellent work on making our ViewLocator and ViewModelLocator both more extensible and more accessible for common customizations.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re still just getting started. Enjoy &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/releases/view/80884"&gt;the new bits&lt;/a&gt; and see what you can build!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=69352" 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/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><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/NuGet/default.aspx">NuGet</category><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/MVP/default.aspx">MVP</category></item><item><title>Caliburn.Micro v1.1 RTW</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2011/06/01/caliburn-micro-v1-1-rtw.aspx</link><pubDate>Wed, 01 Jun 2011 17:08:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:67427</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=67427</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2011/06/01/caliburn-micro-v1-1-rtw.aspx#comments</comments><description>&lt;p&gt;Today I&amp;rsquo;m happy to announce the release of &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/releases/view/67451"&gt;Caliburn.Micro v1.1&lt;/a&gt;. You can get it on &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/releases/view/67451"&gt;our project site&lt;/a&gt; or by &lt;a target="_blank" href="http://nuget.org/List/Packages/Caliburn.Micro"&gt;using Nuget&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve had a number of bug fixes, general improvements and a few new features added. Here&amp;rsquo;s the highlights:&lt;/p&gt;
&lt;p&gt;For WP7&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A new Tombstoning API based on ideas from Fluent NHibernate&lt;/li&gt;
&lt;li&gt;A new Launcher/Chooser API&lt;/li&gt;
&lt;li&gt;Strongly typed Navigation&lt;/li&gt;
&lt;li&gt;SimpleContainer included&lt;/li&gt;
&lt;li&gt;The full phone lifecycle is made easy to work with
&lt;ul&gt;
&lt;li&gt;ie. we figure out whether your app is actually Resurrecting of just Continuing and tell you&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For WPF&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for the Client Profile&lt;/li&gt;
&lt;li&gt;Better support for WinForms integration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All Platforms&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A powerful new RegEx-based ViewLocator and ViewModelLocator
&lt;ul&gt;
&lt;li&gt;Special thanks to &lt;a href="http://www.codeplex.com/site/users/view/cb55555"&gt;cb55555&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Polymorphic subscriptions and custom thread marshaling for the EventAggregator&lt;/li&gt;
&lt;li&gt;Numerous bug fixes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can get the complete list of changes in the release notes. Enjoy!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=67427" 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/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><category domain="http://devlicio.us/blogs/rob_eisenberg/archive/tags/NuGet/default.aspx">NuGet</category></item><item><title>Two Caliburn Releases in One Day!</title><link>http://devlicio.us/blogs/rob_eisenberg/archive/2011/02/21/two-caliburn-releases-in-one-day.aspx</link><pubDate>Mon, 21 Feb 2011 19:18:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:66614</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=66614</wfw:commentRss><comments>http://devlicio.us/blogs/rob_eisenberg/archive/2011/02/21/two-caliburn-releases-in-one-day.aspx#comments</comments><description>&lt;p&gt;Today, I&amp;#39;m happy to make available the Release Candidates for both &lt;a target="_blank" href="http://caliburn.codeplex.com/releases/view/61383"&gt;Caliburn 2.0&lt;/a&gt;&amp;nbsp;and &lt;a target="_blank" href="http://caliburnmicro.codeplex.com/releases/view/61385"&gt;Caliburn.Micro 1.0&lt;/a&gt;! The docs for both have been updated significantly, though they will continue to evolve over the coming months. Get em&amp;#39; while they&amp;#39;re hot!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=66614" 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/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></channel></rss>