caliburnmicro Wiki Rss Feedhttp://caliburnmicro.codeplex.com/caliburnmicro Wiki Rss DescriptionUpdated Wiki: Documentationhttps://caliburnmicro.codeplex.com/documentation?version=101<div class="wikidoc"><h1><b>This project has moved to github for v2.0.</b></h1>
<h1><a href="https://github.com/Caliburn-Micro">https://github.com/Caliburn-Micro</a></h1>
<h1>Documentation</h1>
Caliburn.Micro is a community project and as such we cannot provide enterprise grade documentation.<br />Fortunately there are many good articles and tutorials on the web to fill the missing pieces.<br />
<ul><li>Getting Started
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Introduction&referringTitle=Documentation">Introduction</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Obtain%20and%20Build%20the%20Code&referringTitle=Documentation">Obtain and Build the Code</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Nuget&referringTitle=Documentation">Nuget</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Cheat%20Sheet&referringTitle=Documentation">Cheat Sheet</a></li></ul></li></ul>
<ul><li>Soup to Nuts
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=Documentation">Basic Configuration, Actions and Conventions</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Customizing%20The%20Bootstrapper&referringTitle=Documentation">Customizing The Bootstrapper</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Actions&referringTitle=Documentation">All About Actions</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Working%20with%20Windows%20Phone&referringTitle=Documentation">Working with Windows Phone</a> (v1.1)</li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Working%20with%20WinRT&referringTitle=Documentation">Working with WinRT</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=IResult%20and%20Coroutines&referringTitle=Documentation">IResult and Coroutines</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Screens%2c%20Conductors%20and%20Composition&referringTitle=Documentation">Screens, Conductors and Composition</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Conventions&referringTitle=Documentation">All About Conventions</a>
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=View%2fViewModel%20Naming%20Conventions&referringTitle=Documentation">View&#47;ViewModel Naming Conventions</a> (v1.3)</li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Handling%20Custom%20Conventions&referringTitle=Documentation">Handling Custom Conventions</a> (v1.3)</li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Using%20the%20NameTransformer&referringTitle=Documentation">Using the NameTransformer - Advanced</a> (v1.1)</li></ul></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Event%20Aggregator&referringTitle=Documentation">The Event Aggregator</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Simple%20IoC%20Container&referringTitle=Documentation">The Simple IoC Container</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Service%20Locator&referringTitle=Documentation">The Service Locator</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Window%20Manager&referringTitle=Documentation">The Window Manager</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Design-Time%20Support&referringTitle=Documentation">Design-Time Support</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Async%20%28Task%29%20Support&referringTitle=Documentation">Async &#40;Task&#41; Support</a></li></ul></li></ul>
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Community%20Articles%20and%20Tutorials&referringTitle=Documentation">Community Articles and Tutorials</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=3rd%20Party%20Extensions&referringTitle=Documentation">3rd Party Extensions</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Contests&referringTitle=Documentation">Contests</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Recipes&referringTitle=Documentation">Recipes</a></li></ul>
<br /><br /><br /></div><div class="ClearBoth"></div>EisenbergEffectSat, 26 Apr 2014 19:34:14 GMTUpdated Wiki: Documentation 20140426073414PUpdated Wiki: Homehttps://caliburnmicro.codeplex.com/wikipage?version=51<div class="wikidoc"><h1><b>This project has moved to github for v2.0</b></h1>
<h1><a href="https://github.com/Caliburn-Micro">https://github.com/Caliburn-Micro</a></h1></div><div class="ClearBoth"></div>EisenbergEffectSat, 26 Apr 2014 19:33:52 GMTUpdated Wiki: Home 20140426073352PUpdated Wiki: Documentationhttps://caliburnmicro.codeplex.com/documentation?version=100<div class="wikidoc"><h1><b>This project has moved to github for v2.0.</b></h1>
<h1><a href="https://github.com/BlueSpire/Caliburn.Micro">https://github.com/BlueSpire/Caliburn.Micro</a></h1>
<h1>Documentation</h1>
Caliburn.Micro is a community project and as such we cannot provide enterprise grade documentation.<br />Fortunately there are many good articles and tutorials on the web to fill the missing pieces.<br />
<ul><li>Getting Started
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Introduction&referringTitle=Documentation">Introduction</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Obtain%20and%20Build%20the%20Code&referringTitle=Documentation">Obtain and Build the Code</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Nuget&referringTitle=Documentation">Nuget</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Cheat%20Sheet&referringTitle=Documentation">Cheat Sheet</a></li></ul></li></ul>
<ul><li>Soup to Nuts
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=Documentation">Basic Configuration, Actions and Conventions</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Customizing%20The%20Bootstrapper&referringTitle=Documentation">Customizing The Bootstrapper</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Actions&referringTitle=Documentation">All About Actions</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Working%20with%20Windows%20Phone&referringTitle=Documentation">Working with Windows Phone</a> (v1.1)</li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Working%20with%20WinRT&referringTitle=Documentation">Working with WinRT</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=IResult%20and%20Coroutines&referringTitle=Documentation">IResult and Coroutines</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Screens%2c%20Conductors%20and%20Composition&referringTitle=Documentation">Screens, Conductors and Composition</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Conventions&referringTitle=Documentation">All About Conventions</a>
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=View%2fViewModel%20Naming%20Conventions&referringTitle=Documentation">View&#47;ViewModel Naming Conventions</a> (v1.3)</li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Handling%20Custom%20Conventions&referringTitle=Documentation">Handling Custom Conventions</a> (v1.3)</li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Using%20the%20NameTransformer&referringTitle=Documentation">Using the NameTransformer - Advanced</a> (v1.1)</li></ul></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Event%20Aggregator&referringTitle=Documentation">The Event Aggregator</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Simple%20IoC%20Container&referringTitle=Documentation">The Simple IoC Container</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Service%20Locator&referringTitle=Documentation">The Service Locator</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Window%20Manager&referringTitle=Documentation">The Window Manager</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Design-Time%20Support&referringTitle=Documentation">Design-Time Support</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Async%20%28Task%29%20Support&referringTitle=Documentation">Async &#40;Task&#41; Support</a></li></ul></li></ul>
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Community%20Articles%20and%20Tutorials&referringTitle=Documentation">Community Articles and Tutorials</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=3rd%20Party%20Extensions&referringTitle=Documentation">3rd Party Extensions</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Contests&referringTitle=Documentation">Contests</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Recipes&referringTitle=Documentation">Recipes</a></li></ul>
<br /><br /><br /></div><div class="ClearBoth"></div>EisenbergEffectMon, 03 Feb 2014 20:58:29 GMTUpdated Wiki: Documentation 20140203085829PUpdated Wiki: Homehttps://caliburnmicro.codeplex.com/wikipage?version=50<div class="wikidoc"><h1><b>This project has moved to github for v2.0</b></h1>
<h1><a href="https://github.com/BlueSpire/Caliburn.Micro">https://github.com/BlueSpire/Caliburn.Micro</a></h1></div><div class="ClearBoth"></div>EisenbergEffectMon, 03 Feb 2014 20:57:35 GMTUpdated Wiki: Home 20140203085735PUpdated Wiki: Documentationhttps://caliburnmicro.codeplex.com/documentation?version=99<div class="wikidoc"><h1><b>This project has moved to github.</b></h1>
<h1><a href="https://github.com/BlueSpire/Caliburn.Micro">https://github.com/BlueSpire/Caliburn.Micro</a></h1>
<h1>Documentation</h1>
Caliburn.Micro is a community project and as such we cannot provide enterprise grade documentation.<br />Fortunately there are many good articles and tutorials on the web to fill the missing pieces.<br />
<ul><li>Getting Started
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Introduction&referringTitle=Documentation">Introduction</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Obtain%20and%20Build%20the%20Code&referringTitle=Documentation">Obtain and Build the Code</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Nuget&referringTitle=Documentation">Nuget</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Cheat%20Sheet&referringTitle=Documentation">Cheat Sheet</a></li></ul></li></ul>
<ul><li>Soup to Nuts
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=Documentation">Basic Configuration, Actions and Conventions</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Customizing%20The%20Bootstrapper&referringTitle=Documentation">Customizing The Bootstrapper</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Actions&referringTitle=Documentation">All About Actions</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Working%20with%20Windows%20Phone&referringTitle=Documentation">Working with Windows Phone</a> (v1.1)</li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Working%20with%20WinRT&referringTitle=Documentation">Working with WinRT</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=IResult%20and%20Coroutines&referringTitle=Documentation">IResult and Coroutines</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Screens%2c%20Conductors%20and%20Composition&referringTitle=Documentation">Screens, Conductors and Composition</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Conventions&referringTitle=Documentation">All About Conventions</a>
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=View%2fViewModel%20Naming%20Conventions&referringTitle=Documentation">View&#47;ViewModel Naming Conventions</a> (v1.3)</li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Handling%20Custom%20Conventions&referringTitle=Documentation">Handling Custom Conventions</a> (v1.3)</li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Using%20the%20NameTransformer&referringTitle=Documentation">Using the NameTransformer - Advanced</a> (v1.1)</li></ul></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Event%20Aggregator&referringTitle=Documentation">The Event Aggregator</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Simple%20IoC%20Container&referringTitle=Documentation">The Simple IoC Container</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Service%20Locator&referringTitle=Documentation">The Service Locator</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Window%20Manager&referringTitle=Documentation">The Window Manager</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Design-Time%20Support&referringTitle=Documentation">Design-Time Support</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Async%20%28Task%29%20Support&referringTitle=Documentation">Async &#40;Task&#41; Support</a></li></ul></li></ul>
<ul><li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Community%20Articles%20and%20Tutorials&referringTitle=Documentation">Community Articles and Tutorials</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=3rd%20Party%20Extensions&referringTitle=Documentation">3rd Party Extensions</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Contests&referringTitle=Documentation">Contests</a></li>
<li><a href="https://caliburnmicro.codeplex.com/wikipage?title=Recipes&referringTitle=Documentation">Recipes</a></li></ul>
<br /><br /><br /></div><div class="ClearBoth"></div>EisenbergEffectMon, 03 Feb 2014 20:57:07 GMTUpdated Wiki: Documentation 20140203085707PUpdated Wiki: Homehttps://caliburnmicro.codeplex.com/wikipage?version=49<div class="wikidoc"><h1><b>This project has moved to github.</b></h1>
<h1><a href="https://github.com/BlueSpire/Caliburn.Micro">https://github.com/BlueSpire/Caliburn.Micro</a></h1></div><div class="ClearBoth"></div>EisenbergEffectMon, 03 Feb 2014 20:54:12 GMTUpdated Wiki: Home 20140203085412PUpdated Wiki: Homehttps://caliburnmicro.codeplex.com/wikipage?version=48<div class="wikidoc"><h1><b>This project has moved to github: <a href="https://github.com/BlueSpire/Caliburn.Micro">https://github.com/BlueSpire/Caliburn.Micro</a></b></h1></div><div class="ClearBoth"></div>EisenbergEffectMon, 03 Feb 2014 20:53:43 GMTUpdated Wiki: Home 20140203085343PUpdated Wiki: Homehttps://caliburnmicro.codeplex.com/wikipage?version=47<div class="wikidoc"><h1>This project has moved to github: <a href="https://github.com/BlueSpire/Caliburn.Micro">https://github.com/BlueSpire/Caliburn.Micro</a></h1></div><div class="ClearBoth"></div>EisenbergEffectMon, 03 Feb 2014 20:52:28 GMTUpdated Wiki: Home 20140203085228PUpdated Wiki: Homehttps://caliburnmicro.codeplex.com/wikipage?version=46<div class="wikidoc"><h4>Caliburn.Micro is a small, yet powerful framework, designed for building applications across all XAML platforms. With strong support for MVVM and other proven UI patterns, Caliburn.Micro will enable you to build your solution quickly, without the need to sacrifice code quality or testability.</h4>
<h1>This project has moved to github: <a href="https://github.com/BlueSpire/Caliburn.Micro">https://github.com/BlueSpire/Caliburn.Micro</a></h1>
This community project is sponsored by <a href="http://www.xceedsoft.com/redirect/ad/index.aspx?adtype=143">Xceed</a>, makers of <a href="http://www.xceedsoft.com/redirect/ad/index.aspx?adtype=141">Xceed DataGrid for WPF</a>, the enterprise datagrid that provides a rich, fluid, and high performance user experience. 50% off any Xceed product with coupon code G00B8T. Xceed also offers <a href="http://extendedsilverlight.codeplex.com">Extended Silverlight Toolkit</a> and <a href="http://wpftoolkit.codeplex.com">Extended WPF Toolkit</a> here on Codeplex.<br /><br />The Caliburn.Micro team uses <a href="http://www.jetbrains.com/resharper/">ReSharper</a> by <a href="http://www.jetbrains.com/">JetBrains</a>.<br /><br /><b>If you like what you find here, please consider <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=VZURNT9MCX3CS">donating</a>.</b></div><div class="ClearBoth"></div>EisenbergEffectMon, 03 Feb 2014 20:51:33 GMTUpdated Wiki: Home 20140203085133PUpdated Wiki: Design-Time Supporthttps://caliburnmicro.codeplex.com/wikipage?title=Design-Time Support&version=6<div class="wikidoc"><h1>Design-Time Support</h1>
Enabling Caliburn.Micro inside the Visual Studio designer (or Blend) is quite easy.<br /><br />You have to set a Desinger-DataContext and tell CM to enable its magic in your view XAML:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Window</span>
<span style="color:Red;">xmlns:d</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/expression/blend/2008</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:mc</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.openxmlformats.org/markup-compatibility/2006</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:vm</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:CaliburnDesignTimeData.ViewModels</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:cal</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro.Platform</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">mc:Ignorable</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">d</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">d:DataContext</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">{d:DesignInstance Type=vm:MainPageViewModel, IsDesignTimeCreatable=True}</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">cal:Bind.AtDesignTime</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">True</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
</pre></div><br />For this to work, the ViewModel must have a default constructor. If this isn&#39;t suitable, you can also use a ViewModelLocator for your design-time ViewModel creation.<br /><br />
<h2>Issues</h2>
It seems that VS2010 has an issue in the <b>WP7 designer</b> and an exception in CM ConventionManager is thrown. You can workaround this by overriding ApplyValidation in your bootstrapper:<br /><div style="color:Black;background-color:White;"><pre>
ConventionManager.ApplyValidation = (binding, viewModelType, property) =&gt; {
<span style="color:Blue;">if</span> (<span style="color:Blue;">typeof</span>(INotifyDataErrorInfo).IsAssignableFrom(viewModelType)) {
binding.ValidatesOnNotifyDataErrors = <span style="color:Blue;">true</span>;
binding.ValidatesOnExceptions = <span style="color:Blue;">true</span>;
}
};
</pre></div></div><div class="ClearBoth"></div>tibelTue, 21 Jan 2014 17:43:27 GMTUpdated Wiki: Design-Time Support 20140121054327PUpdated Wiki: The Service Locatorhttps://caliburnmicro.codeplex.com/wikipage?title=The Service Locator&version=5<div class="wikidoc"><h1>The Service Locator</h1>
Caliburn.Micro comes pre-bundled with a static Service Locator called IoC. For those unfamiliar, a Service Locator is an entity that can provide another entity with service instances, usually based on some type or key. Service Locator is actually a <a href="http://en.wikipedia.org/wiki/Service_locator_pattern">pattern</a> and is related to <a href="http://en.wikipedia.org/wiki/Inversion_of_control">Inversion of Control</a>. Many consider Service Locator to be an anti-pattern but like all patterns it has its use cases. <br />
<h2>Getting Started</h2>
IoC is the static entity used for Service Location in Caliburn.Micro, this enables IoC to work with static entites such as dependency properties with ease. The public definition of IoC is shown below.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">static</span> <span style="color:Blue;">class</span> IoC {
<span style="color:Blue;">public</span> <span style="color:Blue;">static</span> Func&lt;Type, <span style="color:Blue;">string</span>, <span style="color:Blue;">object</span>&gt; GetInstance;
<span style="color:Blue;">public</span> <span style="color:Blue;">static</span> Func&lt;Type, IEnumerable&lt;<span style="color:Blue;">object</span>&gt;&gt; GetAllInstances;
<span style="color:Blue;">public</span> <span style="color:Blue;">static</span> Action&lt;<span style="color:Blue;">object</span>&gt; BuildUp;
<span style="color:Blue;">public</span> <span style="color:Blue;">static</span> T Get&lt;T&gt;(<span style="color:Blue;">string</span> key = <span style="color:Blue;">null</span>);
<span style="color:Blue;">public</span> <span style="color:Blue;">static</span> IEnumerable&lt;T&gt; GetAll&lt;T&gt;();
}
</pre></div><br />As you can see above much of the functionality of IoC is dependant on the consumer providing it. In most cases the relevant methods required map directly to methods provided by all <a href="http://en.wikipedia.org/wiki/Dependency_injection">Dependency Injection</a> containers (although the name and functionality may differ).<br />
<h3>Injecting IoC with functionality.</h3>
Caliburn.Micro requires IoC to work correctly because it takes advantage of it at a framework level. As a non optional service we provide an extensibility point directly on the <a href="https://caliburnmicro.codeplex.com/wikipage?title=Customizing%20The%20Bootstrapper">Bootstrapper</a> for the purposes of injecting functionality into IoC. Below, the sample uses Caliburn.Micro&#39;s own <a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Simple%20IoC%20Container&amp;referringTitle=Documentation">SimpleContainer</a> to inject functionality into IoC.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> CustomBootstrapper : Bootstrapper {
<span style="color:Blue;">private</span> SimpleContainer _container = <span style="color:Blue;">new</span> SimpleContainer();
<span style="color:Green;">//...</span>
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">object</span> GetInstance(Type service, <span style="color:Blue;">string</span> key) {
<span style="color:Blue;">return</span> _container.GetInstance(service, key);
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> IEnumerable&lt;<span style="color:Blue;">object</span>&gt; GetAllInstances(Type service) {
<span style="color:Blue;">return</span> _container.GetAllInstances(service);
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> BuildUp(<span style="color:Blue;">object</span> instance) {
_container.BuildUp(instance);
}
<span style="color:Green;">//...</span>
}
</pre></div><br />By mapping your chosen dependency container to IoC, Calburn.Micro can take advantage of any service bindings made on the container via Service Location. <br />
<h2>Using IoC in your application</h2>
As stated at the outset Service Location, apart from a few specific areas, is considered by many to be an anti pattern; in most cases you will want to make use of your dependency injection container. Many problems that Service Locator solves can be fixed without it by planning out your applications composition; refer to <a href="https://caliburnmicro.codeplex.com/wikipage?title=Screens%2c%20Conductors%20and%20Composition&amp;referringTitle=Documentation">Screens, Conductors &amp; Composition</a> for more information on composition.<br /><br />However, if you still require Service Location, IoC makes it easy. The code below shows how to use the service locator to retrieve or inject instances with services.<br />
<h3>Getting a single service</h3>
IoC supports the retrieval of a single type by type or type and key. Key-based retrieval is not supported by all dependency injection containers, because of this the key param is optional.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">var</span> windowManager = IoC.Get&lt;IWindowManager&gt;();
<span style="color:Blue;">var</span> windowManager = IoC.Get&lt;IWindowManager&gt;(<span style="color:#A31515;">&quot;windowManager&quot;</span>);
</pre></div> <br />
<h3>Getting a collection of services</h3>
Requesting a collection of services is also supported by IoC. The return type is IEnumerable T where T is the type of service requested. LINQ can be used to filter the final collection but be aware that at this point any entity in the collection will have already been instantiated.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">var</span> viewModelCollection = IoC.GetAll&lt;IViewModel&gt;();
<span style="color:Blue;">var</span> viewModel = IoC.GetAll&lt;IViewModel&gt;()
.FirstOrDefault(vm =&gt; vm.GetType() == <span style="color:Blue;">typeof</span>(ShellViewModel));
</pre></div>
<h3>Injecting an instance with services</h3>
IoC supports the injection of services into a given instance. The mechanics of how this is done is left to the implementation injected into the <span class="codeInline">Action&lt;Instance&gt; BuildUp</span> field. There are various places in the framework were this is used to inject functionality into entities that were created externally to the dependency container mapped to IoC.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">var</span> viewModel = <span style="color:Blue;">new</span> LocallyCreatedViewModel();
IoC.BuildUp(viewModel);
</pre></div><br /></div><div class="ClearBoth"></div>tibelWed, 15 Jan 2014 18:25:39 GMTUpdated Wiki: The Service Locator 20140115062539PUpdated Wiki: The Event Aggregatorhttps://caliburnmicro.codeplex.com/wikipage?title=The Event Aggregator&version=11<div class="wikidoc"><h1>The Event Aggregator</h1>
Caliburn.Micro comes pre-bundled with an Event Aggregator, conveniently called EventAggregator. For those unfamiliar, an Event Aggregator is a service that provides the ability to publish an object from one entity to another in a loosely based fashion. <a href="http://martinfowler.com/eaaDev/EventAggregator.html">Event Aggregator</a> is actually a pattern and it&#39;s implementation can vary from framework to framework. For Caliburn.Micro we focused on making our Event Aggregator implementation simple to use without sacrificing features or flexibility.<br />
<h2>Getting Started</h2>
As previously mentioned we provide an implementation of Event Aggregator for you. This implementation implements the IEventAggregator interface, however, you can provide your own implementation if required. Please take a moment to familiarize yourself with the IEventAggregator signature.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">interface</span> IEventAggregator {
<span style="color:Blue;">bool</span> HandlerExistsFor(Type messageType);
<span style="color:Blue;">void</span> Subscribe(<span style="color:Blue;">object</span> subscriber);
<span style="color:Blue;">void</span> Unsubscribe(<span style="color:Blue;">object</span> subscriber);
<span style="color:Blue;">void</span> Publish(<span style="color:Blue;">object</span> message, Action&lt;Action&gt; marshal);
}
</pre></div>
<h3>Creation and Lifecycle</h3>
To use the EventAggregator correctly it must exist as an application level service. This is usually achieved by creating an instance of EventAggregator as a <a href="http://en.wikipedia.org/wiki/Singleton_pattern">Singleton</a>. We recommend that you use <a href="http://en.wikipedia.org/wiki/Dependency_Injection">Dependency Injection</a> to obtain a reference to the instance although we do not enforce this. The sample below details how to create an instance of EventAggregator, add it to the <a href="https://caliburnmicro.codeplex.com/wikipage?title=The%20Simple%20IoC%20Container&amp;referringTitle=Documentation">IoC container</a> included with Caliburn.Micro (although you are free to use any container you wish) and request it in a ViewModel.<br /> <br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Green;">// Creating the EventAggregator as a singleton.</span>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> Bootstrapper : BootstrapperBase {
<span style="color:Blue;">private</span> <span style="color:Blue;">readonly</span> SimpleContainer _container =
<span style="color:Blue;">new</span> SimpleContainer();
<span style="color:Green;">// ... Other Bootstrapper Config</span>
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> Configure(){
_container.Singleton&lt;IEventAggregator, EventAggregator&gt;();
}
<span style="color:Green;">// ... Other Bootstrapper Config</span>
}
<span style="color:Green;">// Acquiring the EventAggregator in a viewModel.</span>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> FooViewModel {
<span style="color:Blue;">private</span> <span style="color:Blue;">readonly</span> IEventAggregator _eventAggregator;
<span style="color:Blue;">public</span> FooViewModel(IEventAggregator eventAggregator) {
_eventAggregator = eventAggregator;
}
}
</pre></div><br /><i>Note that we are utilizing the <a href="http://caliburnmicro.codeplex.com/wikipage?title=Customizing%20The%20Bootstrapper&amp;referringTitle=Documentation">Bootstrapper</a>, and specifically the Configure method, in the code above. There is no requirement to wire up the EventAggregator in a specific location, simply ensure it is created before it is first requested.</i><br />
<h3>Publishing Events</h3>
Once you have obtained a reference to the EventAggregator instance you are free to begin publishing Events. An Event or message as we call it to distinguish between .Net events, can be any object you like. There is no requirement to build your Events in any specific fashion. As you can see in the sample below the Publish method can accept any entity that derives from System.Object and will happily publish it to any interested subscribers.<br /> <br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> FooViewModel {
<span style="color:Blue;">private</span> <span style="color:Blue;">readonly</span> IEventAggregator _eventAggregator;
<span style="color:Blue;">public</span> FooViewModel(IEventAggregator eventAggregator) {
_eventAggregator = eventAggregator;
_eventAggregator.Publish(<span style="color:Blue;">new</span> <span style="color:Blue;">object</span>());
_eventAggregator.Publish(<span style="color:#A31515;">&quot;Hello World&quot;</span>);
_eventAggregator.Publish(22);
}
}
</pre></div>
<h3>Publishing using a custom thread Marshal</h3>
By convention, the EventAggregator publishes on the UI thread (using PublishOnUIThread() method). You can override this per publish. Consider the following code below which publishes the message supplied on a background thread.<br /><br /><div style="color:Black;background-color:White;"><pre>
_eventAggregator.Publish(<span style="color:Blue;">new</span> <span style="color:Blue;">object</span>(), action =&gt; {
Task.Factory.StartNew(action);
});
</pre></div>
<h2>Subscribing To Events</h2>
Any entity can subscribe to any Event by providing itself to the EventAggregator via the Subscribe method. To keep this functionality easy to use we provide a special interface (IHandle&lt;T&gt;) which marks a subscriber as interested in an Event of a given type.<br /><br /><div style="color:Black;background-color:White;"><pre>
IHandle&lt;TMessage&gt; : IHandle {
<span style="color:Blue;">void</span> Handle&lt;TMessage&gt;(TMessage message);
}
</pre></div><br />Notice that by implementing the interface above you are forced to implement the method Handle(T message) were T is the type of message you have specified your interest in. This method is what will be called when a matching Event type is published. <br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> FooViewModel : IHandle&lt;<span style="color:Blue;">object</span>&gt; {
<span style="color:Blue;">private</span> <span style="color:Blue;">readonly</span> IEventAggregator _eventAggregator;
<span style="color:Blue;">public</span> FooViewModel(IEventAggregator eventAggregator) {
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(<span style="color:Blue;">this</span>);
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Handle(<span style="color:Blue;">object</span> message) {
<span style="color:Green;">// Handle the message here.</span>
}
}
</pre></div><br /><i>You may be wondering about IHandle&lt;T&gt; implementing IHandle. IHandle is a <a href="http://stackoverflow.com/questions/1023068/what-is-the-purpose-of-a-marker-interface">Marker Interface</a> used internally to assist with reflecting over various IHandle Implementations, you do not need to work with this interface directly.</i><br />
<h3>Subscribing To Many Events</h3>
It is not uncommon for a single entity to want to listen for multiple event types. Because of our use of generics this is as simple as adding a second IHandle&lt;T&gt; interface to the subscriber. Notice that Handle method is now overloaded with the new Event type.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> FooViewModel : IHandle&lt;<span style="color:Blue;">string</span>&gt;, IHandle&lt;<span style="color:Blue;">bool</span>&gt; {
<span style="color:Blue;">private</span> <span style="color:Blue;">readonly</span> IEventAggregator _eventAggregator;
<span style="color:Blue;">public</span> FooViewModel(IEventAggregator eventAggregator) {
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(<span style="color:Blue;">this</span>);
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Handle(<span style="color:Blue;">string</span> message) {
<span style="color:Green;">// Handle the message here.</span>
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Handle(<span style="color:Blue;">bool</span> message) {
<span style="color:Green;">// Handle the message here.</span>
}
}
</pre></div>
<h3>Polymorphic Subscribers</h3>
Caliburn.Micro&#39;s EventAggregator honors polymorphism. When selecting handlers to call, the EventAggregator will fire any handler who&#39;s Event type is assignable from the Event being sent. This results in a lot of flexibility and helps reuse.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> FooViewModel : IHandle&lt;<span style="color:Blue;">object</span>&gt;, IHandle&lt;<span style="color:Blue;">string</span>&gt; {
<span style="color:Blue;">private</span> <span style="color:Blue;">readonly</span> IEventAggregator _eventAggregator;
<span style="color:Blue;">public</span> FooViewModel(IEventAggregator eventAggregator) {
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(<span style="color:Blue;">this</span>);
_eventAggregator.Publish(<span style="color:#A31515;">&quot;Hello&quot;</span>);
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Handle(<span style="color:Blue;">object</span> message) {
<span style="color:Green;">// This will be called</span>
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Handle(<span style="color:Blue;">string</span> message) {
<span style="color:Green;">// This also</span>
}
}
</pre></div><br />In the example above, because String is derived from System.Object both handlers will be called when a String message is published.<br /><br />
<h3>Querying Handlers</h3>
When a subscriber is passed to the EventAggregator it is broken down into a special object called a Handler and a weak reference is maintained. We provide a mechanism to query the EventAggregator to see if a given Event type has any handlers, this can be useful in specific scenarios were at least one handler is assumed to exist.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> FooViewModel : IHandle&lt;<span style="color:Blue;">object</span>&gt; {
<span style="color:Blue;">private</span> <span style="color:Blue;">readonly</span> IEventAggregator _eventAggregator;
<span style="color:Blue;">public</span> FooViewModel(IEventAggregator eventAggregator) {
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(<span style="color:Blue;">this</span>);
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Handle(<span style="color:Blue;">object</span> message){
<span style="color:Blue;">if</span> (_eventAggregator.HandlerExistsFor(<span style="color:Blue;">typeof</span>(SpecialMessageEvent))){
_eventAggregator.Publish(<span style="color:Blue;">new</span> SpecialEventMessage(message));
}
}
}
</pre></div>
<h3>Coroutine Aware Subscribers</h3>
If you are using the EventAggregator with Caliburn.Micro as opposed to on it&#39;s own via Nuget, access to <a href="https://caliburnmicro.codeplex.com/wikipage?title=IResult%20and%20Coroutines&amp;referringTitle=Documentation">Coroutine</a> support within the Event Aggregator becomes available. Coroutines are supported via the IHandleWithCoroutine&lt;T&gt; Interface.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">interface</span> IHandleWithCoroutine&lt;TMessage&gt; : IHandle {
IEnumerable&lt;IResult&gt; Handle(TMessage message);
}
</pre></div><br />The code below utilizes Coroutines with the EventAggregator. In this instance Activate will be fired asynchronously, Do work however, will not be called until after Activate has completed.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> FooViewModel : Screen, IHandleWithCoroutine&lt;EventWithCoroutine&gt; {
<span style="color:Blue;">private</span> <span style="color:Blue;">readonly</span> IEventAggregator _eventAggregator;
<span style="color:Blue;">public</span> FooViewModel(IEventAggregator eventAggregator) {
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(<span style="color:Blue;">this</span>);
}
<span style="color:Blue;">public</span> IEnumerable&lt;IResult&gt; Handle(EventWithCoroutine message) {
<span style="color:Blue;">yield</span> <span style="color:Blue;">return</span> message.Activate();
<span style="color:Blue;">yield</span> <span style="color:Blue;">return</span> message.DoWork();
}
}
</pre></div><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> EventWithCoroutine {
<span style="color:Blue;">public</span> IResult Activate() {
<span style="color:Blue;">return</span> <span style="color:Blue;">new</span> TaskResult(Task.Factory.StartNew(() =&gt; {
<span style="color:Green;">// Activate logic</span>
}));
}
<span style="color:Blue;">public</span> IResult DoWork() {
<span style="color:Blue;">return</span> <span style="color:Blue;">new</span> TaskResult(Task.Factory.StartNew(() =&gt; {
<span style="color:Green;">// Do work logic</span>
}));
}
}
</pre></div>
<h3>Task Aware Subscribers</h3>
Caliburn.Micro also provides support for task based subscribers where the asynchronous functionality of Coroutines is desired but in a more light weight fashion. To utilize this functionality implement the IHandleWithTask&lt;T&gt; Interface, seen below.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">interface</span> IHandleWithTask&lt;TMessage&gt; : IHandle {
Task Handle(TMessage message);
}
</pre></div><br />Any subscribers that implement the above interface can then handle events in Task based manner.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> FooViewModel : Screen, IHandleWithTask&lt;<span style="color:Blue;">object</span>&gt; {
<span style="color:Blue;">private</span> <span style="color:Blue;">readonly</span> IEventAggregator _eventAggregator;
<span style="color:Blue;">public</span> FooViewModel(IEventAggregator eventAggregator) {
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(<span style="color:Blue;">this</span>);
}
<span style="color:Blue;">public</span> Task Handle(<span style="color:Blue;">object</span> message) {
<span style="color:Blue;">return</span> Task.Factory.StartNew(() =&gt; message);
}
}
</pre></div>
<h3>Unsubscribing and Leaks</h3>
The problem with standard .Net events is that they are prone to memory leaks. We avoid this situation by maintaining a weak reference to subscribers. If the only thing that references a subscriber is the EventAggregator then it will be allowed to go out of scope and ultimately be garbage collected. However, we still provide an explicit way to unsubscribe to allow for conditional handling as seen below.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> FooViewModel : Screen, IHandle&lt;<span style="color:Blue;">object</span>&gt; {
<span style="color:Blue;">private</span> <span style="color:Blue;">readonly</span> IEventAggregator _eventAggregator;
<span style="color:Blue;">public</span> FooViewModel(IEventAggregator eventAggregator) {
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(<span style="color:Blue;">this</span>);
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Handle(<span style="color:Blue;">object</span> message) {
<span style="color:Green;">// Handle the message here.</span>
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> OnActivate() {
_eventAggregator.Subscribe(<span style="color:Blue;">this</span>);
<span style="color:Blue;">base</span>.OnActivate();
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> OnDeactivate(<span style="color:Blue;">bool</span> close) {
_eventAggregator.Unsubscribe(<span style="color:Blue;">this</span>);
<span style="color:Blue;">base</span>.OnDeactivate(close);
}
}
</pre></div><br /><i>In the code above Screen is used to expose lifecycle events on the ViewModel. More on this can be found on this in the <a href="https://caliburnmicro.codeplex.com/wikipage?title=Screens%2c%20Conductors%20and%20Composition&amp;referringTitle=Documentation">Screens, Conductors and Composition</a> article on this wiki.</i><br />
<h3>Custom Result Handling</h3>
In more complex scenarios it may be required to override the default handling of Handlers which have results. In this instance it is possible to swap out the existing implementation in favour of your own. First we create a new handler type.<br /><br /><div style="color:Black;background-color:White;"><pre>
IHandleAndReturnString&lt;T&gt; : IHandle {
<span style="color:Blue;">string</span> Handle&lt;T&gt;(T message);
}
</pre></div><br />Next we create our new result processor. This can be configured in the bootstrapper.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">var</span> standardResultProcesser = EventAggregator.HandlerResultProcessing;
EventAggregator.HandlerResultProcessing = (target, result) =&gt;
{
<span style="color:Blue;">var</span> stringResult = result <span style="color:Blue;">as</span> <span style="color:Blue;">string</span>;
<span style="color:Blue;">if</span> (stringResult != <span style="color:Blue;">null</span>)
MessageBox.Show(stringResult);
<span style="color:Blue;">else</span>
standardResultProcesser(target, result);
};
</pre></div><br />Now, any time an event is processed returns a string, it will be captured and displayed in a MessageBox. The new handler falls back to the default implementations in cases were the result is not assignable from string. It is extremely important to note however, this feature was not designed for request / response usage, treating it as such will most definitely create bottle necks on publish.<br /></div><div class="ClearBoth"></div>tibelWed, 15 Jan 2014 18:22:38 GMTUpdated Wiki: The Event Aggregator 20140115062238PUpdated Wiki: IResult and Coroutineshttps://caliburnmicro.codeplex.com/wikipage?title=IResult and Coroutines&version=21<div class="wikidoc"><h1>IResult and Coroutines</h1>
Previously, I mentioned that there was one more compelling feature of the Actions concept called Coroutines. If you haven’t heard that term before, here’s what <a href="http://en.wikipedia.org/wiki/Coroutine">wikipedia</a><sup>1</sup> has to say:<br /><br /><i>In computer science, coroutines are program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations. Coroutines are well-suited for implementing more familiar program components such as cooperative tasks, iterators,infinite lists and pipes.</i><br /><br />Here’s one way you can thing about it: Imagine being able to execute a method, then pause it’s execution on some statement, go do something else, then come back and resume execution where you left off. This technique is extremely powerful in task-based programming, especially when those tasks need to run asynchronously. For example, let’s say we have a ViewModel that needs to call a web service asynchronously, then it needs to take the results of that, do some work on it and call another web service asynchronously. Finally, it must then display the result in a modal dialog and respond to the user’s dialog selection with another asynchronous task. Accomplishing this with the standard event-driven async model is not a pleasant experience. However, this is a simple task to accomplish by using coroutines. The problem…C# doesn’t implement coroutines natively. Fortunately, we can (sort of) build them on top of iterators.<br /><br />There are two things necessary to take advantage of this feature in Caliburn.Micro: First, implement the IResult interface on some class, representing the task you wish to execute; Second, yield instances of IResult from an Action<sup>2</sup>. Let’s make this more concrete. Say we had a Silverlight application where we wanted to dynamically download and show screens not part of the main package. First we would probably want to show a “Loading” indicator, then asynchronously download the external package, next hide the “Loading” indicator and finally navigate to a particular screen inside the dynamic module. Here’s what the code would look like if your first screen wanted to use coroutines to navigate to a dynamically loaded second screen:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">using</span> System.Collections.Generic;
<span style="color:Blue;">using</span> System.ComponentModel.Composition;
[Export(<span style="color:Blue;">typeof</span>(ScreenOneViewModel))]
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> ScreenOneViewModel
{
<span style="color:Blue;">public</span> IEnumerable&lt;IResult&gt; GoForward()
{
<span style="color:Blue;">yield</span> <span style="color:Blue;">return</span> Loader.Show(<span style="color:#A31515;">&quot;Downloading...&quot;</span>);
<span style="color:Blue;">yield</span> <span style="color:Blue;">return</span> <span style="color:Blue;">new</span> LoadCatalog(<span style="color:#A31515;">&quot;Caliburn.Micro.Coroutines.External.xap&quot;</span>);
<span style="color:Blue;">yield</span> <span style="color:Blue;">return</span> Loader.Hide();
<span style="color:Blue;">yield</span> <span style="color:Blue;">return</span> <span style="color:Blue;">new</span> ShowScreen(<span style="color:#A31515;">&quot;ExternalScreen&quot;</span>);
}
}
</pre></div><br />First, notice that the Action “GoForward” has a return type of IEnumerable&lt;IResult&gt;. This is critical for using coroutines. The body of the method has four yield statements. Each of these yields is returning an instance of IResult. The first is a result to show the “Downloading” indicator, the second to download the xap asynchronously, the third to hide the “Downloading” message and the fourth to show a new screen from the downloaded xap. After each yield statement, the compiler will “pause” the execution of this method until that particular task completes. The first, third and fourth tasks are synchronous, while the second is asynchronous. But the yield syntax allows you to write all the code in a sequential fashion, preserving the original workflow as a much more readable and declarative structure. To understand a bit more how this works, have a look at the IResult interface:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">interface</span> IResult
{
<span style="color:Blue;">void</span> Execute(CoroutineExecutionContext context);
<span style="color:Blue;">event</span> EventHandler&lt;ResultCompletionEventArgs&gt; Completed;
}
</pre></div><br />It’s a fairly simple interface to implement. Simply write your code in the “Execute” method and be sure to raise the “Completed” event when you are done, whether it be a synchronous or an asynchronous task. Because coroutines occur inside of an Action, we provide you with an ActionExecutionContext useful in building UI-related IResult implementations. This allows the ViewModel a way to declaratively state its intentions in controlling the view without having any reference to a View or the need for interaction-based unit testing. Here’s what the ActionExecutionContext looks like:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> ActionExecutionContext
{
<span style="color:Blue;">public</span> ActionMessage Message;
<span style="color:Blue;">public</span> FrameworkElement Source;
<span style="color:Blue;">public</span> <span style="color:Blue;">object</span> EventArgs;
<span style="color:Blue;">public</span> <span style="color:Blue;">object</span> Target;
<span style="color:Blue;">public</span> DependencyObject View;
<span style="color:Blue;">public</span> MethodInfo Method;
<span style="color:Blue;">public</span> Func&lt;<span style="color:Blue;">bool</span>&gt; CanExecute;
<span style="color:Blue;">public</span> <span style="color:Blue;">object</span> <span style="color:Blue;">this</span>[<span style="color:Blue;">string</span> key];
}
</pre></div><br />And here’s an explanation of what all these properties mean:<br />
<ul><li>Message – The original ActionMessage that caused the invocation of this IResult.</li>
<li>Source – The FrameworkElement that triggered the execution of the Action.</li>
<li>EventArgs – Any event arguments associated with the trigger of the Action.</li>
<li>Target – The class instance on which the actual Action method exists.</li>
<li>View – The view associated with the Target.</li>
<li>Method – The MethodInfo specifying which method to invoke on the Target instance.</li>
<li>CanExecute – A function that returns true if the Action can be invoked, false otherwise.</li>
<li>Key Index: A place to store/retrieve any additional metadata which may be used by extensions to the framework.</li></ul>
<br />Bearing that in mind, I wrote a naive Loader IResult that searches the VisualTree looking for the first instance of a BusyIndicator to use to display a loading message. Here’s the implementation:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">using</span> System;
<span style="color:Blue;">using</span> System.Windows;
<span style="color:Blue;">using</span> System.Windows.Controls;
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> Loader : IResult
{
<span style="color:Blue;">readonly</span> <span style="color:Blue;">string</span> message;
<span style="color:Blue;">readonly</span> <span style="color:Blue;">bool</span> hide;
<span style="color:Blue;">public</span> Loader(<span style="color:Blue;">string</span> message)
{
<span style="color:Blue;">this</span>.message = message;
}
<span style="color:Blue;">public</span> Loader(<span style="color:Blue;">bool</span> hide)
{
<span style="color:Blue;">this</span>.hide = hide;
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Execute(CoroutineExecutionContext context)
{
<span style="color:Blue;">var</span> view = context.View <span style="color:Blue;">as</span> FrameworkElement;
<span style="color:Blue;">while</span>(view != <span style="color:Blue;">null</span>)
{
<span style="color:Blue;">var</span> busyIndicator = view <span style="color:Blue;">as</span> BusyIndicator;
<span style="color:Blue;">if</span>(busyIndicator != <span style="color:Blue;">null</span>)
{
<span style="color:Blue;">if</span>(!<span style="color:Blue;">string</span>.IsNullOrEmpty(message))
busyIndicator.BusyContent = message;
busyIndicator.IsBusy = !hide;
<span style="color:Blue;">break</span>;
}
view = view.Parent <span style="color:Blue;">as</span> FrameworkElement;
}
Completed(<span style="color:Blue;">this</span>, <span style="color:Blue;">new</span> ResultCompletionEventArgs());
}
<span style="color:Blue;">public</span> <span style="color:Blue;">event</span> EventHandler&lt;ResultCompletionEventArgs&gt; Completed = <span style="color:Blue;">delegate</span> { };
<span style="color:Blue;">public</span> <span style="color:Blue;">static</span> IResult Show(<span style="color:Blue;">string</span> message = <span style="color:Blue;">null</span>)
{
<span style="color:Blue;">return</span> <span style="color:Blue;">new</span> Loader(message);
}
<span style="color:Blue;">public</span> <span style="color:Blue;">static</span> IResult Hide()
{
<span style="color:Blue;">return</span> <span style="color:Blue;">new</span> Loader(<span style="color:Blue;">true</span>);
}
}
</pre></div><br />See how I took advantage of context.View? This opens up a lot of possibilities while maintaining separation between the view and the view model. Just to list a few interesting things you could do with IResult implementations: show a message box, show a VM-based modal dialog, show a VM-based Popup at the user’s mouse position, play an animation, show File Save/Load dialogs, place focus on a particular UI element based on VM properties rather than controls, etc. Of course, one of the biggest opportunities is calling web services. Let’s look at how you might do that, but by using a slightly different scenario, dynamically downloading a xap:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">using</span> System;
<span style="color:Blue;">using</span> System.Collections.Generic;
<span style="color:Blue;">using</span> System.ComponentModel.Composition;
<span style="color:Blue;">using</span> System.ComponentModel.Composition.Hosting;
<span style="color:Blue;">using</span> System.ComponentModel.Composition.ReflectionModel;
<span style="color:Blue;">using</span> System.Linq;
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> LoadCatalog : IResult
{
<span style="color:Blue;">static</span> <span style="color:Blue;">readonly</span> Dictionary&lt;<span style="color:Blue;">string</span>, DeploymentCatalog&gt; Catalogs = <span style="color:Blue;">new</span> Dictionary&lt;<span style="color:Blue;">string</span>, DeploymentCatalog&gt;();
<span style="color:Blue;">readonly</span> <span style="color:Blue;">string</span> uri;
[Import]
<span style="color:Blue;">public</span> AggregateCatalog Catalog { <span style="color:Blue;">get</span>; <span style="color:Blue;">set</span>; }
<span style="color:Blue;">public</span> LoadCatalog(<span style="color:Blue;">string</span> relativeUri)
{
uri = relativeUri;
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Execute(CoroutineExecutionContext context)
{
DeploymentCatalog catalog;
<span style="color:Blue;">if</span>(Catalogs.TryGetValue(uri, <span style="color:Blue;">out</span> catalog))
Completed(<span style="color:Blue;">this</span>, <span style="color:Blue;">new</span> ResultCompletionEventArgs());
<span style="color:Blue;">else</span>
{
catalog = <span style="color:Blue;">new</span> DeploymentCatalog(uri);
catalog.DownloadCompleted += (s, e) =&gt;{
<span style="color:Blue;">if</span>(e.Error == <span style="color:Blue;">null</span>)
{
Catalogs[uri] = catalog;
Catalog.Catalogs.Add(catalog);
catalog.Parts
.Select(part =&gt; ReflectionModelServices.GetPartType(part).Value.Assembly)
.Where(assembly =&gt; !AssemblySource.Instance.Contains(assembly))
.Apply(x =&gt; AssemblySource.Instance.Add(x));
}
<span style="color:Blue;">else</span> Loader.Hide().Execute(context);
Completed(<span style="color:Blue;">this</span>, <span style="color:Blue;">new</span> ResultCompletionEventArgs {
Error = e.Error,
WasCancelled = <span style="color:Blue;">false</span>
});
};
catalog.DownloadAsync();
}
}
<span style="color:Blue;">public</span> <span style="color:Blue;">event</span> EventHandler&lt;ResultCompletionEventArgs&gt; Completed = <span style="color:Blue;">delegate</span> { };
}
</pre></div><br />In case it wasn’t clear, this sample is using MEF. Furthermore, we are taking advantage of the DeploymentCatalog created for Silverlight 4. You don’t really need to know a lot about MEF or DeploymentCatalog to get the takeaway. Just take note of the fact that we wire for the DownloadCompleted event and make sure to fire the IResult.Completed event in its handler. This is what enables the async pattern to work. We also make sure to check the error and pass that along in the ResultCompletionEventArgs. Speaking of that, here’s what that class looks like:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> ResultCompletionEventArgs : EventArgs
{
<span style="color:Blue;">public</span> Exception Error;
<span style="color:Blue;">public</span> <span style="color:Blue;">bool</span> WasCancelled;
}
</pre></div><br />Caliburn.Micro’s enumerator checks these properties after it get’s called back from each IResult. If there is either an error or WasCancelled is set to true, we stop execution. You can use this to your advantage. Let’s say you create an IResult for the OpenFileDialog. You could check the result of that dialog, and if the user canceled it, set WasCancelled on the event args. By doing this, you can write an action that assumes that if the code following the Dialog.Show executes, the user must have selected a file. This sort of technique can simplify the logic in such situations. Obviously, you could use the same technique for the SaveFileDialog or any confirmation style message box if you so desired. My favorite part of the LoadCatalog implementation shown above, is that the original implementation was written by a CM user! Thanks janoveh for this awesome submission! As a side note, one of the things we added to the CM project site is a “Recipes” section. We are going to be adding more common solutions such as this to that area in the coming months. So, it will be a great place to check for cool plugins and customizations to the framework.<br /><br />Another thing you can do is create a series of IResult implementations built around your application’s shell. That is what the ShowScreen result used above does. Here is its implementation:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">using</span> System;
<span style="color:Blue;">using</span> System.ComponentModel.Composition;
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> ShowScreen : IResult
{
<span style="color:Blue;">readonly</span> Type screenType;
<span style="color:Blue;">readonly</span> <span style="color:Blue;">string</span> name;
[Import]
<span style="color:Blue;">public</span> IShell Shell { <span style="color:Blue;">get</span>; <span style="color:Blue;">set</span>; }
<span style="color:Blue;">public</span> ShowScreen(<span style="color:Blue;">string</span> name)
{
<span style="color:Blue;">this</span>.name = name;
}
<span style="color:Blue;">public</span> ShowScreen(Type screenType)
{
<span style="color:Blue;">this</span>.screenType = screenType;
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Execute(CoroutineExecutionContext context)
{
<span style="color:Blue;">var</span> screen = !<span style="color:Blue;">string</span>.IsNullOrEmpty(name)
? IoC.Get&lt;<span style="color:Blue;">object</span>&gt;(name)
: IoC.GetInstance(screenType, <span style="color:Blue;">null</span>);
Shell.ActivateItem(screen);
Completed(<span style="color:Blue;">this</span>, <span style="color:Blue;">new</span> ResultCompletionEventArgs());
}
<span style="color:Blue;">public</span> <span style="color:Blue;">event</span> EventHandler&lt;ResultCompletionEventArgs&gt; Completed = <span style="color:Blue;">delegate</span> { };
<span style="color:Blue;">public</span> <span style="color:Blue;">static</span> ShowScreen Of&lt;T&gt;()
{
<span style="color:Blue;">return</span> <span style="color:Blue;">new</span> ShowScreen(<span style="color:Blue;">typeof</span>(T));
}
}
</pre></div><br />This bring up another important feature of IResult. Before CM executes a result, it passes it through the IoC.BuildUp method allowing your container the opportunity to push dependencies in through the properties. This allows you to create them normally within your view models, while still allowing them to take dependencies on application services. In this case, we depend on IShell. You could also have your container injected, but in this case I chose to use the IoC static class internally. As a general rule, you should avoid pulling things from the container directly. However, I think it is acceptable when done inside of infrastructure code such as a ShowScreen IResult.<br />
<h2>Other Usages</h2>
Out-of-the-box Caliburn.Micro can execute coroutines automatically for any action invoked via an ActionMessage. However, there are times where you may wish to take advantage of the coroutine feature directly. To execute a coroutine, you can use the static Coroutine.BeginExecute method.<br /><br /><br />I hope this gives some explanation and creative ideas for what can be accomplished with IResult. Be sure to check out the sample application attached. There’s a few other interesting things in there as well.<br />
<h2>Referenced Samples</h2>
<ul><li>Caliburn.Micro.Coroutines</li></ul>
<blockquote><i>Note: Please be sure to run the sample as an out-of-browser application.</i></blockquote>
<h2>Footnotes</h2>
<ol><li>When I went to look up the “official” definition on wikipedia I was interested to see what it had to say about implementations in various languages. Scrolling down to the section on C#…Caliburn was listed! Fun stuff. </li>
<li>You can also return a single instance of IResult without using IEnuermable&lt;IResult&gt; if you just want a simple way to execute a single task.</li></ol></div><div class="ClearBoth"></div>tibelWed, 15 Jan 2014 18:17:13 GMTUpdated Wiki: IResult and Coroutines 20140115061713PUpdated Wiki: Working with Windows Phonehttps://caliburnmicro.codeplex.com/wikipage?title=Working with Windows Phone&version=2<div class="wikidoc"><h1>Working with Windows Phone</h1>
In version 1.0 we had pretty good support for building apps for WP7, but in v1.1 we’ve taken things up a notch. Let’s look at the same HelloWP7 sample that we did previously, but see how it’s been updated to take advantage of our improved tombstoning, launcher/chooser support and strongly typed navigation. You’ll also notice that the code is cleaner overall.<br />
<h3>Bootstrapper</h3>
Here’s the cleaned up boostrapper in v1.1.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> HelloWP7Bootstrapper : PhoneBootstrapperBase {
PhoneContainer container;
<span style="color:Blue;">public</span> HelloWP7Bootstrapper() {
Start();
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> Configure() {
container = <span style="color:Blue;">new</span> PhoneContainer(RootFrame);
<span style="color:Blue;">if</span> (!Execute.InDesignMode)
container.RegisterPhoneServices();
container.PerRequest&lt;MainPageViewModel&gt;();
container.PerRequest&lt;PivotPageViewModel&gt;();
container.PerRequest&lt;TabViewModel&gt;();
AddCustomConventions();
}
<span style="color:Blue;">static</span> <span style="color:Blue;">void</span> AddCustomConventions() {
<span style="color:Green;">//ellided </span>
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">object</span> GetInstance(Type service, <span style="color:Blue;">string</span> key) {
<span style="color:Blue;">return</span> container.GetInstance(service, key);
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> IEnumerable&lt;<span style="color:Blue;">object</span>&gt; GetAllInstances(Type service) {
<span style="color:Blue;">return</span> container.GetAllInstances(service);
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> BuildUp(<span style="color:Blue;">object</span> instance) {
container.BuildUp(instance);
}
}
</pre></div><br />There are two things to notice here. First, we’ve removed all the manual Caliburn.Micro service configuration and pushed it into the SimpleContainer. That gives you one line of code to configure the framework if you are using the OOTB container. Speaking of which, we now provide the SimpleContainer officially in the Caliburn.Micro.Extensions assembly. That helps you get started faster. You can always plug your own in, of coarse. In addition to the simplified configuration, notice that the ViewModels for pages are no longer registered using a string key. For v1.1 our ViewModelLocator has been re-implemented to pull VMs from the container by Type rather than key. It now follows the exact same naming strategies as the ViewLocator (but in reverse) and even derives possible interface names so that it resolves VMs from the container correctly. This both improves the consistency of ViewModel location as well as makes the configuration simpler.<br /><br />The boostrapper is added to your App.xaml as always:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Application</span> <span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.HelloWP7.App</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:local</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:Caliburn.Micro.HelloWP7</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Application.Resources</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">local</span><span style="color:Blue;">:</span><span style="color:#A31515;">HelloWP7Bootstrapper</span> <span style="color:Red;">x:Key</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">bootstrapper</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Application.Resources</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Application</span><span style="color:Blue;">&gt;</span>
</pre></div><br /><b>Important Note About App.xaml.cs</b><br /><br /><i>If you create your WP7 application using a standard Visual Studio template, the generated App.xaml.cs file will have a lot of code in it. The purpose of this code is to set up the root frame for the application and make sure everything gets initialized properly. Of course, that&#39;s what the bootstrapper&#39;s job is too (and in fact it does a few things better than the out-of-the-box code in addition to configuring CM). So, you don&#39;t need both. When using CM&#39;s PhoneBootstrapper, be sure to clear out all the code from the App.xaml.cs file except for the call to InitializeComponent in the constructor.</i><br />
<h3>INavigationService</h3>
Let’s review what CM’s INavigationService does for you. First, remember that WP7 enforces a View-First approach to UI at the platform level. Like it or not, the platform is going to create pages at will and the Frame control is going to conduct your application thusly. You don’t get to control that and there are no extensibility points, unlike the Silverlight version of the navigation framework. Rather than fight this, I’m going to recommend embracing the View-First approach for Pages in WP7, but maintaining a Model-First composition strategy for the sub-components of those pages and a Model-First approach to coding against the navigation system. In order to bridge this gap, I’ve enabled the INavigationService to hook into the native navigation frame’s functionality and augment it with the following behaviors:<br /><br /><i>When Navigating To a Page</i><br />
<ul><li>Use the new ViewModelLocator to conventionally determine the Type of the VM that should be attached to the page being navigated to. Pull that VM by Type out of the container.</li>
<li>If a VM is found, use the ViewModelBinder to connect the Page to the located ViewModel.</li>
<li>Examine the Page’s QueryString. Look for properties on the VM that match the QueryString parameters and inject them, performing the necessary type coercion.</li>
<li>If the ViewModel implements the IActivate interface, call its Activate method.</li></ul>
<br /><i>When Navigating Away From a Page</i><br />
<ul><li>Detect whether the associated ViewModel implements the IGuardClose interface.</li>
<li>If IGuardClose is implemented and the app is not being tombstoned or closed, invoke the CanClose method and use its result to optionally cancel page navigation.1</li>
<li>If the ViewModel can close and implements the IDeactivate interface, call it’s Deactivate method. Always pass “false” to indicate that the VM should deactivate, but not necessarily close. This is because the phone may be deactivating, but not actually tombstoning or closing. There’s no way to know.</li></ul>
<br />The behavior of the navigation service allows the correct VM to be hooked up to the page, allows that VM to be notified that it is being navigated to (IActivate), allows it to prevent navigation away from the current page (IGuardClose) and allows it to clean up after itself on navigation away, tombstoning or normal “closing” of the application (IDeactivate). All these interfaces (and a couple more) are implemented by the Screen class. If you prefer not to inherit from Screen, you can implement any of the interfaces individually of coarse. They provide a nice View-Model-Centric, testable and predictable way of responding to navigation without needing to wire up a ton of event handlers or write important application flow logic in the page’s code-behind.<br /><br />These hooks into phone navigation enable a really smooth way of interacting with the phone’s navigation lifecycle. But now that we have an improved ViewModelLocator that matches exactly the ViewLocator and works on types, we can take things further. In v1.1 we’ve introduced support for strongly-typed navigation. Here’s what the new MainPageViewModel from the sample looks like using this new feature:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> MainPageViewModel {
<span style="color:Blue;">readonly</span> INavigationService navigationService;
<span style="color:Blue;">public</span> MainPageViewModel(INavigationService navigationService) {
<span style="color:Blue;">this</span>.navigationService = navigationService;
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> GotoPageTwo() {
navigationService.UriFor&lt;PivotPageViewModel&gt;()
.WithParam(x =&gt; x.NumberOfTabs, 5)
.Navigate();
}
}
</pre></div><br />This allows you to specify a ViewModel to navigate to along with the query string parameters. Since this all happens using generics and lambdas, you can never miss-type a page Uri or mess up your query strings….and refactoring will work beautifully.<br /><br />For the sake of completeness, here’s the page that will be bound to MainPageViewModel:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">phone</span><span style="color:Blue;">:</span><span style="color:#A31515;">PhoneApplicationPage</span> <span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.HelloWP7.MainPage</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:phone</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:shell</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:cal</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">SupportedOrientations</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Portrait</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">Orientation</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Portrait</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">shell:SystemTray.IsVisible</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">True</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Grid</span> <span style="color:Red;">Background</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Transparent</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Grid.RowDefinitions</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">RowDefinition</span> <span style="color:Red;">Height</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Auto</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">RowDefinition</span> <span style="color:Red;">Height</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">*</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Grid.RowDefinitions</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">StackPanel</span> <span style="color:Red;">Grid.Row</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">0</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">Margin</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">24,24,0,12</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBlock</span> <span style="color:Red;">Text</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">WP7 Caliburn.Micro</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">Style</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">{StaticResource PhoneTextNormalStyle}</span><span style="color:Black;">&#39;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBlock</span> <span style="color:Red;">Text</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">Main Page</span><span style="color:Black;">&#39;</span>
<span style="color:Red;">Margin</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">-3,-8,0,0</span><span style="color:Black;">&#39;</span>
<span style="color:Red;">Style</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">{StaticResource PhoneTextTitle1Style}</span><span style="color:Black;">&#39;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Grid</span> <span style="color:Red;">Grid.Row</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">1</span><span style="color:Black;">&#39;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">GotoPageTwo</span><span style="color:Black;">&#39;</span>
<span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">Goto Page Two</span><span style="color:Black;">&#39;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Grid</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Grid</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">phone</span><span style="color:Blue;">:</span><span style="color:#A31515;">PhoneApplicationPage.ApplicationBar</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">shell</span><span style="color:Blue;">:</span><span style="color:#A31515;">ApplicationBar</span> <span style="color:Red;">IsVisible</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">True</span><span style="color:Black;">&#39;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">shell</span><span style="color:Blue;">:</span><span style="color:#A31515;">ApplicationBar.Buttons</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">cal</span><span style="color:Blue;">:</span><span style="color:#A31515;">AppBarButton</span> <span style="color:Red;">IconUri</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">ApplicationIcon.png</span><span style="color:Black;">&#39;</span>
<span style="color:Red;">Text</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">Page Two</span><span style="color:Black;">&#39;</span>
<span style="color:Red;">Message</span><span style="color:Blue;">=</span><span style="color:Black;">&#39;</span><span style="color:Blue;">GotoPageTwo</span><span style="color:Black;">&#39;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">shell</span><span style="color:Blue;">:</span><span style="color:#A31515;">ApplicationBar.Buttons</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">shell</span><span style="color:Blue;">:</span><span style="color:#A31515;">ApplicationBar</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">phone</span><span style="color:Blue;">:</span><span style="color:#A31515;">PhoneApplicationPage.ApplicationBar</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">phone</span><span style="color:Blue;">:</span><span style="color:#A31515;">PhoneApplicationPage</span><span style="color:Blue;">&gt;</span>
</pre></div><br />There’s really nothing new here in v1.1. But I just wanted to remind you that Caliburn.Micro supports Actions on the AppBar as long as you use CM’s AppBarButton and AppBarMenuItem :)<br />
<h3>IPhoneService</h3>
The IPhoneService wraps the phone’s frame and provides access to important information and events. We had this service in v1.0 but we’ve expanded it in v1.1 to expose a better event model. Those familiar with WP7 know that the phone has a series of events that fire in different circumstances: Launching, Activated, Deactivated and Closing. Unfortunately, these events obscure whether the phone is actually resurrecting from a tombstoned state or simply continuing execution. The current SDK does not make it easy for the developer to actually determine this, so Caliburn.Micro does the heavy lifting for you and provides the following event model:<br />
<ul><li>Launching - Occurs when a fresh instance of the application is launching.</li>
<li>Activated - Occurs when a previously paused/tombstoned app is resumed/resurrected.</li>
<li>Deactivated - Occurs when the application is being paused or tombstoned.</li>
<li>Closing - Occurs when the application is closing.</li>
<li>Continuing - Occurs when the app is continuing from a temporarily paused state.</li>
<li>Continued - Occurs after the app has continued from a temporarily paused state.</li>
<li>Resurrecting - Occurs when the app is &quot;resurrecting&quot; from a tombstoned state.</li>
<li>Resurrected - Occurs after the app has &quot;resurrected&quot; from a tombstoned state.</li></ul>
<br />Using these new events, you can more intelligently make decisions about whether or not you need to restore data. In the forthcoming Mango release, the platform will provide us information on whether the app is continuing or resurrecting. However, developers working with Caliburn.Micro can have that information now and when Mango arrives, we’ll update our implementation to use the new bits. Your code won’t have to change.<br />
<h3>Tombstoning</h3>
As you might imagine, our new tombstoning mechanism takes advantage of the new events so that it can more reliably and accurately save/restore important data. Let’s have a look at the PivotPageViewModel to see how it interacts with the tombstoning mechanism.<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> PivotPageViewModel : Conductor&lt;IScreen&gt;.Collection.OneActive {
<span style="color:Blue;">readonly</span> Func&lt;TabViewModel&gt; createTab;
<span style="color:Blue;">public</span> PivotPageViewModel(Func&lt;TabViewModel&gt; createTab) {
<span style="color:Blue;">this</span>.createTab = createTab;
}
<span style="color:Blue;">public</span> <span style="color:Blue;">int</span> NumberOfTabs { <span style="color:Blue;">get</span>; <span style="color:Blue;">set</span>; }
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> OnInitialize() {
Enumerable.Range(1, NumberOfTabs).Apply(x =&gt; {
<span style="color:Blue;">var</span> tab = createTab();
tab.DisplayName = <span style="color:#A31515;">&quot;Item &quot;</span> + x;
Items.Add(tab);
});
ActivateItem(Items[0]);
}
}
</pre></div><br />The PivotPageViewModel will receive the number of pivot items to create through it’s NumberOfTabs property, which is pushed in from the query string, as mentioned above. It will then add these items to the conductor and activate the first one. If you’re familiar with the Pivot and CM’s previous sample, you’ll notice that our PivotFix is gone. Pivot has a horrible bug that will crash your application if you try to set the SelectedItem or SelectedIndex to an item 3 or greater from either end of the pivot collection, while the Pivot itself is not visible. This makes it really hard to restore this control from a tombstoned state because you have to set the value at the exact right time. Previously we used a PivotFix hack to work around the control’s bug, but the new tombstoning mechanism is powerful and extensible enough to just make it work. You’ll notice that there are no attributes describing tombstoning behavior. They’ve been removed in favor of a poco model inspired by Fluent NHibhernate. If you would rather have the attributes, you can actually build them on top of the new system. The new system is also more reliable than previously and has a lot more options for storage. Let’s see the class that describes the tombstoning behavior for PivotPageViewModel:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> PivotPageModelStorage : StorageHandler&lt;PivotPageViewModel&gt; {
<span style="color:Blue;">public</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> Configure() {
<span style="color:Blue;">this</span>.ActiveItemIndex()
.InPhoneState()
.RestoreAfterViewLoad();
}
}
</pre></div><br />All you have to do to make a class participate in tombstoning is to inherit from StorageHandler&lt;T&gt;. The PhoneContainer will auto-register anything of this type in the assembly. Just override the Configure method and declare the tombstoning instructions. I’ve created some extension methods for common scenarios. Here’s what the above declaration states:<br />
<ul><li>Persist the Conductor’s ActiveItem’s index</li>
<li>Store the index in PhoneState</li>
<li>Restore the value after the associated view has been loaded.</li></ul>
<br />Let’s look at the storage handler for the TabViewModel to see some more options:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> TabViewModelStorage : StorageHandler&lt;TabViewModel&gt; {
<span style="color:Blue;">public</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> Configure() {
Id(x =&gt; x.DisplayName);
Property(x =&gt; x.Text)
.InPhoneState()
.RestoreAfterActivation();
}
}
</pre></div><br />Here we are specifying an Id because we actually need to persist multiple instances of the same VM. When we restore, we’ll need to know how to map the properties back. We’re also storing the data in PhoneState, but this time we’re not waiting for the view to load, but just waiting for the TabViewModel to be activated by its owning Conductor.<br /><br />Out of the box, we also support storing data in AppSettings. For example, if you wanted to same tab to be selected <b>across application restarts</b> not just when tombstoned, you could define the PivotPageModelStorage like this:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> PivotPageModelStorage : StorageHandler&lt;PivotPageViewModel&gt; {
<span style="color:Blue;">public</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> Configure() {
<span style="color:Blue;">this</span>.ActiveItemIndex()
.InAppSettings()
.RestoreAfterViewLoad();
}
}
</pre></div><br />Pretty easy? All this works by collaborating with the IoC container and keying off of the new event model exposed by the IPhoneService. It’s pretty powerful and extensible. You can add your own storage mechanism or define your own restore timing. You can even implement IStorageHandler directly to write completely custom code on a class by class basis. You could easily add a version that inspected classes for custom attributes and built up the configuration, if you like the attribute model better. You can also store whole instances, not just their properties, and have them rehydrated properly and available for ctor injection.<br /><br /><b>Note About Restore Timing</b><br /><br /><i>If you want the data to be restored as soon as the object is created, leave off the timing specifier, ie. RestoreAfterViewLoad. The default is to restore the data immediately.</i><br />
<h3>Launchers and Choosers</h3>
Launchers and Choosers are painful to work with if you want to do MVVM. In v1.0 we provided a solution to this. I wasn’t happy with its implementation…it was unpredictable in certain scenarios. Once we established the new phone events, better IoC integration and new tombstoning mechanism, I realized I could build a better launcher/chooser system. Let’s take a look at the updated version of TabViewModel in order to see how it works:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> TabViewModel : Screen, IHandle&lt;TaskCompleted&lt;PhoneNumberResult&gt;&gt; {
<span style="color:Blue;">string</span> text;
<span style="color:Blue;">readonly</span> IEventAggregator events;
<span style="color:Blue;">public</span> TabViewModel(IEventAggregator events) {
<span style="color:Blue;">this</span>.events = events;
}
<span style="color:Blue;">public</span> <span style="color:Blue;">string</span> Text {
<span style="color:Blue;">get</span> { <span style="color:Blue;">return</span> text; }
<span style="color:Blue;">set</span> {
text = value;
NotifyOfPropertyChange(() =&gt; Text);
}
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Choose() {
events.RequestTask&lt;PhoneNumberChooserTask&gt;();
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Handle(TaskCompleted&lt;PhoneNumberResult&gt; message) {
MessageBox.Show(<span style="color:#A31515;">&quot;The result was &quot;</span> + message.Result.TaskResult, DisplayName, MessageBoxButton.OK);
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> OnActivate() {
events.Subscribe(<span style="color:Blue;">this</span>);
<span style="color:Blue;">base</span>.OnActivate();
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> OnDeactivate(<span style="color:Blue;">bool</span> close) {
events.Unsubscribe(<span style="color:Blue;">this</span>);
<span style="color:Blue;">base</span>.OnDeactivate(close);
}
}
</pre></div><br />The most significant architectural change I made was to re-implement the launcher/chooser mechanism to work on top of the IEventAggregator. Take a look at the Choose method. The RequestTask method is just an extension method of the IEventAggregator that publishes a special event that the framework is subscribed to. The framework then starts the task. When it’s completed, the framework publishes an event TaskCompleted&lt;T&gt; where T is the result the the chooser returns. You can register for this in the same VM that published the chooser event or in an entirely different one if you like. In the case of our sample, we have 5 TabViewModels that can launch the same chooser. That’s probably not normal, but you can handle this situation in three ways. In our case, the VMs are in a Conductor, and only one of them can be active at a time, so we just Subscribe/Unsubscribe based on the Screen lifecycle so that only the active VM will receive the result. This is a version of the Latch pattern. The second way to handle this is through the event state. When you call the RequestTask method you can pass a state object which you can use for identification purposes later. Yes, this will be present even if the chooser causes a tombstone event. The final way is to have a single object that registers for the completed event, decoupling the launching from the completion. Thus multiple VM could launch the same chooser, but only one class would handle the result.<br />
<h3>IWindowManager</h3>
The IWindowManager was actually in v1.0, as a last minute addition. It’s a really easy way to show native-looking, custom message boxes or modal dialogs. You can also use it to show popups. There is a whole topic devoted to this in the docs.<br /> <br />
<h4>Referenced Samples</h4>
<ul><li>Caliburn.Micro.HelloWP7</li></ul>
<h4>Footnotes</h4>
<ol><li>Even though the IGuardClose interface was designed to handle async scenarios, you must use it synchronously in WP7. This is due to a flaw in the design of Silverlight Navigation Framework which doesn’t account for async shutdown scenarios.</li></ol></div><div class="ClearBoth"></div>tibelWed, 15 Jan 2014 18:13:06 GMTUpdated Wiki: Working with Windows Phone 20140115061306PUpdated Wiki: All About Actionshttps://caliburnmicro.codeplex.com/wikipage?title=All About Actions&version=31<div class="wikidoc"><h1>All About Actions</h1>
<br />We briefly introduced actions in <a href="https://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=All%20About%20Actions">Pt. 1</a>, but there is so much more to know. To begin our investigation, we’ll take our simple “Hello” example and see what it looks like when we explicitly create the actions rather than use conventions. Here’s the Xaml:<br /><br /> <br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">UserControl</span> <span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.Hello.ShellView</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:i</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:cal</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://www.caliburnproject.org</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBox</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Name</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Click Me</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">Interaction.Triggers</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">EventTrigger</span> <span style="color:Red;">EventName</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Click</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">cal</span><span style="color:Blue;">:</span><span style="color:#A31515;">ActionMessage</span> <span style="color:Red;">MethodName</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">SayHello</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">EventTrigger</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">Interaction.Triggers</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Button</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">UserControl</span><span style="color:Blue;">&gt;</span>
</pre></div><br />As you can see, the Actions feature leverages System.Windows.Interactivity for it’s trigger mechanism. This means that you can use anything that inherits from System.Windows.Interactivity.TriggerBase to trigger the sending of an ActionMessage.<sup>1</sup> Perhaps the most common trigger is an EventTrigger, but you can create almost any kind of trigger imaginable or leverage some common triggers already created by the community. ActionMessage is, of course, the Caliburn.Micro-specific part of this markup. It indicates that when the trigger occurs, we should send a message of “SayHello.” So, why do I use the language “send a message” instead of “execute a method” when describing this functionality? That’s the interesting and powerful part. ActionMessage bubbles through the Visual Tree searching for a target instance that can handle it. If a target is found, but does not have a “SayHello” method, the framework will continue to bubble until it finds one, throwing an exception if no “handler” is found.<sup>2</sup> This bubbling nature of ActionMessage comes in handy in a number of interesting scenarios, Master/Details being a key use case. Another important feature to note is Action guards. When a handler is found for the “SayHello” message, it will check to see if that class also has either a property or a method named “CanSayHello.” If you have a guard property and your class implements INotifyPropertyChanged, then the framework will observe changes in that property and re-evaluate the guard accordingly. We’ll discuss method guards in further detail below.<br />
<h2>Action Targets</h2>
Now you’re probably wondering how to specify the target of an ActionMessage. Looking at the markup above, there’s no visible indication of what that target will be. So, where does that come from? Since we used a Model-First approach, when Caliburn.Micro (hereafter CM) created the view and bound it to the ViewModel using the ViewModelBinder, it set this up for us. Anything that goes through the ViewModelBinder will have its action target set automatically. But, you can set it yourself as well, using the attached property Action.Target. Setting this property positions an ActionMessage “handler” in the Visual Tree attached to the node on with you declare the property. It also sets the DataContext to the same value, since you often want these two things to be the same. However, you can vary the Action.Target from the DataContext if you like. Simply use the Action.TargetWithoutContext attached property instead. One nice thing about Action.Target is that you can set it to a System.String and CM will use that string to resolve an instance from the IoC container using the provided value as its key. This gives you a nice way of doing View-First MVVM if you so desire. If you want Action.Target set and you want Action/Binding Conventions applied as well, you can use the Bind.Model attached property in the same way.<br />
<h3>View First</h3>
Let’s see how we would apply this to achieve MVVM using a View-First technique (gasp!) Here’s how we would change our bootstrapper:<br /><br /> <br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> MefBootstrapper : BootstrapperBase
{
<span style="color:Green;">//same as before</span>
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> OnStartup(<span style="color:Blue;">object</span> sender, StartupEventArgs e)
{
Application.RootVisual = <span style="color:Blue;">new</span> ShellView();
}
<span style="color:Green;">//same as before</span>
}
</pre></div><br />Because we are using View-First, we’ve inherited from the non-generic Bootstrapper. The MEF configuration is the same as seen previously, so I have left that out for brevity’s sake. The only other thing that is changed is how the view gets created. In this scenario, we simply override OnStartup, instantiate the view ourselves and set it as the RootVisual (or call Show in the case of WPF). Next, we’ll slightly alter how we are exporting our ShellViewModel, by adding an explicitly named contract:<br /><br /> <br /><div style="color:Black;background-color:White;"><pre>
[Export(<span style="color:#A31515;">&quot;Shell&quot;</span>, <span style="color:Blue;">typeof</span>(IShell))]
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> ShellViewModel : PropertyChangedBase, IShell
{
<span style="color:Green;">//same as before</span>
}
</pre></div><br />Finally, we will alter our view to pull in the VM and perform all bindings:<br /><br /> <br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">UserControl</span> <span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.ViewFirst.ShellView</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:cal</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://www.caliburnproject.org</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">cal:Bind.Model</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Shell</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBox</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Name</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">SayHello</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Click Me</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">UserControl</span><span style="color:Blue;">&gt;</span>
</pre></div><br />Notice the use of the Bind.Model attached property. This resolves our VM by key from the IoC container, sets the Action.Target and DataContext and applies all conventions. I thought it would be nice to show how View-First development is fully supported with CM, but mainly I want to make clear the various ways that you can set targets for actions and the implications of using each technique. Here’s a summary of the available attached properties:<br />
<ul><li><b>Action.Target</b> – Sets both the Action.Target property and the DataContext property to the specified instance. String values are used to resolve an instance from the IoC container. </li>
<li><b>Action.TargetWithoutContext</b> – Sets only the Action.Target property to the specified instance. String values are used to resolve an instance from the IoC container. </li>
<li><b>Bind.Model</b> – View-First - Set’s the Action.Target and DataContext properties to the specified instance. Applies conventions to the view. String values are used to resolve an instance from the IoC container. (Use on root nodes like Window/UserControl/Page.)</li>
<li><b>Bind.ModelWithoutContext</b> - View-First - Set’s the Action.Target to the specified instance. Applies conventions to the view. (Use inside of DataTemplate.)</li>
<li><b>View.Model</b> – ViewModel-First – Locates the view for the specified VM instance and injects it at the content site. Sets the VM to the Action.Target and the DataContext. Applies conventions to the view. </li></ul>
<h2>Action Parameters</h2>
Now, let’s take a look at another interesting aspect of ActionMessage: Parameters. To see this in action, let’s switch back to our original ViewModel-First bootstrapper, etc. and begin by changing our ShellViewModel to look like this: <br /><br /> <br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">using</span> System.ComponentModel.Composition;
<span style="color:Blue;">using</span> System.Windows;
[Export(<span style="color:Blue;">typeof</span>(IShell))]
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> ShellViewModel : IShell
{
<span style="color:Blue;">public</span> <span style="color:Blue;">bool</span> CanSayHello(<span style="color:Blue;">string</span> name)
{
<span style="color:Blue;">return</span> !<span style="color:Blue;">string</span>.IsNullOrWhiteSpace(name);
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> SayHello(<span style="color:Blue;">string</span> name)
{
MessageBox.Show(<span style="color:Blue;">string</span>.Format(<span style="color:#A31515;">&quot;Hello {0}!&quot;</span>, name));
}
}
</pre></div><br />There are a few things to note here. First, we are now working with a completely POCO class; no INPC goop here. Second, we have added an input parameter to our SayHello method. Finally, we changed our CanSayHello property into a method with the same inputs as the action, but with a bool return type. Now, let’s have a look at the Xaml:<br /><br /> <br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">UserControl</span> <span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.HelloParameters.ShellView</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:i</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:cal</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://www.caliburnproject.org</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBox</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Name</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Click Me</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">Interaction.Triggers</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">EventTrigger</span> <span style="color:Red;">EventName</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Click</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">cal</span><span style="color:Blue;">:</span><span style="color:#A31515;">ActionMessage</span> <span style="color:Red;">MethodName</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">SayHello</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">cal</span><span style="color:Blue;">:</span><span style="color:#A31515;">Parameter</span> <span style="color:Red;">Value</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">{Binding ElementName=Name, Path=Text}</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">cal</span><span style="color:Blue;">:</span><span style="color:#A31515;">ActionMessage</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">EventTrigger</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">Interaction.Triggers</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Button</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">UserControl</span><span style="color:Blue;">&gt;</span>
</pre></div><br />Our markup now has one modification: We declared the parameter as part of the ActionMessage using an ElementName Binding. You can have any number of parameters you desire. Value is a DependencyProperty, so all the standard binding capabilities apply to parameters. Did I mention you can do all this in Blend?<br /><br /> <br /> <img src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=caliburnmicro&DownloadId=133357" alt="ActionsInBlend.jpg" title="ActionsInBlend.jpg" /><br /> <br /><br />One thing that is nice about this is that every time the value of a parameter changes, we’ll call the guard method associated with the action(CanSayHello in this case) and use its result to update the UI that the ActionMessage is attached to. Go ahead and run the application. You’ll see that it behaves the same as in previous examples.<br /><br />In addition to literal values and Binding Expressions, there are a number of helpful “special” values that you can use with parameters. These allow you a convenient way to access common contextual information:<br />
<ul><li><b>$eventArgs</b> – Passes the Trigger’s EventArgs or input parameter to your Action. Note: This will be null for guard methods since the trigger hasn’t actually occurred. </li>
<li><b>$dataContext</b> – Passes the DataContext of the element that the ActionMessage is attached to. This is very useful in Master/Detail scenarios where the ActionMessage may bubble to a parent VM but needs to carry with it the child instance to be acted upon. </li>
<li><b>$source</b> – The actual FrameworkElement that triggered the ActionMessage to be sent. </li>
<li><b>$view</b> - The view (usually a UserControl or Window) that is bound to the ViewModel.</li>
<li><b>$executionContext</b> - The actions&#39;s execution context, which contains all the above information and more. This is useful in advanced scenarios.</li>
<li><b>$this</b> - The actual ui element to which the action is attached.</li></ul>
You must start the variable with a “$” but the name is treated in a case-insensitive way by CM. These can be extended through adding values to MessageBinder.SpecialValues.<br /><br /><b>Note: Using Special Values like $this or a Named Element</b><br /><i>When you don&#39;t specify a property, CM uses a default one, which is specified by the particular control convention. For button, that property happens to be &quot;DataContext&quot;, while a TextBox defaults to Text, a Selector to SelectedItem, etc. The same happens when using a reference to another named control in the View instead of $this. The following: &lt;Button cal:Message.Attach=&quot;Click = MyAction(someTextBox)&quot; /&gt; causes CM to pass the Text contained in the TextBox named &quot;someTextBox&quot; to MyAction. The reason why the actual control is <b>never</b> passed to the action is that VMs should never directly deal with UI elements, so the convention discourages it. Note, however, that the control itself could easily be accessed anyway using the extended syntax (based on System.Windows.Interactivity) to populate the parameters, or customizing the Parser.</i><br /><br /><b>Word to the Wise</b><br /><i>Parameters are a convenience feature. They are very powerful and can help you out of some tricky spots, but they can be easily abused. Personally, I only use parameters in the simplest scenarios. One place where they have worked nicely for me is in login forms. Another scenario, as mentioned previously is Master/Detail operations.</i><br /> <br /><br />Now, do you want to see something truly wicked? Change your Xaml back to this:<br /><br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">UserControl</span> <span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.HelloParameters.ShellView</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBox</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Name</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">SayHello</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Click Me</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">UserControl</span><span style="color:Blue;">&gt;</span>
</pre></div><br />Running the application will confirm for you that CM’s conventions even understand ActionMessage parameters. We’ll discuss conventions a lot more in the future, but you should be happy to know that these conventions are case-insensitive and can even detect the before-mentioned “special” values.<br /><br />
<h2>Action Bubbling</h2>
Now, lets look at a simple Master/Detail scenario that demonstrates ActionMessage bubbling, but let’s do it with a shorthand syntax that is designed to be more developer friendly. We’ll start by adding a simple new class named Model:<br /><br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">using</span> System;
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> Model
{
<span style="color:Blue;">public</span> Guid Id { <span style="color:Blue;">get</span>; <span style="color:Blue;">set</span>; }
}
</pre></div><br />And then we’ll change our ShellViewModel to this:<br /><br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">using</span> System;
<span style="color:Blue;">using</span> System.ComponentModel.Composition;
[Export(<span style="color:Blue;">typeof</span>(IShell))]
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> ShellViewModel : IShell
{
<span style="color:Blue;">public</span> BindableCollection&lt;Model&gt; Items { <span style="color:Blue;">get</span>; <span style="color:Blue;">private</span> <span style="color:Blue;">set</span>; }
<span style="color:Blue;">public</span> ShellViewModel()
{
Items = <span style="color:Blue;">new</span> BindableCollection&lt;Model&gt;{
<span style="color:Blue;">new</span> Model { Id = Guid.NewGuid() },
<span style="color:Blue;">new</span> Model { Id = Guid.NewGuid() },
<span style="color:Blue;">new</span> Model { Id = Guid.NewGuid() },
<span style="color:Blue;">new</span> Model { Id = Guid.NewGuid() }
};
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Add()
{
Items.Add(<span style="color:Blue;">new</span> Model { Id = Guid.NewGuid() });
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> Remove(Model child)
{
Items.Remove(child);
}
}
</pre></div><br />Now our shell has a collection of Model instances along with the ability to add or remove from the collection. Notice that the Remove method takes a single parameter of type Model. Now, let’s update the ShellView:<br /><br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">UserControl</span> <span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.BubblingAction.ShellView</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:cal</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://www.caliburnproject.org</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">ItemsControl</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Items</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">ItemsControl.ItemTemplate</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">DataTemplate</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">StackPanel</span> <span style="color:Red;">Orientation</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Horizontal</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Remove</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">cal:Message.Attach</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Remove($dataContext)</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBlock</span> <span style="color:Red;">Text</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">{Binding Id}</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">DataTemplate</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">ItemsControl.ItemTemplate</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">ItemsControl</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Add</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">cal:Message.Attach</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Add</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">UserControl</span><span style="color:Blue;">&gt;</span>
</pre></div>
<h3>Message.Attach</h3>
The first thing to notice is that we are using a more Xaml-developer-friendly mechanism for declaring our ActionMessages. The Message.Attach property is backed by a simple parser which takes its textual input and transforms it into the full Interaction.Trigger/ActionMessage that you’ve seen previously. If you work primarily in the Xaml editor and not in the designer, you’re going to like Message.Attach. Notice that neither Message.Attach declarations specify which event should send the message. If you leave off the event, the parser will use the ConventionManager to determine the default event to use for the trigger. In the case of Button, it’s Click. You can always be explicit of coarse. Here’s what the full syntax for our Remove message would look like if we were declaring everything:<br /><br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Remove</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">cal:Message.Attach</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">[Event Click] = [Action Remove($dataContext)]</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
</pre></div><br />Suppose we were to re-write our parameterized SayHello action with the Message.Attach syntax. It would look like this:<br /><br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Click Me</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">cal:Message.Attach</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">[Event Click] = [Action SayHello(Name.Text)]</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
</pre></div><br />But we could also leverage some smart defaults of the parser and do it like this:<br /><br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Click Me</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">cal:Message.Attach</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">SayHello(Name)</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
</pre></div><br />You can specify literals as parameters as well and even declare multiple actions by separating them with a semicolon:<br /><br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Let&#39;s Talk</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">cal:Message.Attach</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">[Event MouseEnter] = [Action Talk(&#39;Hello&#39;, Name.Text)]; [Event MouseLeave] = [Action Talk(&#39;Goodbye&#39;, Name.Text)]</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
</pre></div><br /><b>WARNING</b> Those developers who ask me to expand this functionality into a full-blown expression parser will be taken out back and…dealt with. Message.Attach is not about cramming code into Xaml. It’s purpose is to provide a streamlined syntax for declaring when/what messages to send to the ViewModel. Please don’t abuse this.<br /><br /><br />If you haven’t already, run the application. Any doubts you had will hopefully be put to rest when you see that the message bubbling works as advertised :) Something else I would like to point out is that CM automatically performs type-conversion on parameters. So, for example, you can pump TextBox.Text into a System.Double parameter without any fear of a casting issue.<br /><br />So, we’ve discussed using Interaction.Triggers with ActionMessage, including the use of Parameters with literals, element bindings<sup>3</sup> and special values. We’ve discussed the various ways to set the action target depending on your needs/architectural style: Action.Target, Action.TargetWithoutContext, Bind.Model or View.Model. We also saw an example of the bubbling nature of ActionMessage and demoed it using the streamlined Message.Attach syntax. All along the way we’ve looked at various examples of conventions in action too. Now, there’s one final killer feature of ActionMessage we haven’t discussed yet…Coroutines. But, that will have to wait until next time.<br />
<h2>Referenced Samples</h2>
<ul><li>Caliburn.Micro.HelloExplicitAction</li>
<li>Caliburn.Micro.ViewFirst</li>
<li>Caliburn.Micro.HelloParameters</li>
<li>Caliburn.Micro.BubblingAction</li></ul>
<h2>Footnotes</h2>
<ol><li>Currently, the full version of Caliburn is not based on System.Windows.Interactivity. Caliburn’s trigger mechanism was around long before Blend’s. You may notice a shocking similarity in the markup. That said, Caliburn v2.0 will be migrated to use the Blend model in the near future.</li>
<li>Actually, if no handler is found, before an exception is thrown, the framework will check the current DataContext to see if it has the requested method. This seamed like a reasonable fallback behavior.</li>
<li>One important detail about ElementName Bindings that I didn’t mention…It doesn’t work with WP7 currently. Due to the fact that WP7 is based on a version of Silverlight 3 which had an incomplete implementation of DependencyObject/DependencyProperty, the infrastructure is not present to make this work in any sort of sane way. However, parameter literals and special values still work as described along with all the rest of the ActionMessage features.</li></ol>
</div><div class="ClearBoth"></div>tibelWed, 15 Jan 2014 18:09:58 GMTUpdated Wiki: All About Actions 20140115060958PUpdated Wiki: Customizing The Bootstrapperhttps://caliburnmicro.codeplex.com/wikipage?title=Customizing The Bootstrapper&version=28<div class="wikidoc"><h1>Customizing The Bootstrapper</h1>
<a href="https://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=Customizing%20The%20Bootstrapper">In the last part</a> we discussed the most basic configuration for Caliburn.Micro and demonstrated a couple of simple features related to Actions and Conventions. In this part, I would like to explore the Bootstrapper class a little more. Let’s begin by configuring our application to use an IoC container. We’ll use MEF for this example, but Caliburn.Micro will work well with any container. First, go ahead and grab the code from Part 1. We are going to use that as our starting point. Add two additional references: System.ComponentModel.Composition and System.ComponentModel.Composition.Initialization. Those are the assemblies that contain MEF’s functionality.<sup>1</sup> Now, let’s create a new Bootstrapper called MefBootstrapper. Use the following code:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">using</span> System;
<span style="color:Blue;">using</span> System.Collections.Generic;
<span style="color:Blue;">using</span> System.ComponentModel.Composition;
<span style="color:Blue;">using</span> System.ComponentModel.Composition.Hosting;
<span style="color:Blue;">using</span> System.ComponentModel.Composition.Primitives;
<span style="color:Blue;">using</span> System.Linq;
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> MefBootstrapper : BootstrapperBase
{
<span style="color:Blue;">private</span> CompositionContainer container;
<span style="color:Blue;">public</span> MefBootstrapper()
{
Start();
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> Configure()
{
container = CompositionHost.Initialize(
<span style="color:Blue;">new</span> AggregateCatalog(
AssemblySource.Instance.Select(x =&gt; <span style="color:Blue;">new</span> AssemblyCatalog(x)).OfType&lt;ComposablePartCatalog&gt;()
)
);
<span style="color:Blue;">var</span> batch = <span style="color:Blue;">new</span> CompositionBatch();
batch.AddExportedValue&lt;IWindowManager&gt;(<span style="color:Blue;">new</span> WindowManager());
batch.AddExportedValue&lt;IEventAggregator&gt;(<span style="color:Blue;">new</span> EventAggregator());
batch.AddExportedValue(container);
container.Compose(batch);
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">object</span> GetInstance(Type serviceType, <span style="color:Blue;">string</span> key)
{
<span style="color:Blue;">string</span> contract = <span style="color:Blue;">string</span>.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
<span style="color:Blue;">var</span> exports = container.GetExportedValues&lt;<span style="color:Blue;">object</span>&gt;(contract);
<span style="color:Blue;">if</span> (exports.Any())
<span style="color:Blue;">return</span> exports.First();
<span style="color:Blue;">throw</span> <span style="color:Blue;">new</span> Exception(<span style="color:Blue;">string</span>.Format(<span style="color:#A31515;">&quot;Could not locate any instances of contract {0}.&quot;</span>, contract));
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> IEnumerable&lt;<span style="color:Blue;">object</span>&gt; GetAllInstances(Type serviceType)
{
<span style="color:Blue;">return</span> container.GetExportedValues&lt;<span style="color:Blue;">object</span>&gt;(AttributedModelServices.GetContractName(serviceType));
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> BuildUp(<span style="color:Blue;">object</span> instance)
{
container.SatisfyImportsOnce(instance);
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> OnStartup(<span style="color:Blue;">object</span> sender, StartupEventArgs e)
{
DisplayRootViewFor&lt;IShell&gt;();
}
}
</pre></div><i>Note: We define IShell down below.</i><br /><br />That’s all the code to integrate MEF. First, we override the Configure method of the Bootstrapper class. This gives us an opportunity to set up our IoC container as well as perform any other framework configuration we may want to do, such as customizing conventions. In this case, I’m taking advantage of Silverlight’s CompositionHost to setup the CompositionContainer. You can just instantiate the container directly if you are working with .NET. Then, I’m creating an AggregateCatalog and populating it with AssemblyCatalogs; one for each Assembly in AssemblySource.Instance. So, what is AssemblySoure.Instance? This is the place that Caliburn.Micro looks for Views. You can add assemblies to this at any time during your application to make them available to the framework, but there is also a special place to do it in the Bootstrapper. Simply override SelectAssemblies like this:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> IEnumerable&lt;Assembly&gt; SelectAssemblies()
{
<span style="color:Blue;">return</span> <span style="color:Blue;">new</span>[] {
Assembly.GetExecutingAssembly()
};
}
</pre></div><br />All you have to do is return a list of searchable assemblies. By default, the base class returns the assembly that your Application exists in. So, if all your views are in the same assembly as your application, you don’t even need to worry about this. If you have multiple referenced assemblies that contain views, this is an extension point you need to remember. Also, if you are dynamically loading modules, you’ll need to make sure they get registered with your IoC container and the AssemblySoure.Instance when they are loaded. <br /><br />After creating the container and providing it with the catalogs, I make sure to add a few Caliburn.Micro-specific services. The framework provides default implementations of both IWindowManager and IEventAggregator. Those are pieces that I’m likely to take dependencies on elsewhere, so I want them to be available for injection. I also register the container with itself (just a personal preference).<br /><br />After we configure the container, we need to tell Caliburn.Micro how to use it. That is the purpose of the three overrides that follow. “GetInstance” and “GetAllInstances” are required by the framework. “BuildUp” is optionally used to supply property dependencies to instances of IResult that are executed by the framework. <br /><br /><br /><b>Word to the Wise</b><br /><br /><i>While Caliburn.Micro does provide ServiceLocator functionality through the Bootstrapper’s overrides and the IoC class, you should avoid using this directly in your application code. ServiceLocator is considered by many to be an anti-pattern. Pulling from a container tends to obscure the intent of the dependent code and can make testing more complicated. In future articles I will demonstrate at least one scenario where you may be tempted to access the ServiceLocator from a ViewModel. I’ll also demonstrate some solutions.<sup>2</sup></i><br /><br />Besides what is shown above, there are some other notable methods on the Bootstrapper. You can override OnStartup and OnExit to execute code when the application starts or shuts down respectively and OnUnhandledException to cleanup after any exception that wasn’t specifically handled by your application code. The last override, DisplayRootView, is unique. Let’s look at how it is implemented in Bootstrapper&lt;TRootModel&gt;<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> DisplayRootView()
{
<span style="color:Blue;">var</span> viewModel = IoC.Get&lt;TRootModel&gt;();
<span style="color:Blue;">#if</span> SILVERLIGHT
<span style="color:Blue;">var</span> view = ViewLocator.LocateForModel(viewModel, <span style="color:Blue;">null</span>, <span style="color:Blue;">null</span>);
ViewModelBinder.Bind(viewModel, view, <span style="color:Blue;">null</span>);
<span style="color:Blue;">var</span> activator = viewModel <span style="color:Blue;">as</span> IActivate;
<span style="color:Blue;">if</span> (activator != <span style="color:Blue;">null</span>)
activator.Activate();
Application.RootVisual = view;
<span style="color:Blue;">#else</span>
IWindowManager windowManager;
<span style="color:Blue;">try</span>
{
windowManager = IoC.Get&lt;IWindowManager&gt;();
}
<span style="color:Blue;">catch</span>
{
windowManager = <span style="color:Blue;">new</span> WindowManager();
}
windowManager.Show(viewModel);
<span style="color:Blue;">#endif</span>
}
</pre></div><br />The Silverlight version of this method resolves your root VM from the container, locates the view for it and binds the two together. It then makes sure to “activate” the VM if it implements the appropriate interface. The WPF version does the same thing by using the WindowManager class, more or less. DisplayRootView is basically a convenience implementation for model-first development. If you don’t like it, perhaps because you prefer view-first MVVM, then this is the method you want to override to change that behavior.<br /><br /><blockquote><b>v1.1 Changes</b></blockquote><blockquote>In v1.1 we removed the DisplayRootView override and placed it&#39;s functionality in a helper method named DisplayRootViewFor. The generic bootstrapper now calls this method from the OnStartup override. To change this behavior, just override OnStartup, and instead of calling the base implementation, write your own activation code. This provides better support for splash screens, login screens and access to startup parameters.</blockquote>
<br />Now that you understand all about the Bootstrapper, let’s get our sample working. We need to add the IShell interface. In our case, it’s just a marker interface. But, in a real application, you would have some significant shell-related functionality baked into this contract. Here’s the code:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">interface</span> IShell
{
}
</pre></div><br />Now, we need to implement the interface and decorate our ShellViewModel with the appropriate MEF attributes:<br /><br /><div style="color:Black;background-color:White;"><pre>
[Export(<span style="color:Blue;">typeof</span>(IShell))]
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> ShellViewModel : PropertyChangedBase, IShell
{
...implementation <span style="color:Blue;">is</span> same <span style="color:Blue;">as</span> before...
}
</pre></div><br />Finally, make sure to update your App.xaml and change the HelloBootstrapper to MefBootstrapper. That’s it! Your up and running with MEF and you have a handle on some of the other key extension points of the Bootstrapper as well.<br />
<h2>Using Caliburn.Micro in Office and WinForms Applications</h2>
Caliburn.Micro can be used from non-Xaml hosts. In order to accomplish this, you must follow a slightly different procedure, since your application does not initiate via the App.xaml. Instead, create a custom boostrapper by inheriting from BoostrapperBase (the non-generic version). When you inherit, you should pass &quot;false&quot; to the base constructor&#39;s &quot;useApplication&quot; parameter. This allows the bootstrapper to properly configure Caliburn.Micro without the presence of a Xaml application instance. All you need to do to start the framework is create an instance of your Bootstrapper and call the Start() method. Once the class is instantiated, you can use Caliburn.Micro like normal, probably by invoke the IWindowManager to display new UI.<br />
<h2>Referenced Samples</h2>
<ul><li>Caliburn.Micro.HelloMef</li></ul>
<h2>Footnotes</h2>
<ol><li>If you are using .NET, you will only need to reference System.ComponentModel.Composition.</li>
<li>I’m quite guilty of this myself, but I’m trying to be more conscious of it. I’m also excited to see that modern IoC containers as well as Caliburn.Micro provide some very nice ways to avoid this situation.</li></ol>
</div><div class="ClearBoth"></div>tibelWed, 15 Jan 2014 18:05:07 GMTUpdated Wiki: Customizing The Bootstrapper 20140115060507PUpdated Wiki: Introductionhttps://caliburnmicro.codeplex.com/wikipage?title=Introduction&version=26<div class="wikidoc"><h1>Introduction</h1>
When my <a href="http://live.visitmix.com/MIX10/Sessions/EX15">“Build Your Own MVVM Framework”</a> talk was chosen for Mix10, I was excited to have the opportunity to show others what we had been doing in <a href="http://caliburn.codeplex.com">Caliburn</a> in a simplified, but powerful way. After giving the talk, I received a ton of positive feedback on the techniques/framework that I had demonstrated. I was approached by several companies and individuals who expressed an interest in a more “official” version of what I had shown. That, coupled with the coming of Windows Phone 7, impressed upon me a need to have a more “lean and mean” framework. My vision was to take 90% of Caliburn’s features and squash them into 10% of the code. I started with the Mix sample framework, then used an iterative process of integrating Caliburn v2 features, simplifying and refactoring. I continued along those lines until I had what I felt was a complete solution that mirrored the full version of Caliburn v2, but on a smaller scale.<br /><br />Caliburn.Micro consists of one ~75k assembly (~35k in XAP) that builds for WPF, Silverlight and Windows Phone. It has a single dependency, System.Windows.Interactivity, which you are probably already using regularly in development. Caliburn.Micro is about 2,700 LOC total, so you can easily go through the whole codebase in a short period and hold it in your head. That’s about 10% of the size of Caliburn v2, which is running around 27,000 LOC and is a lot harder to grasp in a short time. The best part is that I believe I was able to put something together that contains all of the features I consider most important in Caliburn. Here’s a brief list:<br />
<ul><li><b>ActionMessages</b> – The Action mechanism allows you to “bind” UI triggers, such as a Button’s “Click” event, to methods on your View-Model or Presenter. The mechanism allows for passing parameters to the method as well. Parameters can be databound to other FrameworkElements or can pass special values, such as the DataContext or EventArgs. All parameters are automatically type converted to the method’s signature. This mechanism also allows the “Action.Target” to vary independently of the DataContext and enables it to be declared at different points in the UI from the trigger. When a trigger occurs, the “message” bubbles through the element tree looking for an Action.Target (handler) that is capable of invoking the specified method. This is why we call them messages. The “bubbling” nature of Action Messages is extremely powerful and very helpful especially in master/detail scenarios. In addition to invocation, the mechanism supports a “CanExecute” guard. If the Action has a corresponding Property or Method with the same name, but preceded by the word “Can,” the invocation of the Action will be blocked and the UI will be disabled. Actions also support Coroutines (see below). That’s all fairly standard for existing Caliburn users, but we do have a few improvements in Caliburn.Micro that will be making their way into the larger framework. The Caliburn.Micro implementation of ActionMessages is built on System.Windows.Interactivity. This allows actions to be triggered by any TriggerBase developed by the community. Furthermore, Caliburn.Micro’s Actions have full design-time support in Blend. Code-centric developers will be happy to know that Caliburn.Micro supports a very terse syntax for declaring these ActionMessages through a special attached property called Message.Attach.</li>
<li><b>Action Conventions</b> – Out of the box, we support a set of binding conventions around the ActionMessage feature. These conventions are based on x:Name. So, if you have a method called “Save” on your ViewModel and a Button named “Save” in your UI, we will automatically create an EventTrigger for the “Click” event and assign an ActionMessage for the “Save” method. Furthermore, we will inspect the method’s signature and properly construct the ActionMessage parameters. This mechanism can be turned off or customized. You can even change or add conventions for different controls. For example, you could make the convention event for Button “MouseMove” instead of “Click” if you really wanted.</li>
<li><b>Binding Conventions</b> – We also support convention-based databinding. This too works with x:Name. If you have a property on your ViewModel with the same name as an element, we will attempt to databind them. Whereas the framework understands convention events for Actions, it additionally understands convention binding properties (which you can customize or extend). When a binding name match occurs, we then proceed through several steps to build up the binding (all of which are customizable), configuring such details as BindingMode, StringFormat, ValueConverter, Validation and UpdateSourceTrigger (works for SL TextBox and PasswordBox too). Finally, we support the addition of custom behaviors for certain scenarios. This allows us to detect whether we need to auto-generate a DataTemplate or wire both the ItemsSource <i>and</i> the SelectedItem of a Selector based on naming patterns.</li>
<li><b>Screens and Conductors</b> – The Screen, ScreenConductor and ScreenCollection patterns enable model-based tracking of the active or current item, enforcing of screen lifecycles and elegant shutdown or shutdown cancellation in an application. Caliburn.Micro’s implementation of these patterns is an evolution of the one found in Caliburn and supports conducting any type of class, not just implementations of IScreen. These improvements are being introduced back into Caliburn. You’ll find that Caliburn.Micro’s screen implementation is quite thorough and even handles asynchronous shutdown scenarios with ease.</li>
<li><b>Event Aggregator</b> – Caliburn.Micro’s EventAggregator is simple yet powerful. The aggregator follows a bus-style pub/sub model. You register a message handler with the aggregator, and it sends you any messages you are interested in. You declare your interest in a particular message type by implementing IHandle&lt;TMessage&gt;. References to handlers are held weakly and publication occurs on the UI thread. We even support polymorphic subscriptions.</li>
<li><b>Coroutines</b> – Any action can optionally choose to return IResult or IEnumerable&lt;IResult&gt;, opening the door to a powerful approach to handling asynchronous programming. Furthermore, implementations of IResult have access to an execution context which tells them what ActionMessage they are executing for, what FrameworkElement triggered the messsage to be sent, what instance the ActionMessage was handled by (invoked on) and what the View is for that instance. Such contextual information enables a loosely-coupled, declarative mechanism by which a Presenter or View-Model can communicate with its View without needing to hold a reference to it at any time.</li>
<li><b>ViewLocator</b> – For every ViewModel in your application, Caliburn.Micro has a basic strategy for locating the View that should render it. We do this based on naming conventions. For example, if your VM is called MyApplication.ViewModels.ShellViewModel, we will look for MyApplication.Views.ShellView. Additionally, we support multiple views over the same View-Model by attaching a View.Context in Xaml. So, given the same model as above, but with a View.Context=”Master” we would search for MyApplication.Views.Shell.Master. Of course, all this is customizable.</li>
<li><b>ViewModelLocator</b> - Though Caliburn.Micro favors the ViewModel-First approach, we also support View-First by providing a ViewModelLocator with the same mapping semantics as the ViewLocator.</li>
<li><b>WindowManager</b> – This service provides a View-Model-centric way of displaying Windows (ChildWindow in Silverlight, Window in WPF, a custom native-styled host in Windows Phone). Simply pass it an instance of the VM and it will locate the view, wrap it in a Window if necessary, apply all conventions you have configured and show the window.</li>
<li><b>PropertyChangedBase and BindableCollection</b> – What self respecting WPF/SL framework could go without a base implementation of INotifyPropertyChanged? The Caliburn.Micro implementation enables string and lambda-based change notification. It also ensures that all events are raised on the UI thread. BindableCollection is a simple collection that inherits from ObservableCollection&lt;T&gt;, but that ensures that all its events are raised on the UI thread as well.</li>
<li><b>Bootstrapper</b> – What’s required to configure this framework and get it up and running? Not much. Simply inherit from Bootstrapper and add an instance of your custom bootstrapper to the Application’s ResourceDictionary. Done. If you want, you can override a few methods to plug in your own IoC container, declare what assemblies should be inspected for Views, etc. It’s pretty simple.</li>
<li><b>Logging</b> – Caliburn.Micro implements a basic logging abstraction. This is important in any serious framework that encourages Convention over Configuration. All the most important parts of the framework are covered with logging. Want to know what conventions are or are not being applied? Turn on logging. Want to know what actions are being executed? Turn on logging. Want to know what events are being published? Turn on logging. You get the picture.</li>
<li><b>MVVM and MVP</b> – In case it isn’t obvious, this framework enables MVVM. MVVM isn’t hard on its own, but Caliburn.Micro strives to go beyond simply getting it done. We want to write elegant, testable, maintainable and extensible presentation layer code…and we want it to be easy to do so. That’s what this is about. If you prefer using Supervising Controller and PassiveView to MVVM, go right ahead. You’ll find that Caliburn.Micro can help you a lot, particularly its Screen/ScreenConductor implementation. If you are not interested in any of the goals I just mentioned, you’d best move along. This framework isn’t for you.</li></ul>
Just to be clear, this isn’t a toy framework. As I said, I really focused on supporting the core and most commonly used features from Caliburn v2. In fact, Caliburn.Micro is going to be my default framework moving forward and I recommend that if you are starting a new project you begin with the Micro framework. I’ve been careful to keep the application developer API consistent with the full version of Caliburn. In fact, the improvements I made in Caliburn.Micro are being folded back into Caliburn v2. What’s the good part about that? You can start developing with Caliburn.Micro, then if you hit edge cases or have some other need to move to Caliburn, you will be able to do so with little or no changes in your application.<br /><br />Keeping with the spirit of “Build Your Own…” I want developers to understand how this little framework works, inside and out. I’ve intentionally chosen Mercurial for source control, because I want developers to take ownership. While I’ve done some work to make the most important parts of the framework extensible, I’m hoping to see many Forks, and looking forward to seeing your Pull requests.</div><div class="ClearBoth"></div>tibelWed, 15 Jan 2014 17:58:21 GMTUpdated Wiki: Introduction 20140115055821PUpdated Wiki: Basic Configuration, Actions and Conventionshttps://caliburnmicro.codeplex.com/wikipage?title=Basic Configuration, Actions and Conventions&version=18<div class="wikidoc"><h1>Basic Configuration, Actions and Conventions</h1>
Open Visual Studio and create a new Silverlight 4 Application called “Caliburn.Micro.Hello”. You don’t need a web site or test project. Add a reference to System.Windows.Interactivity.dll and Caliburn.Micro.dll. You can find them both in the \src\Caliburn.Micro.Silverlight\Bin\Release (or Debug) folder. Delete “MainPage.xaml” and clean up your “App.xaml.cs” so that it looks like this:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">namespace</span> Caliburn.Micro.Hello {
<span style="color:Blue;">using</span> System.Windows;
<span style="color:Blue;">public</span> <span style="color:Blue;">partial</span> <span style="color:Blue;">class</span> App : Application {
<span style="color:Blue;">public</span> App() {
InitializeComponent();
}
}
}
</pre></div><br />Since Caliburn.Micro prefers a View-Model-First approach, let’s start there. Create your first VM and call it ShellViewModel. Use the following code for the implementation:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">namespace</span> Caliburn.Micro.Hello {
<span style="color:Blue;">using</span> System.Windows;
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> ShellViewModel : PropertyChangedBase {
<span style="color:Blue;">string</span> name;
<span style="color:Blue;">public</span> <span style="color:Blue;">string</span> Name {
<span style="color:Blue;">get</span> { <span style="color:Blue;">return</span> name; }
<span style="color:Blue;">set</span> {
name = value;
NotifyOfPropertyChange(() =&gt; Name);
NotifyOfPropertyChange(() =&gt; CanSayHello);
}
}
<span style="color:Blue;">public</span> <span style="color:Blue;">bool</span> CanSayHello {
<span style="color:Blue;">get</span> { <span style="color:Blue;">return</span> !<span style="color:Blue;">string</span>.IsNullOrWhiteSpace(Name); }
}
<span style="color:Blue;">public</span> <span style="color:Blue;">void</span> SayHello() {
MessageBox.Show(<span style="color:Blue;">string</span>.Format(<span style="color:#A31515;">&quot;Hello {0}!&quot;</span>, Name)); <span style="color:Green;">//Don&#39;t do this in real life :)</span>
}
}
}
</pre></div><br />Notice that the ShellViewModel inherits from PropertyChangedBase. This is a base class that implements the infrastructure for property change notification and automatically performs UI thread marshalling. It will come in handy :)<br /><br />Now that we have our VM, let’s create the bootstrapper that will configure the framework and tell it what to do. Create a new class named HelloBootstrapper. You can use this tiny bit of code:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">namespace</span> Caliburn.Micro.Hello {
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> HelloBootstrapper : BootstrapperBase {
<span style="color:Blue;">public</span> HelloBootstrapper() {
Start();
}
<span style="color:Blue;">protected</span> <span style="color:Blue;">override</span> <span style="color:Blue;">void</span> OnStartup(<span style="color:Blue;">object</span> sender, StartupEventArgs e) {
DisplayRootViewFor&lt;ShellViewModel&gt;();
}
}
}
</pre></div><br />The Bootsrapper allows you to specify the type of “root view model” via the generic method. The “root view model” is a VM that Caliburn.Micro will instantiate and use to show your application. Next, we need to place the HelloBootstrapper somewhere where it will be run at startup. To do that, change your App.xaml to match this:<br /><br /><i>Silverlight/Phone</i><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Application</span> <span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:local</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:Caliburn.Micro.Hello</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.Hello.App</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Application.Resources</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">local</span><span style="color:Blue;">:</span><span style="color:#A31515;">HelloBootstrapper</span> <span style="color:Red;">x:Key</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">bootstrapper</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Application.Resources</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Application</span><span style="color:Blue;">&gt;</span>
</pre></div><br /><i>WPF</i><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Application</span> <span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:local</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:Caliburn.Micro.Hello</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.Hello.App</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Application.Resources</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">ResourceDictionary</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">ResourceDictionary.MergedDictionaries</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">ResourceDictionary</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">local</span><span style="color:Blue;">:</span><span style="color:#A31515;">HelloBootstrapper</span> <span style="color:Red;">x:Key</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">bootstrapper</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">ResourceDictionary</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">ResourceDictionary.MergedDictionaries</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">ResourceDictionary</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Application.Resources</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Application</span><span style="color:Blue;">&gt;</span>
</pre></div><br />All we have to do is place a Caliburn.Micro bootstrapper in the Application.Resources and it will do the rest of the work. Now, run the application. You should see something like this:<br /><br /><img src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=caliburnmicro&DownloadId=130828" alt="ViewNotFound.jpg" title="ViewNotFound.jpg" /><br /><br />Caliburn.Micro creates the ShellViewModel, but doesn’t know how to render it. So, let’s create a view. Create a new Silverlight User Control named ShellView. Use the following xaml:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">UserControl</span> <span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.Hello.ShellView</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBox</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Name</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">SayHello</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Click Me</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">UserControl</span><span style="color:Blue;">&gt;</span>
</pre></div><br />Run the application again. You should now see the UI:<br /><br /><img src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=caliburnmicro&DownloadId=130829" alt="ViewFound.jpg" title="ViewFound.jpg" /><br /> <br />Typing something in the TextBox will enable the Button and clicking it will show a message:<br /><br /><img src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=caliburnmicro&DownloadId=130833" alt="ViewWithData.jpg" title="ViewWithData.jpg" /><br /><br />Caliburn.Micro uses a simple naming convention to locate Views for ViewModels. Essentially, it takes the FullName and removes “Model” from it. So, given MyApp.ViewModels.MyViewModel, it would look for MyApp.Views.MyView. Looking at the View and ViewModel side-by-side, you can see that the TextBox with x:Name=”Name” is bound to the “Name” property on the VM. You can also see that the Button with x:Name=”SayHello” is bound to the method with the same name on the VM. The “CanSayHello” property is guarding access to the “SayHello” action by disabling the Button. These are the basics of Caliburn.Micro’s ActionMessage and Conventions functionality. There’s much more to show. But, next time I want to show how we can integrate an IoC container such as MEF.<br />
<h2>Referenced Samples</h2>
<ul><li>Caliburn.Micro.Hello</li></ul>
</div><div class="ClearBoth"></div>tibelWed, 15 Jan 2014 17:56:26 GMTUpdated Wiki: Basic Configuration, Actions and Conventions 20140115055626PUpdated Wiki: Cheat Sheethttps://caliburnmicro.codeplex.com/wikipage?title=Cheat Sheet&version=14<div class="wikidoc"><h1>Cheat Sheet</h1>
This serves as a quick guide to the most frequently used conventions and features in the Caliburn.Micro project. <br />
<h2>Wiring Events</h2>
This is automatically wiring events on controls to call methods on the ViewModel.<br />
<h3>Convention</h3>
<br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Save</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
</pre></div><br />This will cause the Click event of the Button to call &quot;Save&quot; method on the ViewModel. <br />
<h3>Short Syntax</h3>
<br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">cal:Message.Attach</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Save</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
</pre></div><br />This will again cause the &quot;Click&quot; event of the Button to call &quot;Save&quot; method on the ViewModel. <br /><br />Different events can be used like this: <br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">cal:Message.Attach</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">[Event MouseEnter] = [Action Save]</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
</pre></div><br />Different parameters can be passed to the method like this: <br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">cal:Message.Attach</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">[Event MouseEnter] = [Action Save($this)]</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
</pre></div>
<ul><li><b>$eventArgs</b> – Passes the EventArgs or input parameter to your Action. Note: This will be null for guard methods since the trigger hasn’t actually occurred. </li></ul>
<ul><li><b>$dataContext</b> – Passes the DataContext of the element that the ActionMessage is attached to. This is very useful in Master/Detail scenarios where the ActionMessage may bubble to a parent VM but needs to carry with it the child instance to be acted upon. </li></ul>
<ul><li><b>$source</b> – The actual FrameworkElement that triggered the ActionMessage to be sent. </li></ul>
<ul><li><b>$view</b> - The view (usually a UserControl or Window) that is bound to the ViewModel. </li></ul>
<ul><li><b>$executionContext</b> - The action&#39;s execution context, which contains all the above information and more. This is useful in advanced scenarios. </li></ul>
<ul><li><b>$this</b> - The actual UI element to which the action is attached. In this case, the element itself won&#39;t be passed as a parameter, but rather its default property.</li></ul>
<h3>Long Syntax</h3>
<br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">UserControl</span> <span style="color:Red;">x:Class</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Caliburn.Micro.CheatSheet.ShellView</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml/presentation</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:x</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://schemas.microsoft.com/winfx/2006/xaml</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:i</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity</span><span style="color:Black;">&quot;</span>
<span style="color:Red;">xmlns:cal</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">http://www.caliburnproject.org</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBox</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Name</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Button</span> <span style="color:Red;">Content</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Save</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">Interaction.Triggers</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">EventTrigger</span> <span style="color:Red;">EventName</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Click</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">cal</span><span style="color:Blue;">:</span><span style="color:#A31515;">ActionMessage</span> <span style="color:Red;">MethodName</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">Save</span><span style="color:Black;">&quot;</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">cal</span><span style="color:Blue;">:</span><span style="color:#A31515;">Parameter</span> <span style="color:Red;">Value</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">{Binding ElementName=Name, Path=Text}</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">cal</span><span style="color:Blue;">:</span><span style="color:#A31515;">ActionMessage</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">EventTrigger</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">i</span><span style="color:Blue;">:</span><span style="color:#A31515;">Interaction.Triggers</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">Button</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">StackPanel</span><span style="color:Blue;">&gt;</span>
<span style="color:Blue;">&lt;/</span><span style="color:#A31515;">UserControl</span><span style="color:Blue;">&gt;</span>
</pre></div><br />This syntax is Expression Blend friendly. <br />
<h2>Databinding</h2>
This is automatically binding dependency properties on controls to properties on the ViewModel.<br />
<h3>Convention</h3>
<br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBox</span> <span style="color:Red;">x:Name</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">FirstName</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
</pre></div><br />Will cause the &quot;Text&quot; property of the TextBox to be bound to the &quot;FirstName&quot; property on the ViewModel. <br />
<h3>Explicit</h3>
<br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">TextBox</span> <span style="color:Red;">Text</span><span style="color:Blue;">=</span><span style="color:Black;">&quot;</span><span style="color:Blue;">{Binding Path=FirstName, Mode=TwoWay}</span><span style="color:Black;">&quot;</span> <span style="color:Blue;">/&gt;</span>
</pre></div><br />This is the normal way of binding properties.<br />
<h2>Composition</h2>
<i>to do</i><br />
<h3>View-Model First</h3>
<i>to do</i><br />
<h3>View-First</h3>
<i>to do</i><br />
<h2>Window Manager</h2>
<i>to do</i><br />
<h2>Event Aggregator</h2>
The three different methods on the Event Aggregator are:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">interface</span> IEventAggregator {
<span style="color:Blue;">void</span> Subscribe(<span style="color:Blue;">object</span> instance);
<span style="color:Blue;">void</span> Unsubscribe(<span style="color:Blue;">object</span> instance);
<span style="color:Blue;">void</span> Publish(<span style="color:Blue;">object</span> message, Action&lt;System.Action&gt; marshal);
}
</pre></div><br />An event can be a simple class such as:<br /><br /><div style="color:Black;background-color:White;"><pre>
<span style="color:Blue;">public</span> <span style="color:Blue;">class</span> MyEvent {
<span style="color:Blue;">public</span> MyEvent(<span style="color:Blue;">string</span> myData) {
<span style="color:Blue;">this</span>.MyData = myData;
}
<span style="color:Blue;">public</span> <span style="color:Blue;">string</span> MyData { <span style="color:Blue;">get</span>; <span style="color:Blue;">private</span> <span style="color:Blue;">set</span>; }
}
</pre></div><br /></div><div class="ClearBoth"></div>tibelWed, 15 Jan 2014 17:48:24 GMTUpdated Wiki: Cheat Sheet 20140115054824PUpdated Wiki: Introductionhttps://caliburnmicro.codeplex.com/wikipage?title=Introduction&version=25<div class="wikidoc"><h1>Introduction</h1>
When my <a href="http://live.visitmix.com/MIX10/Sessions/EX15">“Build Your Own MVVM Framework”</a> talk was chosen for Mix10, I was excited to have the opportunity to show others what we had been doing in <a href="http://caliburn.codeplex.com">Caliburn</a> in a simplified, but powerful way. After giving the talk, I received a ton of positive feedback on the techniques/framework that I had demonstrated. I was approached by several companies and individuals who expressed an interest in a more “official” version of what I had shown. That, coupled with the coming of Windows Phone 7, impressed upon me a need to have a more “lean and mean” framework. My vision was to take 90% of Caliburn’s features and squash them into 10% of the code. I started with the Mix sample framework, then used an iterative process of integrating Caliburn v2 features, simplifying and refactoring. I continued along those lines until I had what I felt was a complete solution that mirrored the full version of Caliburn v2, but on a smaller scale.<br /><br />Caliburn.Micro consists of one ~75k assembly (~35k in XAP) that builds for WPF4, SL4 and WP7. It has a single dependency, System.Windows.Interactivity, which you are probably already using regularly in development. Caliburn.Micro is about 2,700 LOC total, so you can easily go through the whole codebase in a short period and hold it in your head. That’s about 10% of the size of Caliburn v2, which is running around 27,000 LOC and is a lot harder to grasp in a short time. The best part is that I believe I was able to put something together that contains all of the features I consider most important in Caliburn. Here’s a brief list:<br />
<ul><li><b>ActionMessages</b> – The Action mechanism allows you to “bind” UI triggers, such as a Button’s “Click” event, to methods on your View-Model or Presenter. The mechanism allows for passing parameters to the method as well. Parameters can be databound to other FrameworkElements or can pass special values, such as the DataContext or EventArgs. All parameters are automatically type converted to the method’s signature. This mechanism also allows the “Action.Target” to vary independently of the DataContext and enables it to be declared at different points in the UI from the trigger. When a trigger occurs, the “message” bubbles through the element tree looking for an Action.Target (handler) that is capable of invoking the specified method. This is why we call them messages. The “bubbling” nature of Action Messages is extremely powerful and very helpful especially in master/detail scenarios. In addition to invocation, the mechanism supports a “CanExecute” guard. If the Action has a corresponding Property or Method with the same name, but preceded by the word “Can,” the invocation of the Action will be blocked and the UI will be disabled. Actions also support Coroutines (see below). That’s all fairly standard for existing Caliburn users, but we do have a few improvements in Caliburn.Micro that will be making their way into the larger framework. The Caliburn.Micro implementation of ActionMessages is built on System.Windows.Interactivity. This allows actions to be triggered by any TriggerBase developed by the community. Furthermore, Caliburn.Micro’s Actions have full design-time support in Blend. Code-centric developers will be happy to know that Caliburn.Micro supports a very terse syntax for declaring these ActionMessages through a special attached property called Message.Attach.</li>
<li><b>Action Conventions</b> – Out of the box, we support a set of binding conventions around the ActionMessage feature. These conventions are based on x:Name. So, if you have a method called “Save” on your ViewModel and a Button named “Save” in your UI, we will automatically create an EventTrigger for the “Click” event and assign an ActionMessage for the “Save” method. Furthermore, we will inspect the method’s signature and properly construct the ActionMessage parameters. This mechanism can be turned off or customized. You can even change or add conventions for different controls. For example, you could make the convention event for Button “MouseMove” instead of “Click” if you really wanted.</li>
<li><b>Binding Conventions</b> – We also support convention-based databinding. This too works with x:Name. If you have a property on your ViewModel with the same name as an element, we will attempt to databind them. Whereas the framework understands convention events for Actions, it additionally understands convention binding properties (which you can customize or extend). When a binding name match occurs, we then proceed through several steps to build up the binding (all of which are customizable), configuring such details as BindingMode, StringFormat, ValueConverter, Validation and UpdateSourceTrigger (works for SL TextBox and PasswordBox too). Finally, we support the addition of custom behaviors for certain scenarios. This allows us to detect whether we need to auto-generate a DataTemplate or wire both the ItemsSource <i>and</i> the SelectedItem of a Selector based on naming patterns.</li>
<li><b>Screens and Conductors</b> – The Screen, ScreenConductor and ScreenCollection patterns enable model-based tracking of the active or current item, enforcing of screen lifecycles and elegant shutdown or shutdown cancellation in an application. Caliburn.Micro’s implementation of these patterns is an evolution of the one found in Caliburn and supports conducting any type of class, not just implementations of IScreen. These improvements are being introduced back into Caliburn. You’ll find that Caliburn.Micro’s screen implementation is quite thorough and even handles asynchronous shutdown scenarios with ease.</li>
<li><b>Event Aggregator</b> – Caliburn.Micro’s EventAggregator is simple yet powerful. The aggregator follows a bus-style pub/sub model. You register a message handler with the aggregator, and it sends you any messages you are interested in. You declare your interest in a particular message type by implementing IHandle&lt;TMessage&gt;. References to handlers are held weakly and publication occurs on the UI thread. We even support polymorphic subscriptions.</li>
<li><b>Coroutines</b> – Any action can optionally choose to return IResult or IEnumerable&lt;IResult&gt;, opening the door to a powerful approach to handling asynchronous programming. Furthermore, implementations of IResult have access to an execution context which tells them what ActionMessage they are executing for, what FrameworkElement triggered the messsage to be sent, what instance the ActionMessage was handled by (invoked on) and what the View is for that instance. Such contextual information enables a loosely-coupled, declarative mechanism by which a Presenter or View-Model can communicate with its View without needing to hold a reference to it at any time.</li>
<li><b>ViewLocator</b> – For every ViewModel in your application, Caliburn.Micro has a basic strategy for locating the View that should render it. We do this based on naming conventions. For example, if your VM is called MyApplication.ViewModels.ShellViewModel, we will look for MyApplication.Views.ShellView. Additionally, we support multiple views over the same View-Model by attaching a View.Context in Xaml. So, given the same model as above, but with a View.Context=”Master” we would search for MyApplication.Views.Shell.Master. Of course, all this is customizable.</li>
<li><b>ViewModelLocator</b> - Though Caliburn.Micro favors the ViewModel-First approach, we also support View-First by providing a ViewModelLocator with the same mapping semantics as the ViewLocator.</li>
<li><b>WindowManager</b> – This service provides a View-Model-centric way of displaying Windows (ChildWindow in SL, Window in WPF, a custom native-styled host in WP7). Simply pass it an instance of the VM and it will locate the view, wrap it in a Window if necessary, apply all conventions you have configured and show the window.</li>
<li><b>PropertyChangedBase and BindableCollection</b> – What self respecting WPF/SL framework could go without a base implementation of INotifyPropertyChanged? The Caliburn.Micro implementation enables string and lambda-based change notification. It also ensures that all events are raised on the UI thread. BindableCollection is a simple collection that inherits from ObservableCollection&lt;T&gt;, but that ensures that all its events are raised on the UI thread as well.</li>
<li><b>Bootstrapper</b> – What’s required to configure this framework and get it up and running? Not much. Simply inherit from Bootstrapper and add an instance of your custom bootstrapper to the Application’s ResourceDictionary. Done. If you want, you can override a few methods to plug in your own IoC container, declare what assemblies should be inspected for Views, etc. It’s pretty simple.</li>
<li><b>Logging</b> – Caliburn.Micro implements a basic logging abstraction. This is important in any serious framework that encourages Convention over Configuration. All the most important parts of the framework are covered with logging. Want to know what conventions are or are not being applied? Turn on logging. Want to know what actions are being executed? Turn on logging. Want to know what events are being published? Turn on logging. You get the picture.</li>
<li><b>MVVM and MVP</b> – In case it isn’t obvious, this framework enables MVVM. MVVM isn’t hard on its own, but Caliburn.Micro strives to go beyond simply getting it done. We want to write elegant, testable, maintainable and extensible presentation layer code…and we want it to be easy to do so. That’s what this is about. If you prefer using Supervising Controller and PassiveView to MVVM, go right ahead. You’ll find that Caliburn.Micro can help you a lot, particularly its Screen/ScreenConductor implementation. If you are not interested in any of the goals I just mentioned, you’d best move along. This framework isn’t for you.</li></ul>
Just to be clear, this isn’t a toy framework. As I said, I really focused on supporting the core and most commonly used features from Caliburn v2. In fact, Caliburn.Micro is going to be my default framework moving forward and I recommend that if you are starting a new project you begin with the Micro framework. I’ve been careful to keep the application developer API consistent with the full version of Caliburn. In fact, the improvements I made in Caliburn.Micro are being folded back into Caliburn v2. What’s the good part about that? You can start developing with Caliburn.Micro, then if you hit edge cases or have some other need to move to Caliburn, you will be able to do so with little or no changes in your application.<br /><br />Keeping with the spirit of “Build Your Own…” I want developers to understand how this little framework works, inside and out. I’ve intentionally chosen Mercurial for source control, because I want developers to take ownership. While I’ve done some work to make the most important parts of the framework extensible, I’m hoping to see many Forks, and looking forward to seeing your Pull requests.</div><div class="ClearBoth"></div>tibelWed, 15 Jan 2014 17:44:59 GMTUpdated Wiki: Introduction 20140115054459P