SilverlightShow: Silverlight Community http://www.silverlightshow.net/ Silverlight articles, Silverlight tutorials, Silverlight videos, Silverlight samples SilverlightShow.net http://www.rssboard.org/rss-specification Argotic Syndication Framework 2008.0.2.0, http://www.codeplex.com/Argotic en-US estoychev@completit.com (Emil Stoychev) WinRT Business Apps with Prism: Client Side Validation <table width="20"> <tbody> <tr> <td> <div data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-Client-Side-Validation.aspx" data-font="segoe ui" data-layout="button_count" class="fb-like"></div> <br /> </td> <td><a data-via="silverlightshow" data-counturl="http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-Client-Side-Validation.aspx" data-count="horizontal" data-text="Article by @briannoyes: '#WinRT Business Apps with #Prism: Client Side Validation'. #win8dev" data-url="http://slshow.net/18rkJmX" href="https://twitter.com/share" class="twitter-share-button">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-Client-Side-Validation.aspx"></g:plusone><br /> </td> <td> </td> </tr> </tbody> </table> <div style="border: 1px solid #dddddd; width: 400px; padding-top: 10px; padding-left: 10px; margin-top: 5px; margin-left: 150px; background-color: #f3f3f3; text-align: center;"><strong><a href="http://www.silverlightshow.net/Storage/Sources/HelloPrismForWinRTPart5.zip">Download the source code for this article</a></strong> </div> <p>This is part 5 in the series WinRT Business Apps with Prism.</p> <h3>Introduction</h3> <p>In this article, I am going to show you how to use the client side validation mechanisms of <a href="http://prismwindowsruntime.codeplex.com/">Prism for Windows Runtime</a>. One challenge you face when you sit down to write a business application with WinRT is that you will probably have a fair amount of data entry in a business application. But then you will quickly discover that unlike WPF and Silverlight, which had great support for input validation through features in the Bindings and controls, WinRT has none. Sure you can write logic that detects when a property changes, evaluate some rules, and then maybe pop a message dialog in the user’s face if they input some bad data. But you will be spinning the code and the patterns for doing that all by yourself. And you won’t have any native support at the input control level for detecting and showing validation. </p> <div style="border: 1px solid #dddddd; width: 200px; padding-top: 5px; padding-bottom: 5px; padding-left: 10px; margin-top: 5px; margin-left: 10px; float: right; background-color: #f3f3f3;"> <h3>Don't miss</h3> <ul style="margin: 0px; padding-left: 20px; font-size: 12px; list-style-type: circle;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/Working-in-the-background-in-Win8-Webinar.aspx">Webinar recording: Working in the background in Win8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx">András Velvárt's Article: Designer-friendly MVVM for XAML Windows Store Apps</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/MVVM-in-Win8-Webinar.aspx">Recording of webinar: MVVM in Windows 8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx">Samidip Basu's Win8 ebook</a>:</li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx"><img usemap="#rade_img_map_1291385581316" src="http://www.silverlightshow.net/Storage/Ebooks/win8_tricks.png" alt="Windows 8 Apps - 8 Must-Know Tricks: Ebook" style="border-width: 0px; border-style: solid; width: 80px; height: 113px;" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>Because this is a primary business app scenario, the Prism team wanted to give you something more to work with. So one of the core features of Prism for Windows Runtime is a set of classes to help you do validation when the user inputs data. These classes evaluate validation rules when properties on a model or view model object change, store the error messages associated with any violated rules in the object so that you can data bind to them and display errors, and some example behaviors to make visual modifications to the bound controls when they have a validation error.</p> <p>So let’s get started seeing how to use those capabilities and looking at the classes that support this in Prism.</p> <h3>Step 1: Add some data entry fields</h3> <p>The starting point for this article’s code is the <a target="_blank" href="http://www.silverlightshow.net/Storage/Sources/HelloPrismForWinRTPart3.zip">completed code from Part 3</a> in this series. In that app, we had a little bit of data input with the selection of products and entry of a quantity, but I need a few more free form entries from a user to demonstrate input validation with a more common scenarios. So I added a Customer model type and some fields at the bottom of the Add Sales page to allow you to input customer information associated with the current order being displayed on that page. Below you can see the visual result and the XAML for those fields as a starting point.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/________Figure1_2.png"><img width="493" height="310" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/________Figure1_thumb.png" alt="Figure1" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" title="Figure1" /></a></p> <p> </p> <div class="csharpcode-wrapper" id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="3"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd"><</span><span class="html">Grid.ColumnDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="*"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd"></</span><span class="html">Grid.ColumnDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd"><</span><span class="html">Grid.RowDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd"></</span><span class="html">Grid.RowDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="attr">Text</span><span class="kwrd">="Name"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Customer.Name, Mode=TwoWay}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum25" class="lnum"> 25:</span> <span class="attr">Width</span><span class="kwrd">="500"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span><span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum27" class="lnum"> 27:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum29" class="lnum"> 29:</span> <span class="attr">Text</span><span class="kwrd">="Phone"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum31" class="lnum"> 31:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum33" class="lnum"> 33:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Customer.Phone, Mode=TwoWay}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum35" class="lnum"> 35:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum36" class="lnum"> 36:</span> <span class="attr">Width</span><span class="kwrd">="500"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum37" class="lnum"> 37:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span><span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum38" class="lnum"> 38:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="2"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum39" class="lnum"> 39:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum40" class="lnum"> 40:</span> <span class="attr">Text</span><span class="kwrd">="Address"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum41" class="lnum"> 41:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum42" class="lnum"> 42:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum43" class="lnum"> 43:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="2"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum44" class="lnum"> 44:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum45" class="lnum"> 45:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Customer.Address, Mode=TwoWay}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum46" class="lnum"> 46:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum47" class="lnum"> 47:</span> <span class="attr">Width</span><span class="kwrd">="500"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum48" class="lnum"> 48:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum49" class="lnum"> 49:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum50" class="lnum"> 50:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum51" class="lnum"> 51:</span> <span class="attr">Text</span><span class="kwrd">="City"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum52" class="lnum"> 52:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum53" class="lnum"> 53:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum54" class="lnum"> 54:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum55" class="lnum"> 55:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum56" class="lnum"> 56:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Customer.City, Mode=TwoWay}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum57" class="lnum"> 57:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum58" class="lnum"> 58:</span> <span class="attr">Width</span><span class="kwrd">="500"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum59" class="lnum"> 59:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum60" class="lnum"> 60:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="4"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum61" class="lnum"> 61:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum62" class="lnum"> 62:</span> <span class="attr">Text</span><span class="kwrd">="State"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum63" class="lnum"> 63:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum64" class="lnum"> 64:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum65" class="lnum"> 65:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="4"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum66" class="lnum"> 66:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum67" class="lnum"> 67:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Customer.State, Mode=TwoWay}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum68" class="lnum"> 68:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum69" class="lnum"> 69:</span> <span class="attr">Width</span><span class="kwrd">="500"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum70" class="lnum"> 70:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum71" class="lnum"> 71:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="5"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum72" class="lnum"> 72:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum73" class="lnum"> 73:</span> <span class="attr">Text</span><span class="kwrd">="Zip Code"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum74" class="lnum"> 74:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum75" class="lnum"> 75:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum76" class="lnum"> 76:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="5"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum77" class="lnum"> 77:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum78" class="lnum"> 78:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Customer.Zip, Mode=TwoWay}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum79" class="lnum"> 79:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum80" class="lnum"> 80:</span> <span class="attr">Width</span><span class="kwrd">="500"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum81" class="lnum"> 81:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum82" class="lnum"> 82:</span> <span class="kwrd"><</span><span class="html">Button</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="6"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum83" class="lnum"> 83:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum84" class="lnum"> 84:</span> <span class="attr">Content</span><span class="kwrd">="Submit Order"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum85" class="lnum"> 85:</span> <span class="attr">Command</span><span class="kwrd">="{Binding SubmitOrderCommand}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum86" class="lnum"> 86:</span> <span class="attr">FontSize</span><span class="kwrd">="20"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum87" class="lnum"> 87:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <h3>Step 2: Add a Customer Model object</h3> <p>Now we need a model object that those fields will bind to. And we want to express some validation rules on that object for those fields. In Prism, we chose to support the most ubiquitous and built-in way to express validation rules – DataAnnotations. If you haven’t been exposed to these, it is a set of attributes in the System.ComponentModel.DataAnnotations namespace and some supporting classes to evaluate them that let you declaratively express validation rules on properties of your model objects. DataAnnotations are automatically evaluated by a number of different parts of the .NET Framework, including ASP.NET model binding, Entity Framework, and WCF RIA Services.</p> <p>Because WinRT does not automatically evaluate those attribute-based rules, we need some infrastructure code to do that for us. Also, once the rules are evaluated, we need to store the resulting errors in a way that can be easily used to display them to the user. This leads us to use the ValidatableBindableBase class from Prism as our Customer base class to provide that support, which I will drill into shortly.</p> <p>The resulting Customer class definition ends up looking like this:</p> <p> </p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">using</span> System;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd">using</span> System.Collections.Generic;</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">using</span> System.ComponentModel.DataAnnotations;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">using</span> System.Linq;</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">using</span> Microsoft.Practices.Prism.StoreApps;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd">namespace</span> HelloPrismForWinRT.Models</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> Customer : ValidatableBindableBase</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd">private</span> <span class="kwrd">string</span> _Name;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd">private</span> <span class="kwrd">string</span> _Phone;</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd">private</span> <span class="kwrd">string</span> _Address;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="kwrd">private</span> <span class="kwrd">string</span> _City;</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd">private</span> <span class="kwrd">string</span> _State;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd">private</span> <span class="kwrd">string</span> _Zip;</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> </pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> [Required]</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> <span class="kwrd">public</span> <span class="kwrd">string</span> Name</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> get { <span class="kwrd">return</span> _Name; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> set { SetProperty(<span class="kwrd">ref</span> _Name, <span class="kwrd">value</span>); }</pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum25" class="lnum"> 25:</span> [RegularExpression(<span class="str">@"^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$"</span>,</pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span> ErrorMessage=<span class="str">"Please enter a 10 digit phone number"</span>)]</pre> <!--CRLF--> <pre class="alt"><span id="lnum27" class="lnum"> 27:</span> <span class="kwrd">public</span> <span class="kwrd">string</span> Phone</pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum29" class="lnum"> 29:</span> get { <span class="kwrd">return</span> _Phone; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> set { SetProperty(<span class="kwrd">ref</span> _Phone, <span class="kwrd">value</span>); }</pre> <!--CRLF--> <pre class="alt"><span id="lnum31" class="lnum"> 31:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum33" class="lnum"> 33:</span> <span class="kwrd">public</span> <span class="kwrd">string</span> Address</pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum35" class="lnum"> 35:</span> get { <span class="kwrd">return</span> _Address; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum36" class="lnum"> 36:</span> set { SetProperty(<span class="kwrd">ref</span> _Address, <span class="kwrd">value</span>); }</pre> <!--CRLF--> <pre class="alt"><span id="lnum37" class="lnum"> 37:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum38" class="lnum"> 38:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum39" class="lnum"> 39:</span> <span class="kwrd">public</span> <span class="kwrd">string</span> City</pre> <!--CRLF--> <pre class="alteven"><span id="lnum40" class="lnum"> 40:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum41" class="lnum"> 41:</span> get { <span class="kwrd">return</span> _City; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum42" class="lnum"> 42:</span> set { SetProperty(<span class="kwrd">ref</span> _City, <span class="kwrd">value</span>); }</pre> <!--CRLF--> <pre class="alt"><span id="lnum43" class="lnum"> 43:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum44" class="lnum"> 44:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum45" class="lnum"> 45:</span> [StringLength(2)]</pre> <!--CRLF--> <pre class="alteven"><span id="lnum46" class="lnum"> 46:</span> <span class="kwrd">public</span> <span class="kwrd">string</span> State</pre> <!--CRLF--> <pre class="alt"><span id="lnum47" class="lnum"> 47:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum48" class="lnum"> 48:</span> get { <span class="kwrd">return</span> _State; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum49" class="lnum"> 49:</span> set { SetProperty(<span class="kwrd">ref</span> _State, <span class="kwrd">value</span>); }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum50" class="lnum"> 50:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum51" class="lnum"> 51:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum52" class="lnum"> 52:</span> <span class="kwrd">public</span> <span class="kwrd">string</span> Zip</pre> <!--CRLF--> <pre class="alt"><span id="lnum53" class="lnum"> 53:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum54" class="lnum"> 54:</span> get { <span class="kwrd">return</span> _Zip; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum55" class="lnum"> 55:</span> set { SetProperty(<span class="kwrd">ref</span> _Zip, <span class="kwrd">value</span>); }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum56" class="lnum"> 56:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum57" class="lnum"> 57:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum58" class="lnum"> 58:</span> }</pre> <!--CRLF--></div> </div> <p>You can see the use of the Required, RegularExpression, and StringLength attributes on the Name, Phone, and State properties, respectively. In addition there is a Range attribute for numeric ranges, and then the power hook – <a target="_blank" href="http://www.silverlightshow.net/items/WCF-RIA-Services-Part-6-Validating-Data.aspx">a CustomValidation attribute that you can point to your own method</a> to do any kind of complex custom validation that you need to.</p> <p>The ValidatableBindableBase class from Prism provides several things for your class. The first is that it inherits from BindableBase itself, which encapsulates the implementation of INotifyPropertyChanged so that your object can participate correctly in data binding when properties change behind the scenes. BindableBase provides some helper methods that let you write more compact property setters like those shown in the Customer class listing where the set block just needs to call SetProperty(), passing a reference to the member variable to be set and the new value that is being set on the property. That method encapsulates checking to see if the value is the same that it was before, in which case it does nothing, or if it is different, it sets the member variable and raises the property changed event.</p> <p>ValidatableBindableBase also encapsulates an instance of a class called BindableValidator. This is the brains of the validation system, in that it has a method called ValidateProperty that can be called for an object it is attached to and it will reflect on that property, find the DataAnnotation attributes, evaluate them, and put any errors for that property into a dictionary of Errors it maintains that keeps a list of errors per property (where the property name is the key in the dictionary and the value is the list of error strings). It also exposes an indexer so that you can simply index into the BindableValidator with a property name and it will return the list of error strings associated with that property.</p> <p>ValidatableBindableBase exposes the underlying indexer from the BindableValidator so that it can be used in data binding, along with a GetAllErrors method if you want to display a validation summary to the user for all errors on a given object. It also overrides the SetProperty method from BindableBase so it can use that as a trigger point for calling ValidateProperty when a property is changing. And of course if you know your WinRT data binding, you know that will happen when there is a focus change off a field that is being edited.</p> <h3>Step 3: Expose the Customer for data binding</h3> <p>I added a Customer property to the AddSalesPageViewModel, but since that will be associated with the current order that is being managed by the OrderRepository, the view model simply gets the Customer out of the repository:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> Customer Customer </pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> { </pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> get { <span class="kwrd">return</span> _OrderRepository.Customer; } </pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> }</pre> <!--CRLF--></div> </div> <p>Then the Repository just initializes a Customer on construction associated with the current order. Obviously in a real application there would need to be a way to clear out the current data associated with an order when it is completed or canceled to allow other orders to be placed, but this sample is not covering that use case.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">interface</span> IOrderRepository</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">void</span> AddToOrder(Product product, <span class="kwrd">int</span> quantity);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> ObservableCollection<OrderItem> CurrentOrderItems { get; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> Customer Customer { get; set; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> OrderRepository : IOrderRepository</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> ...</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd">public</span> Customer Customer { get; set; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd">public</span> OrderRepository(ISessionStateService stateService)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> Customer = <span class="kwrd">new</span> Customer();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> ...</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> ...</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> }</pre> <!--CRLF--></div> </div> <h3> </h3> <h3>Step 4: Display validation errors to the user</h3> <p>Next to each one of the input fields that have rules associated with them, I added a TextBlock to display the errors for the bound property. That TextBlock needs to be bound to the errors collection associated with that property. Since the bound object is the Customer, and it has an indexer exposed from the ValidatableBindableBase to get to those errors, what that looks like is this:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="2"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource ErrorStyle}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Customer.Errors[Name], </span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> Converter={StaticResource FirstErrorConverter}}" <span class="kwrd">/></span></pre> <!--CRLF--></div> </div> <p>So the Text property is bound to Customer.Errors[Name], which returns the collection of errors strings that result from evaluating the rules associated with the Name property. However, since that returns a collection of strings, we need a converter that will turn that into a simple string to set the Text property. I pulled in a converter from the AdventureWorks Shopper sample application that comes with Prism, which just pulls the first error out of the collection if there are any:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">sealed</span> <span class="kwrd">class</span> FirstErrorConverter : IValueConverter</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> <span class="kwrd">object</span> Convert(<span class="kwrd">object</span> <span class="kwrd">value</span>, Type targetType, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">object</span> parameter, <span class="kwrd">string</span> language)</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> ICollection<<span class="kwrd">string</span>> errors = <span class="kwrd">value</span> <span class="kwrd">as</span> ICollection<<span class="kwrd">string</span>>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd">return</span> errors != <span class="kwrd">null</span> && errors.Count > 0 ? errors.ElementAt(0) : <span class="kwrd">null</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd">public</span> <span class="kwrd">object</span> ConvertBack(<span class="kwrd">object</span> <span class="kwrd">value</span>, Type targetType, </pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd">object</span> parameter, <span class="kwrd">string</span> language)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd">throw</span> <span class="kwrd">new</span> NotImplementedException();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> }</pre> <!--CRLF--></div> </div> <p>The ErrorStyle that is being set simply sets the Foreground color Red and the FontSize to 20.</p> <h3>Step 5: Highlight the control when it has a validation error</h3> <p>Another thing most validation mechanisms do that you may want to support as well is to highlight the control itself in some way when it has a validation error. For example, both WPF and Silverlight put a red box around the control when the Binding sees that there are validation errors. </p> <p>Because there is no built in support for that in WinRT, you have to do a little extra work. The best way to implement some code that supplements the behavior of an existing control that you do not own the code for is with a behavior. In WinRT, <a target="_blank" href="http://briannoyes.net/2012/12/20/AttachedBehaviorsVsAttachedPropertiesVsBlendBehaviors.aspx">attached behaviors</a> (based off of attached properties) are the way to go until we have first class support for Blend Behaviors in WinRT.</p> <p>The Prism sample code has a couple of these already implemented for you. For this article, I pulled the HighlightOnErrors behavior class out of the Prism Validation QuickStart that is designed to work with a TextBox and apply a style to it when there are errors to change it’s appearance. That class looks like this:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">class</span> HighlightOnErrors</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> DependencyProperty PropertyErrorsProperty =</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> DependencyProperty.RegisterAttached(<span class="str">"PropertyErrors"</span>, </pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">typeof</span>(ReadOnlyCollection<<span class="kwrd">string</span>>), <span class="kwrd">typeof</span>(HighlightOnErrors),</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">new</span> PropertyMetadata(BindableValidator.EmptyErrorsCollection, OnPropertyErrorsChanged));</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> ReadOnlyCollection<<span class="kwrd">string</span>> GetPropertyErrors(DependencyObject obj)</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd">if</span> (obj == <span class="kwrd">null</span>) { <span class="kwrd">return</span> <span class="kwrd">null</span>; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd">return</span> (ReadOnlyCollection<<span class="kwrd">string</span>>)obj.GetValue(PropertyErrorsProperty);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> SetPropertyErrors(DependencyObject obj, </pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> ReadOnlyCollection<<span class="kwrd">string</span>> <span class="kwrd">value</span>)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> <span class="kwrd">if</span> (obj == <span class="kwrd">null</span>) { <span class="kwrd">return</span>; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> obj.SetValue(PropertyErrorsProperty, <span class="kwrd">value</span>);</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> OnPropertyErrorsChanged(DependencyObject d, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> DependencyPropertyChangedEventArgs args)</pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> <span class="kwrd">if</span> (args == <span class="kwrd">null</span> || args.NewValue == <span class="kwrd">null</span>) { <span class="kwrd">return</span>; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum25" class="lnum"> 25:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span> TextBox textBox = (TextBox)d;</pre> <!--CRLF--> <pre class="alt"><span id="lnum27" class="lnum"> 27:</span> var propertyErrors = (ReadOnlyCollection<<span class="kwrd">string</span>>)args.NewValue;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum29" class="lnum"> 29:</span> Style textBoxStyle = (propertyErrors.Count() > 0) ? </pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> (Style)Application.Current.Resources[<span class="str">"HighlightTextStyle"</span>] : <span class="kwrd">null</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum31" class="lnum"> 31:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> textBox.Style = textBoxStyle;</pre> <!--CRLF--> <pre class="alt"><span id="lnum33" class="lnum"> 33:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> }</pre> <!--CRLF--></div> </div> <p>You can see that it declares an attached property called PropertyErrors. It is designed so you can set that property through a binding to the errors collection for a property. When the errors collection changes, it will re-evaluate its logic and set a style on the control if there are errors in the errors collection. It is hard wired to expect an application scoped resource named </p> <p>So all we need to do is attach that to the TextBoxes that have rules on them with the PropertyErrors bound the to Errors collection for the same property the Text property is bound to and we are good to go:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Customer.Name, Mode=TwoWay}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="attr">Width</span><span class="kwrd">="500"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="attr">beh:HighlightOnErrors</span>.<span class="attr">PropertyErrors</span><span class="kwrd">="{Binding Customer.Errors[Name]}"</span> <span class="kwrd">/></span></pre> <!--CRLF--></div> </div> <p>Now with that in place on the Name, Phone, and State field, and errors introduced on those fields, we have a display like so:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/____Figure2_2.png"><img width="714" height="196" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/____Figure2_thumb.png" alt="Figure2" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" title="Figure2" /></a></p> <h3>Step 6: Validate all properties on submit</h3> <p>A final thing you probably want to do is make sure all errors are checked when the user tries to submit, because the validation errors do not display until the user has tried to change the field (by design) and you may have some other required fields there. Plus you probably want to prevent calling the back end or trying to persist the changes if they are invalid.</p> <p>To do that I have a DelegateCommand bound to the SubmitOrder button with the following command handler:</p> <p> </p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnSubmit()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="rem">// You can trigger all properties to evaluate their rules </span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> Customer.ValidateProperties();</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="rem">// May want to get all errors for a validation summary display:</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> var allErrors = Customer.GetAllErrors().Values.SelectMany(c => c).ToList();</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="rem">// You can check for any validation errors by checking the count of all errors</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd">if</span> (allErrors.Count == 0)</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="rem">// Go ahead and persist</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> }</pre> <!--CRLF--></div> </div> <p>You can see that the ValidateProperties() method will trigger validation across all properties on the object. Once that is done, the errors collection for each property will be populated. You can collect all errors across all properties with the GetAllErrors method and can flatten that dictionary into a list with LINQ.</p> <h3>Summary</h3> <p>In this article I have shown you how to use the validation features of Prism to support rich input validation with minimal effort. You saw that all you need to do is first have your model objects inherit from ValidatableBindableBase and have your property set blocks call SetProperty on the base. Next you add DataAnnotation attribute based rules to the properties on your object. You can then data bind to that object normally, and whenever you set a property, the data annotations rules for that property will be evaluated. To display the error strings, you can bind through the Errors indexer exposed from the base class, passing in the property that you want to get the errors for. And to display errors on the control itself, you can use a behavior to adorn that control based on the presence of errors in the same indexer.</p> <h3>About the Author</h3> <p>Brian Noyes is CTO of Solliance (<a href="http://www.solliance.net/">www.solliance.net</a>), a software development company offering Architecture as a Service, end-to-end product development, technology consulting and training. Brian is a Microsoft Regional Director and MVP, <a href="http://www.pluralsight.com/">Pluralsight</a> author, and speaker at conferences worldwide.  Brian worked directly on the Prism team with Microsoft patterns & practices, and has a Pluralsight course that covers Prism for Windows Runtime end-to-end titled <a target="_blank" href="http://pluralsight.com/training/Courses/TableOfContents/building-windows-store-business-applications-prism">Building Windows Store Business Apps with Prism</a>. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at <a href="http://briannoyes.net/">http://briannoyes.net/</a> or on Twitter @briannoyes.</p> http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-Client-Side-Validation.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-Client-Side-Validation.aspx#comments http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-Client-Side-Validation.aspx Tue, 11 Jun 2013 11:54:00 GMT WinRT Business Apps with Prism: PubSubEvents <table width="20"> <tbody> <tr> <td> <div data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-PubSubEvents.aspx" data-font="segoe ui" data-layout="button_count" class="fb-like"></div> <br /> </td> <td><a data-via="silverlightshow" data-counturl="http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-PubSubEvents.aspx" data-count="horizontal" data-text="Article by @briannoyes: '#WinRT Business Apps with #Prism: PubSubEvents'. #win8dev #windows8" data-url="http://slshow.net/ZabnIi" href="https://twitter.com/share" class="twitter-share-button">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-PubSubEvents.aspx"></g:plusone><br /> </td> <td> </td> </tr> </tbody> </table> <div style="border: 1px solid #dddddd; width: 400px; padding-top: 10px; padding-left: 10px; margin-top: 5px; margin-left: 150px; background-color: #f3f3f3; text-align: center;"><strong><a href="http://www.silverlightshow.net/Storage/Sources/EventAggregatorQuickstart-Modified-End.zip">Download the source code for this article</a></strong> </div> <p>This is part 4 in the series WinRT Business Apps with Prism.</p> <h3>Introduction</h3> <p>In this article, I am going to cover the loosely coupled communication mechanism from the <a target="_blank" href="http://prismwindowsruntime.codeplex.com/">newly released Prism for Windows Runtime</a>, called PubSubEvents. This communication mechanism is also known as EventAggregator because it is based on the <a target="_blank" href="http://martinfowler.com/eaaDev/EventAggregator.html">design pattern of the same name</a>. If you have had exposure to <a target="_blank" href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-1-Getting-Started.aspx">Prism 4</a>, then you might also be familiar with EventAggregator from there. If you already know how to use Prism 4’s EventAggregator, you know how to use the one that ships with Prism for Windows Runtime, because this is simply a ported version, no functional differences other than the projects in which you can use it. For those folks, the quick and dirty is this: the EventAggregator of Prism 4 was ported to a <a target="_blank" href="http://msdn.microsoft.com/en-us/library/vstudio/gg597391(v=vs.100).aspx">Portable Class Library</a> that uses a SynchronizationContext under the covers for the thread dispatching features, which removes the coupling to WPF and Silverlight and avoids taking a new dependency on WinRT for what the EventAggregator does. This library is set up so that it works with any .NET 4.0 or later, Silverlight 4 or later, Windows Phone 7.1 or later, or WinRT project.</p> <div style="border: 1px solid #dddddd; width: 200px; padding-top: 5px; padding-bottom: 5px; padding-left: 10px; margin-top: 5px; margin-left: 10px; float: right; background-color: #f3f3f3;"> <h3>Don't miss</h3> <ul style="margin: 0px; padding-left: 20px; font-size: 12px; list-style-type: circle;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/Working-in-the-background-in-Win8-Webinar.aspx">Webinar recording: Working in the background in Win8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx">András Velvárt's Article: Designer-friendly MVVM for XAML Windows Store Apps</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/MVVM-in-Win8-Webinar.aspx">Recording of webinar: MVVM in Windows 8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx">Samidip Basu's Win8 ebook</a>:</li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx"><img style="border-width: 0px; border-style: solid; width: 80px; height: 113px;" alt="Windows 8 Apps - 8 Must-Know Tricks: Ebook" src="http://www.silverlightshow.net/Storage/Ebooks/win8_tricks.png" usemap="#rade_img_map_1291385581316" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>In this article, for those that don’t already have a lot of experience with EventAggregator, I will show you how you can use it to communicate between components in your application, typically between ViewModels or between client side services, so that those components do not have to take direct dependencies on each other. Additionally, I’ll show how you can benefit from the fact that Prism PubSubEvents use weak references by default, alleviating the need to worry about unsubscribing from events to avoid memory leaks, how to use it’s thread dispatching capabilities, and how to wire up filter methods to keep your event handlers from being called unless some criteria is met.</p> <h3>Step 1: Set up an app with two decoupled ViewModels</h3> <p>I’m using a modified version of the EventAggregator QuickStart from the Prism for Windows Runtime guidance as my starting point. You can <a href="http://www.silverlightshow.net/Storage/Sources/EventAggregatorQuickstart-Modified-StartPoint.zip">download that starting point here</a>. </p> <p>The official QuickStart is pretty close to the same as the completed sample from this article. The main difference is that the official one does not use the MvvmAppBase class on the App class, so there is a bunch of boilerplate startup code in the App class. This is because this QuickStart was written and documented prior to the MvvmAppBase class being factored out. If you look at the sample code from this article, you will see that the App class is simple and clean by using the MvvmAppBase class instead, the structure of which was discussed in <a target="_blank" href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx">Part 1</a> and <a target="_blank" href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Commands-Dependencies-and-Navigation.aspx">Part 2</a> of this series.</p> <p>This app has a parent ViewModel on the MainPage, with two simple child Views/ViewModels – PublisherViewModel and SubscriberViewModel. Here is what the UI will look like running.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/_______Figure1_2.png"><img width="678" height="425" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/_______Figure1_thumb.png" alt="Figure1" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" title="Figure1" /></a></p> <h3>Step 2: Grab the Prism Libraries through NuGet</h3> <p>To build the app starting point solution, you will need to add in the Microsoft.Practices.Prism.StoreApps and Microsoft.Practices.Prism.PubSubEvents libraries. You can do that by downloading the code from here, or you can use NuGet to pull in the binaries. I’m going to do the latter for this article. So head out to Nuget, and do a search on the terms Prism.StoreApps and Prism.PubSubEvents. At the time I am writing this, the NuGet feed has not been updated, so I had to select Pre-release at the top. But that should be updated soon since Prism for Windows Runtime officially released on May 17 2013.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/___Figure2_2.png"><img width="541" height="306" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/___Figure2_thumb.png" alt="Figure2" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" title="Figure2" /></a></p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/_____Figure3_2.png"><img width="549" height="311" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/_____Figure3_thumb.png" alt="Figure3" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" title="Figure3" /></a></p> <p>At this point, if you downloaded the starting point solution in Step 1, you should be able to build and run, but the buttons don’t do anything noticeable yet.</p> <h3>Step 3: Add the EventAggregator</h3> <p>To do pub/sub events, you need a middleman object to decouple the publisher and the subscriber. The idea is that they can each take a dependency on the middleman, then they don’t have to directly depend on each other. The EventAggregator is that middleman in Prism PubSubEvents. It is a singleton service that acts as a repository or registry of event objects. The event objects are the things that actually do the dispatching of calls from a publisher out to the subscribers for a particular event. So you need to make a reference to the singleton IEventAggregator reference available to the publishers and subscribers. You could do this through a container as was covered in <a target="_blank" href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Commands-Dependencies-and-Navigation.aspx">Part 2</a>, but for this article I am just going to use manual dependency injection.</p> <p>The way the app is structured, the MainPageViewModel explicitly constructs the two child ViewModels (PublisherViewModel and SubscriberViewModel) and renders their views via DataTemplates.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> MainPageViewModel : ViewModel</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> MainPageViewModel()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> SubscriberViewModel = <span class="kwrd">new</span> SubscriberViewModel();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> PublisherViewModel = <span class="kwrd">new</span> PublisherViewModel();</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">public</span> SubscriberViewModel SubscriberViewModel { get; set; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd">public</span> PublisherViewModel PublisherViewModel { get; set; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> }</pre> <!--CRLF--></div> </div> <p> </p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">Page.Resources</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd"><</span><span class="html">DataTemplate</span> <span class="attr">x:Key</span><span class="kwrd">="SubscriberTemplate"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd"><</span><span class="html">views:SubscriberView</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd"></</span><span class="html">DataTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd"><</span><span class="html">DataTemplate</span> <span class="attr">x:Key</span><span class="kwrd">="PublisherTemplate"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd"><</span><span class="html">views:PublisherView</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd"></</span><span class="html">DataTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd"></</span><span class="html">Page.Resources</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> ...</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd"><</span><span class="html">ContentControl</span> <span class="attr">Content</span><span class="kwrd">="{Binding PublisherViewModel}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="attr">ContentTemplate</span><span class="kwrd">="{StaticResource PublisherTemplate}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="attr">HorizontalContentAlignment</span><span class="kwrd">="Center"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="attr">VerticalContentAlignment</span><span class="kwrd">="Center"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="kwrd"><</span><span class="html">ContentControl</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="attr">Content</span><span class="kwrd">="{Binding SubscriberViewModel}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="attr">ContentTemplate</span><span class="kwrd">="{StaticResource SubscriberTemplate}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> <span class="attr">HorizontalContentAlignment</span><span class="kwrd">="Center"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="attr">VerticalContentAlignment</span><span class="kwrd">="Center"</span> <span class="kwrd">/></span></pre> <!--CRLF--></div> </div> <p>So I can simply construct the EventAggregator up in the App class, and pass it into the MainPageViewModel by using a Register call on the ViewModelLocator. It is important to construct the EventAggregator on the UI thread so that it can set up the underlying SynchronizationContext correctly for thread dispatching, so I wait until the OnInitialize override to construct it, then pass it into the MainPageViewModel as a parameter, keeping it in a member variable on the App class to make the singleton lifetime match the App lifetime.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">sealed</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> App : MvvmAppBase</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> IEventAggregator _EventAggregator;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnLaunchApplication(LaunchActivatedEventArgs args)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> NavigationService.Navigate(<span class="str">"Main"</span>, <span class="kwrd">null</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnInitialize(IActivatedEventArgs args)</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd">base</span>.OnInitialize(args);</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> _EventAggregator = <span class="kwrd">new</span> EventAggregator();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> ViewModelLocator.Register(<span class="kwrd">typeof</span>(MainPage).ToString(), </pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> () => <span class="kwrd">new</span> MainPageViewModel(_EventAggregator));</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> }</pre> <!--CRLF--></div> </div> <p>Next I need to modify the MainPageViewModel to accept the constructor parameter, and to pass it down to the PublisherViewModel and SubscriberViewModel.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> MainPageViewModel : ViewModel</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> MainPageViewModel(IEventAggregator eventAggregator)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> SubscriberViewModel = <span class="kwrd">new</span> SubscriberViewModel(eventAggregator);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> PublisherViewModel = <span class="kwrd">new</span> PublisherViewModel(eventAggregator);</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">public</span> SubscriberViewModel SubscriberViewModel { get; set; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd">public</span> PublisherViewModel PublisherViewModel { get; set; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> ...</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> }</pre> <!--CRLF--></div> </div> <p>Now likewise, they each need parameterized constructors to accept and hold the reference to IEventAggregator.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> PublisherViewModel : ViewModel</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> IEventAggregator _EventAggregator;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> </pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">public</span> PublisherViewModel(IEventAggregator eventAggregator)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> _EventAggregator = eventAggregator;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> ...</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> ...</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> }</pre> <!--CRLF--></div> </div> <p> </p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> SubscriberViewModel : ViewModel</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> IEventAggregator _EventAggregator;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> </pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">public</span> SubscriberViewModel(IEventAggregator eventAggregator)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> _EventAggregator = eventAggregator;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> ...</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> ...</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> }</pre> <!--CRLF--></div> </div> <p> </p> <h3>Step 4: Define an event class for the needed communication</h3> <p>For the sample app, the idea is that the publisher will publish when a shopping cart has changed that the subscriber also needs to monitor and display information about. When using Prism PubSubEvents, you define an event class for each distinct communication along with a strongly typed payload that can be passed along with the event. The event for our sample looks like this:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> ShoppingCartChangedEvent : PubSubEvent<ShoppingCart> { }</pre> <!--CRLF--></div> </div> <p>Believe it or not, that is all there is to defining the event. All the implementation is in the PubSubEvent base class. You just need to define a class that represents the specific event you want to publish and maps it through the generic argument to the payload entity you want to pass when it fires. If you have no payload, you can just use object as the type and pass null.</p> <h3>Step 5: Publish</h3> <p>Wherever it is appropriate in your code (based on user interaction or other triggers) you just need one line of code to publish:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> _EventAggregator.GetEvent<ShoppingCartChangedEvent>().Publish(_cart);</pre> <!--CRLF--></div> </div> <p>You call the GetEvent method on IEventAggregator to get a reference to a singleton instance of your event class (managed by the EventAggregator itself), and then call Publish on that event, passing the strongly typed payload. In the sample app, this is done from the command handlers for the buttons in that view, specifically the PublishOnUIThread method for now.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> PublishOnUIThread()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> AddItemToCart();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> _EventAggregator.GetEvent<ShoppingCartChangedEvent>().Publish(_cart);</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> }</pre> <!--CRLF--></div> </div> <h3>Step 6: Subscribe</h3> <p>Likewise, in the Subscriber, you can hook up the subscription wherever it makes sense, but typically in a ViewModel that is on construction, as soon as the EventAggregator reference is injected:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> SubscriberViewModel(IEventAggregator eventAggregator)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> _EventAggregator = eventAggregator;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> ...</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> _EventAggregator.GetEvent<ShoppingCartChangedEvent>().Subscribe(HandleShoppingCartUpdate);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> }</pre> <!--CRLF--></div> </div> <p>The handling method that you pass as a delegate reference to this method needs to have a void return (events are fire and forget) and takes in a single parameter of the payload type:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> HandleShoppingCartUpdate(ShoppingCart cart)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> ItemsInCart = cart.Count;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> }</pre> <!--CRLF--></div> </div> <p>That is it for the basic hookup of pub/sub events in Prism. At this point you should be able to run, click on the “Add Item to Cart (UI Thread) button, and see the count increment in the subscriber view.</p> <h3>Step 7: Define a background subscriber for showing weak references</h3> <p>There is a separate class defined in the sample called BackgroundSubscriber:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> BackgroundSubscriber</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> CoreDispatcher _dispatcher;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">public</span> BackgroundSubscriber(CoreDispatcher dispatcher)</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> _dispatcher = dispatcher;</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> HandleShoppingCartChanged(ShoppingCart cart)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> var threadId = Environment.CurrentManagedThreadId;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> var count = cart.Count;</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="rem">// Assign into local variable because it is meant to be fire </span></pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="rem">// and forget and calling would require an await/async</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> var dialogAction = _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =></pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> MessageDialog dialog = <span class="kwrd">new</span> MessageDialog(</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> <span class="kwrd">string</span>.Format(CultureInfo.InvariantCulture, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> <span class="str">"Shopping cart updated to {0} item(s) in background subscriber on thread {1}"</span>, </pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> count, threadId));</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> var showAsync = dialog.ShowAsync();</pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> });</pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum25" class="lnum"> 25:</span> }</pre> <!--CRLF--></div> </div> <p>There is a little complexity in the code there, but basically this is a class with a method that can be targeted by the pub/sub event that will pop a message dialog even if it is called on a background thread and will show what thread it was called on and the number of items in the shopping cart.</p> <p>The reason for this class is that it is an object that we can explicitly new up, hold a reference to from the view model, then release the reference and cause garbage collection, and see if it sticks around if there is still an event subscription targeting it.</p> <p>So in the subscriber view you can see two buttons – Add Background Subscriber and GC Background Subscriber. The command handler for the first creates the subscriber, adds an event subscription for it, and holds it in a member variable.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> AddBackgroundSubscriber()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="rem">// Create subscriber and hold on to it so it does not get garbage collected</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> _subscriber = <span class="kwrd">new</span> BackgroundSubscriber(Window.Current.Dispatcher);</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> _EventAggregator.GetEvent<ShoppingCartChangedEvent>().Subscribe(</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> _subscriber.HandleShoppingCartChanged);</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> }</pre> <!--CRLF--></div> </div> <p>The second button command handler releases the member variable reference to the subscriber and forces a garbage collection – but note that no code has unsubscribed the event handling that pointed to the object through its handling method.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> GCBackgroundSubscriber()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="rem">// Release and GC, showing that we don't have to unsubscribe </span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="rem">// to keep the subscriber from being garbage collected</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> _subscriber = <span class="kwrd">null</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> GC.Collect();</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> }</pre> <!--CRLF--></div> </div> <p>After adding that code, if you run, click on the Add Background Subscriber button, and then start firing the events from the UI thread, you will see the message dialog pop each time. Then press the GC Background Subscriber button, fire a few more events, and you will see that the background subscriber is no longer there to receive events because it has been garbage collected even though there was never an Unsubscribe call to release the reference that was passed into the event through a delegate. </p> <p>This is there to address the number one cause of memory leaks in .NET applications – event subscriptions between two objects with different lifetimes where the subscribing object has a shorter lifetime from the consuming code that the object it is subscribing on. A normal event subscription through a delegate holds a strong reference back to the subscriber that will prevent it from being garbage collected if it does not get unsubscribed, even if all other references are released.</p> <p>But Prism events use a WeakReference under the covers by default, which the garbage collector ignores in its reference counting scheme, so it will allow the underlying object to get garbage collected if nothing else has a reference to it, thus alleviating you from needing to worry about unsubscribing at the appropriate time.</p> <p>If you want to have a strong reference, just use an overload of the Subscribe method with a second parameter named keepSubscriberReferenceAlive:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> _EventAggregator.GetEvent<ShoppingCartChangedEvent>().Subscribe(</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> _subscriber.HandleShoppingCartChanged, <span class="kwrd">true</span>);</pre> <!--CRLF--></div> </div> <h3> </h3> <h3>Step 8: Leverage Thread Dispatching</h3> <p>Another feature of the PubSubEvents is the ability to tell Prism when you subscribe what thread you want to be notified on. If you were to publish from the non-UI thread button in the publisher using a Task to fire on a background thread:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> PublishOnBackgroundThread()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> AddItemToCart();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> Task.Factory.StartNew(() => </pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> Debug.WriteLine(String.Format(<span class="str">"Publishing from thread: {0}"</span>, </pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> Environment.CurrentManagedThreadId));</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> _EventAggregator.GetEvent<ShoppingCartChangedEvent>().Publish(_cart);</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> });</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> }</pre> <!--CRLF--></div> </div> <p>You would see you have a problem on the subscriber side when it tries to update a property that is bound from the UI – it throws an exception because the event comes into the subscriber on the background thread of the publisher. All you need to do to fix that is use a different overload of the Subscribe method that takes a ThreadOption parameter. This allows you to dictate from the subscriber that you want to be notified on either the Publisher thread (the default), the UIThread, or a Background thread.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> _EventAggregator.GetEvent<ShoppingCartChangedEvent>().Subscribe(</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> HandleShoppingCartUpdate, ThreadOption.UIThread);</pre> <!--CRLF--></div> </div> <p>The PubSubEvents class will handle getting the call dispatched onto the UI thread using a SynchronizationContext it sets up when it is constructed. This means if you are going to use the UIThread option, you need to make sure the EventAggregator is constructed on the UI thread. If you don’t you will get an exception when the Subscribe call is made telling you that. Using SynchronizationContext instead of a Dispatcher means the code can be portable to any .NET platform. If you choose the Background option, a Task will be used to call the subscriber on a Task Scheduler background thread.</p> <h3>Step 9: Leverage Filtering</h3> <p>Sometimes you don’t want your event handler to be called unless some criteria is met first. You could do this by putting a guard condition in the handling method, but from a testability and separation of concerns perspective, that should happen outside of the method that is focused on handling the event. So Prism PubSubEvents lets you pass a filter criteria, in the form of a Predicate<T> delegate (which is equivalent to a Func<T,bool> delegate). You can do that by passing a full delegate reference to a method that takes in the payload type and returns a bool, or you can pass a lambda expression directly to the Subscribe method.</p> <p>So for our example, if we want to show a warning on the screen if the count of items in the shopping cart exceeds 10, we can do the subscription like this:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> _EventAggregator.GetEvent<ShoppingCartChangedEvent>().Subscribe(</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> HandleShoppingCartUpdateFiltered,</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> ThreadOption.UIThread, <span class="kwrd">false</span>, (cart) => cart.Count > 10);</pre> <!--CRLF--></div> </div> <p>HandleShoppingCartUpdateFiltered just sets a property that causes a warning to show. But that won’t be called unless the filter criteria (cart.Count > 10) is met.</p> <h3>Summary</h3> <p>In this article, I showed you how simple PubSubEvents in Prism are to use. You saw that once you have a reference to the IEventAggregator in the publisher and subscriber, it is one line of code to publish, one line of code to subscribe, and effectively one line of code to define the event itself. On the subscriber side you have the options of not using weak references (which it does by default), controlling the thread you are notified on, and passing a filter condition that gets evaluated and must pass (return true) before the handling method is called. The publish and subscribe methods are strongly typed based on the payload type specified by the event class.</p> <p>This allows you to have communications between ViewModels or between repositories and other client side services without needing to pass explicit references between them – meaning more loose coupling in your architecture.</p> <p> </p> <h3>About the Author:</h3> <p>Brian Noyes is CTO of Solliance (<a href="http://www.solliance.net/">www.solliance.net</a>), a software development company offering Architecture as a Service, end-to-end product development, technology consulting and training. Brian is a Microsoft Regional Director and MVP, <a href="http://www.pluralsight.com/">Pluralsight</a> author, and speaker at conferences worldwide.  Brian worked directly on the Prism team with Microsoft patterns and practices. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at <a href="http://briannoyes.net/">http://briannoyes.net/</a> or on Twitter @briannoyes.</p> http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-PubSubEvents.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-PubSubEvents.aspx#comments http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-PubSubEvents.aspx Tue, 21 May 2013 14:01:00 GMT WinRT Business Apps with Prism: App State Management <table width="20"> <tbody> <tr> <td> <div data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-App-State-Management.aspx" data-font="segoe ui" data-layout="button_count" class="fb-like"></div> <br /> </td> <td><a data-via="silverlightshow" data-counturl="http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-App-State-Management.aspx" data-count="horizontal" data-text="Article by @briannoyes: '#WinRT Business Apps with #Prism: App State Management'. #win8dev" data-url="http://slshow.net/15TXDUg" href="https://twitter.com/share" class="twitter-share-button">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-App-State-Management.aspx"></g:plusone><br /> </td> <td> </td> </tr> </tbody> </table> <div style="border: 1px solid #dddddd; width: 400px; padding-top: 10px; padding-left: 10px; margin-top: 5px; margin-left: 150px; background-color: #f3f3f3; text-align: center;"><strong><a href="http://www.silverlightshow.net/Storage/Sources/HelloPrismForWinRTPart3.zip">Download the source code for this article</a></strong> </div> <p>This is part 3 in the series WinRT Business Apps with Prism.</p> <h3>Introduction</h3> <p>In the last article in this series, I walked you quickly through using commands, wiring up dependencies, and handling navigation using Prism in a Windows Store app. In this article I am going to focus on the application lifecycle state management features. I’ll show you how you can manage transient application data that you want to survive when your application gets suspended, terminated, and resumed. You’ll see how you can store objects that are properties in your view models, as well as anywhere else in your application such as transient data in a repository.</p> <h3>WinRT Application Lifecycle</h3> <div style="border: 1px solid #dddddd; width: 200px; padding-top: 5px; padding-bottom: 5px; padding-left: 10px; margin-top: 5px; margin-left: 10px; float: right; background-color: #f3f3f3;"> <h3>Don't miss</h3> <ul style="margin: 0px; padding-left: 20px; font-size: 12px; list-style-type: circle;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/Working-in-the-background-in-Win8-Webinar.aspx">Webinar recording: Working in the background in Win8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx">András Velvárt's Article: Designer-friendly MVVM for XAML Windows Store Apps</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/MVVM-in-Win8-Webinar.aspx">Recording of webinar: MVVM in Windows 8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx">Samidip Basu's Win8 ebook</a>:</li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx"><img usemap="#rade_img_map_1291385581316" src="http://www.silverlightshow.net/Storage/Ebooks/win8_tricks.png" alt="Windows 8 Apps - 8 Must-Know Tricks: Ebook" style="border-width: 0px; border-style: solid; width: 80px; height: 113px;" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>WinRT apps have a number of different ways they can be started, and phases that they go through while running. An app starts in a not running state. Once the user launches it it is running. But the user can switch to a different Windows Store or desktop app at any time, which will cause your app to go off screen. When it does, it goes into a suspended state. While suspended, no threads are allocated to the program, so it is consuming zero CPU resources. But your app stays in memory and if the user switches back to your app (through Windows-key+Tab or a swiping gesture from the left side of the screen on a touch device), then the app immediately begins running again. Threads are reallocated, and the program picks right back up executing whatever it was doing before.</p> <p>However, if your app is suspended and the system is running low on memory, WinRT can choose to terminate your application from its suspended state at any time. When that happens, your app is cleared from memory, and all the objects that were built up and connected together while your app was running are gone as well.  If the user launches your application again after termination, it is part of the platform guidance that the should have the state of the app restored just as if they were resuming directly from the suspended state. Only if the user explicitly shuts the application down (Alt-F4 or a swiping gesture from top to bottom of the screen on a  touch device) are you allowed to reset the application start as if it was a clean start of the application.</p> <p>This lifecycle is depicted in Figure 1. The key thing to understand is that resuming from suspend or launching after termination should result in the same exact user experience – the last screen the user was on should be there, any transient state in the screen should be restored (i.e.. selections, scroll position, etc), and the navigation stack should be back to what it was when they left.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/______Figure1_2.png"><img width="665" height="396" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/______Figure1_thumb.png" alt="Figure1" style="border: 0px none currentcolor; display: inline; background-image: none;" title="Figure1" /></a></p> <p>Figure 1: Windows Store Application States</p> <p>To create that user experience, it means you need to be able to save and restore state that is maintained by your view models and client side services in a Prism app. Prism makes this very easy for you through several mechanisms available to you in your view models and services.</p> <h3>Step 1: Add a user experience working with data</h3> <p>I need to have a requirement to work with data in the app before I can start designing for it. For this article, I decide that I want a simple data interaction scenario for taking a phone order from a customer. The user can select from the products that their company sells, enter a quantity, and add that to the current order. They also need to be able to see what is currently part of the current order. </p> <p>I sketch this out and decide it looks something like this:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure2_5.png"><img width="595" height="218" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/__Figure2_thumb_1.png" alt="Figure2" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" title="Figure2" /></a></p> <p>Figure 2: The AddSalePage UI</p> <p>The XAML for this looks like this:</p> <div class="csharpcode-wrapper" id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">ComboBox</span> <span class="attr">ItemsSource</span><span class="kwrd">="{Binding Products}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">SelectedValue</span><span class="kwrd">="{Binding SelectedProductId, Mode=TwoWay}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">DisplayMemberPath</span><span class="kwrd">="ProductName"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="attr">SelectedValuePath</span><span class="kwrd">="ProductId"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="attr">Margin</span><span class="kwrd">="120,60,0,0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Top"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="attr">Width</span><span class="kwrd">="434"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Text</span><span class="kwrd">="{Binding Quantity, Mode=TwoWay}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="attr">Margin</span><span class="kwrd">="580,60,0,0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="attr">TextWrapping</span><span class="kwrd">="Wrap"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Top"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="attr">Width</span><span class="kwrd">="99"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> <span class="kwrd"><</span><span class="html">Button</span> <span class="attr">Content</span><span class="kwrd">="Add to Order"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="attr">Command</span><span class="kwrd">="{Binding AddToOrderCommand}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> <span class="attr">Margin</span><span class="kwrd">="750,60,0,0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Top"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum25" class="lnum"> 25:</span> <span class="attr">Margin</span><span class="kwrd">="120,15,0,0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum27" class="lnum"> 27:</span> <span class="attr">TextWrapping</span><span class="kwrd">="Wrap"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> <span class="attr">Text</span><span class="kwrd">="Product"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum29" class="lnum"> 29:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Top"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> <span class="attr">Height</span><span class="kwrd">="25"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum31" class="lnum"> 31:</span> <span class="attr">Width</span><span class="kwrd">="215"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum33" class="lnum"> 33:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> <span class="attr">Margin</span><span class="kwrd">="580,15,0,0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum35" class="lnum"> 35:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum36" class="lnum"> 36:</span> <span class="attr">TextWrapping</span><span class="kwrd">="Wrap"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum37" class="lnum"> 37:</span> <span class="attr">Text</span><span class="kwrd">="Quantity"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum38" class="lnum"> 38:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Top"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum39" class="lnum"> 39:</span> <span class="attr">Height</span><span class="kwrd">="25"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum40" class="lnum"> 40:</span> <span class="attr">Width</span><span class="kwrd">="105"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum41" class="lnum"> 41:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum42" class="lnum"> 42:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum43" class="lnum"> 43:</span> <span class="attr">Height</span><span class="kwrd">="416"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum44" class="lnum"> 44:</span> <span class="attr">Margin</span><span class="kwrd">="120,165,0,0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum45" class="lnum"> 45:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum46" class="lnum"> 46:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Top"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum47" class="lnum"> 47:</span> <span class="attr">Width</span><span class="kwrd">="868"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum48" class="lnum"> 48:</span> <span class="kwrd"><</span><span class="html">Grid.RowDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum49" class="lnum"> 49:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="50"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum50" class="lnum"> 50:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="*"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum51" class="lnum"> 51:</span> <span class="kwrd"></</span><span class="html">Grid.RowDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum52" class="lnum"> 52:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum53" class="lnum"> 53:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum54" class="lnum"> 54:</span> <span class="kwrd"><</span><span class="html">Grid.ColumnDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum55" class="lnum"> 55:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="300"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum56" class="lnum"> 56:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="150"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum57" class="lnum"> 57:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="150"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum58" class="lnum"> 58:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="300"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum59" class="lnum"> 59:</span> <span class="kwrd"></</span><span class="html">Grid.ColumnDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum60" class="lnum"> 60:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum61" class="lnum"> 61:</span> <span class="attr">Text</span><span class="kwrd">="Product"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum62" class="lnum"> 62:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum63" class="lnum"> 63:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum64" class="lnum"> 64:</span> <span class="attr">Text</span><span class="kwrd">="Price"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum65" class="lnum"> 65:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum66" class="lnum"> 66:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="2"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum67" class="lnum"> 67:</span> <span class="attr">Text</span><span class="kwrd">="Quantity"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum68" class="lnum"> 68:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum69" class="lnum"> 69:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum70" class="lnum"> 70:</span> <span class="attr">Text</span><span class="kwrd">="Category"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum71" class="lnum"> 71:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum72" class="lnum"> 72:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum73" class="lnum"> 73:</span> <span class="kwrd"><</span><span class="html">ListView</span> <span class="attr">x:Name</span><span class="kwrd">="OrderItemsList"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum74" class="lnum"> 74:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum75" class="lnum"> 75:</span> <span class="attr">ItemsSource</span><span class="kwrd">="{Binding CurrentOrderItems}"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum76" class="lnum"> 76:</span> <span class="kwrd"><</span><span class="html">ListView.ItemTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum77" class="lnum"> 77:</span> <span class="kwrd"><</span><span class="html">DataTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum78" class="lnum"> 78:</span> <span class="kwrd"><</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum79" class="lnum"> 79:</span> <span class="kwrd"><</span><span class="html">Grid.ColumnDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum80" class="lnum"> 80:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="300"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum81" class="lnum"> 81:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="150"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum82" class="lnum"> 82:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="150"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum83" class="lnum"> 83:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="300"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum84" class="lnum"> 84:</span> <span class="kwrd"></</span><span class="html">Grid.ColumnDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum85" class="lnum"> 85:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum86" class="lnum"> 86:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Product.ProductName}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum87" class="lnum"> 87:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum88" class="lnum"> 88:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Product.UnitPrice}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum89" class="lnum"> 89:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="2"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum90" class="lnum"> 90:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Quantity}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum91" class="lnum"> 91:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum92" class="lnum"> 92:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Product.Category}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum93" class="lnum"> 93:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum94" class="lnum"> 94:</span> <span class="kwrd"></</span><span class="html">DataTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum95" class="lnum"> 95:</span> <span class="kwrd"></</span><span class="html">ListView.ItemTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum96" class="lnum"> 96:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum97" class="lnum"> 97:</span> <span class="kwrd"></</span><span class="html">ListView</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum98" class="lnum"> 98:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p> </p> <h3>Step 2:  Add some data to the app</h3> <p>The demo code at the completion of the last article didn’t have much going on in terms of application state, we just had two pages that we were navigating between with commands. The first thing I need to start fleshing out some state management is some data that the application is managing. I added two repositories to the client application, one for showing a collection of products, and one for managing the state of the current order.</p> <p>The ProductsRepository exposes a collection of products:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> ProductsRepository : IProductsRepository</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> IEnumerable<Product> AllProducts()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">return</span> <span class="kwrd">new</span> List<Product></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd">new</span> Product { ProductId = 1, ProductName = <span class="str">"Surface Pro"</span>, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> Category=<span class="str">"Tablets"</span>, UnitPrice = 999.00m, UnitsInStock=42},</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">new</span> Product { ProductId = 2, ProductName = <span class="str">"Surface RT"</span>, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> Category=<span class="str">"Tablets"</span>, UnitPrice = 629.00m, UnitsInStock=33},</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd">new</span> Product { ProductId = 3, ProductName = <span class="str">"Lumia 920"</span>, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> Category=<span class="str">"Phones"</span>, UnitPrice = 400.00m, UnitsInStock=12},</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd">new</span> Product { ProductId = 4, ProductName = <span class="str">"iPhone 5"</span>, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> Category=<span class="str">"Phones"</span>, UnitPrice = 629.00m, UnitsInStock=54},</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd">new</span> Product { ProductId = 5, ProductName = <span class="str">"Razr"</span>, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> Category=<span class="str">"Phones"</span>, UnitPrice = 59.99m, UnitsInStock=987},</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> };</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> }</pre> <!--CRLF--></div> </div> <p>The OrderRepository manages the state of the current order:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> OrderRepository : IOrderRepository</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">readonly</span> ObservableCollection<OrderItem> _OrderItems = </pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">new</span> ObservableCollection<OrderItem>();</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> AddToOrder(Product product, <span class="kwrd">int</span> quantity)</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> var orderitem = (from oi <span class="kwrd">in</span> _OrderItems <span class="kwrd">where</span> oi.Product.ProductId </pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> == product.ProductId select oi).FirstOrDefault();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd">if</span> (orderitem == <span class="kwrd">null</span>)</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> _OrderItems.Add(<span class="kwrd">new</span> OrderItem { Product = product, Quantity = quantity });</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd">else</span> orderitem.Quantity += quantity;</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd">public</span> ObservableCollection<OrderItem> CurrentOrderItems </pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> { </pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> get { <span class="kwrd">return</span> _OrderItems; } </pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> }</pre> <!--CRLF--></div> </div> <h3> </h3> <h3>Step 3: Expose properties from the view model to support the view</h3> <p>If you wade through the XAML in Step 1, you will see that the view has bindings that expect certain things exposed from the ViewModel for data binding. It needs a collection of Products, a SelectedProductId, a Quantity, an AddToOrderCommand, and CurrentOrderItems collection.</p> <p>Some of these will be fed from the repository, so the resulting view model looks like this so far.</p> <p> </p> <h3 id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> AddSalePageViewModel : ViewModel</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> INavigationService _NavService;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> IProductsRepository _ProductsRespository;</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> IOrderRepository _OrderRepository;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">private</span> <span class="kwrd">int</span> _SelectedProductId;</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd">private</span> <span class="kwrd">int</span> _Quantity = 1;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">public</span> AddSalePageViewModel(INavigationService navService, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> IProductsRepository productsRespository, </pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> IOrderRepository orderRepository)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> _OrderRepository = orderRepository;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> _ProductsRespository = productsRespository;</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> _NavService = navService;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> GoBackCommand = <span class="kwrd">new</span> DelegateCommand(</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> () => _NavService.GoBack(),</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> () => _NavService.CanGoBack());</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> AddToOrderCommand = <span class="kwrd">new</span> DelegateCommand(OnAddToOrder, CanAddToOrder);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> <span class="kwrd">public</span> DelegateCommand GoBackCommand { get; <span class="kwrd">private</span> set; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> <span class="kwrd">public</span> DelegateCommand AddToOrderCommand { get; <span class="kwrd">private</span> set; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum25" class="lnum"> 25:</span> <span class="kwrd">public</span> IEnumerable<Product> Products</pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum27" class="lnum"> 27:</span> get { <span class="kwrd">return</span> _ProductsRespository.AllProducts(); }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum29" class="lnum"> 29:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> <span class="kwrd">public</span> ObservableCollection<OrderItem> CurrentOrderItems</pre> <!--CRLF--> <pre class="alt"><span id="lnum31" class="lnum"> 31:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> get { <span class="kwrd">return</span> _OrderRepository.CurrentOrderItems; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum33" class="lnum"> 33:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum35" class="lnum"> 35:</span> <span class="kwrd">public</span> <span class="kwrd">int</span> SelectedProductId</pre> <!--CRLF--> <pre class="alteven"><span id="lnum36" class="lnum"> 36:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum37" class="lnum"> 37:</span> get { <span class="kwrd">return</span> _SelectedProductId; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum38" class="lnum"> 38:</span> set </pre> <!--CRLF--> <pre class="alt"><span id="lnum39" class="lnum"> 39:</span> { </pre> <!--CRLF--> <pre class="alteven"><span id="lnum40" class="lnum"> 40:</span> SetProperty(<span class="kwrd">ref</span> _SelectedProductId, <span class="kwrd">value</span>);</pre> <!--CRLF--> <pre class="alt"><span id="lnum41" class="lnum"> 41:</span> AddToOrderCommand.RaiseCanExecuteChanged();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum42" class="lnum"> 42:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum43" class="lnum"> 43:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum44" class="lnum"> 44:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum45" class="lnum"> 45:</span> <span class="kwrd">public</span> <span class="kwrd">int</span> Quantity</pre> <!--CRLF--> <pre class="alteven"><span id="lnum46" class="lnum"> 46:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum47" class="lnum"> 47:</span> get { <span class="kwrd">return</span> _Quantity; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum48" class="lnum"> 48:</span> set { SetProperty(<span class="kwrd">ref</span> _Quantity, <span class="kwrd">value</span>); }</pre> <!--CRLF--> <pre class="alt"><span id="lnum49" class="lnum"> 49:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum50" class="lnum"> 50:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum51" class="lnum"> 51:</span> <span class="kwrd">private</span> <span class="kwrd">bool</span> CanAddToOrder()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum52" class="lnum"> 52:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum53" class="lnum"> 53:</span> var prod = (from p <span class="kwrd">in</span> _ProductsRespository.AllProducts() <span class="kwrd">where</span> </pre> <!--CRLF--> <pre class="alteven"><span id="lnum54" class="lnum"> 54:</span> p.ProductId == _SelectedProductId select p).FirstOrDefault();</pre> <!--CRLF--> <pre class="alt"><span id="lnum55" class="lnum"> 55:</span> <span class="kwrd">return</span> prod != <span class="kwrd">null</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum56" class="lnum"> 56:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum57" class="lnum"> 57:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum58" class="lnum"> 58:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnAddToOrder()</pre> <!--CRLF--> <pre class="alt"><span id="lnum59" class="lnum"> 59:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum60" class="lnum"> 60:</span> var prod = (from p <span class="kwrd">in</span> _ProductsRespository.AllProducts() <span class="kwrd">where</span> </pre> <!--CRLF--> <pre class="alt"><span id="lnum61" class="lnum"> 61:</span> p.ProductId == _SelectedProductId select p).FirstOrDefault();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum62" class="lnum"> 62:</span> _OrderRepository.AddToOrder(prod, Quantity);</pre> <!--CRLF--> <pre class="alt"><span id="lnum63" class="lnum"> 63:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum64" class="lnum"> 64:</span> }</pre> <!--CRLF--></div> </h3> <p>At this point you should be able to run and get the user experience expected.</p> <h3>Step 4: Admit you have a problem</h3> <p>No, I’m not suggesting you find yourself a chapter of Coder’s Anonymous and start going to meetings because you are addicted to code (although that may be appropriate too!). The problem is that our app does not behave correctly in the face of application suspend – terminate – resume. You could see this by adding the code in steps 1-3 to the ending point from the second article in this series and running. </p> <p>You would navigate to the AddSalePage and select a product and enter a quantity – two pieces of transient state in the view. Then you can force a terminate while debugging a Windows Store app by using the “Debug Location” toolbar in Visual Studio. To do so, switch back to Visual Studio from your running Windows Store app, and select “Suspend and Shutdown”.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/____Figure3_2.png"><img width="484" height="234" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/____Figure3_thumb.png" alt="Figure3" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" title="Figure3" /></a></p> <p>This causes the app to suspend and then be terminated in the same way as if the OS were running low on memory while your app was suspended and it decided to terminate your app. </p> <p>Now run the program again (F5 or click the Start Debugging button in the toolbar). It will start on the correct page (AddtoSalePage), but the selection and the quantity you entered will be gone. This would be a violation of the guideline that says it should be transparent to the user when they launch the app after termination compared to resuming after suspend without termination.</p> <h3>Step 5: Add RestorableState to properties</h3> <p>So what can we do to fix it? Well, Prism makes it really easy to deal with this. The things that cause the selection and that hold the quantity are properties on your ViewModel. You ViewModel inherits (or should) from the Prism ViewModel base class, which has built in wiring to make this simple. All you need to do is decorate your SelectedProductId and Quantity properties with the [RestorableState] attribute.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> [RestorableState]</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd">public</span> <span class="kwrd">int</span> SelectedProductId</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> get { <span class="kwrd">return</span> _SelectedProductId; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> set </pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> { </pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> SetProperty(<span class="kwrd">ref</span> _SelectedProductId, <span class="kwrd">value</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> AddToOrderCommand.RaiseCanExecuteChanged();</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> [RestorableState]</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd">public</span> <span class="kwrd">int</span> Quantity</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> get { <span class="kwrd">return</span> _Quantity; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> set { SetProperty(<span class="kwrd">ref</span> _Quantity, <span class="kwrd">value</span>); }</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> }</pre> <!--CRLF--></div> </div> <p>Now you could run that same scenario again – Suspend and Shutdown from the Debug Location toolbar, start the app again.</p> <p>Now when you restart, your selection is retained, as is the quantity that you entered. Nice!</p> <p>What if the property you want to put [RestorableState] on is a model object or complex type? No problem, you just need to do one more thing to make that work. The way this works under the covers is that the Prism FrameNavigationService is aware when the app is suspending. Likewise, when you navigate away from a view, especially one that you could navigate back to through the back button, you probably want to store and restore state on those transitions as well, and the FrameNavigationService is in charge of that whole process. </p> <p>So whenever Prism sees that the app is suspending or that your ViewModel is being navigated away from, it will find all of the [RestorableState] properties in your ViewModel through reflection, and it will persist the state of them in Local Storage. It uses the WCF DataContractSerializer to do this, just like the SuspensionManager class that gets injected into your Common folder by Visual Studio does. That means the DataContractSerializer needs to know about all the types it will be serializing. For primitives, this is automatic. But for complex types, you need to tell it about your types. </p> <p>To do so, you override a method in the MvvmAppBase class and pass the type information for the model objects you will be using as restorable state like so:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnRegisterKnownTypesForSerialization()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">base</span>.OnRegisterKnownTypesForSerialization();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> SessionStateService.RegisterKnownType(<span class="kwrd">typeof</span>(Product));</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> SessionStateService.RegisterKnownType(<span class="kwrd">typeof</span>(OrderItem));</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> SessionStateService.RegisterKnownType(<span class="kwrd">typeof</span>(OrderItem[]));</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> }</pre> <!--CRLF--></div> </div> <p>Now just so you don’t get yourself confused like I have often done to myself, you might be tempted to change the AddSalePageViewModel to use a SelectedProduct property instead of a SelectedProducyId property and bind the SelectedItem property of the ListView to it instead of the SelectedValue property. Just realize that if you do, you won’t get what you expect when the app starts back up. This is because the SelectedItem property has to point to an instance of an object that is in the bound collection that ItemsSource points to. For this demo, that is the Products collection. But when the [RestorableState] attribute kicks in, it is really going to be populating your SelectedProduct property (assuming it had that attribute) with a new instance of an object based on the data serialized from a previous session. This object is not going to be part of the new collection of Products that are getting returned separately from the ProductsRepository, so the selection will not show up. Just be warned. This is why I went with SelectedValue, which is more resilient to that subtle fact because it is matching by value instead of by object reference.</p> <p>Now if you poke and prod the app and play with Suspend and Shutdown some more, you will realize your still have a problem. Add a couple items to the order and then suspend and terminate. Start the app again and the items are gone. Darn it, we still have more work to do.</p> <h3>Step 6: Use ISessionStateService in your client services</h3> <p>ViewModels are not the only objects in an MVVM app that need to retain state across termination. Your views might too (i.e. a scrollbar position – see the HubPage in the AdventureWorks Shopper sample in Prism for an example of this. They have built in support for this through the Prism VisualStateAwarePage and its Page base class. </p> <p>But what about repositories and other client side services that sit logically behind the ViewModel. They often retain transient state as well.</p> <p>The way you handle this in Prism is to have those objects take a dependency on the Prism ISessionStateService that is managing all the automatic state load/save as the app starts up and shuts down. If you read and write your data into that state service (which exposes a Dictionary API), then it will survive terminations correctly as well.</p> <p>So I just need to modify the OrderRepository that is caching the order data to do this. First I add a dependency on the ISessionStateService:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> ISessionStateService _StateService;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd">private</span> <span class="kwrd">const</span> <span class="kwrd">string</span> CurrentOrderKey = <span class="str">"CurrentOrderKey"</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> OrderRepository(ISessionStateService stateService)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> _StateService = stateService;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> }</pre> <!--CRLF--></div> </div> <p>Notice that I need a unique string key that I will end up associating the state of this service with.</p> <p>Then whenever my state changes, I also write it into the state service:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> AddToOrder(Product product, <span class="kwrd">int</span> quantity)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> var orderitem = (from oi <span class="kwrd">in</span> _OrderItems <span class="kwrd">where</span> oi.Product.ProductId </pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> == product.ProductId select oi).FirstOrDefault();</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">if</span> (orderitem == <span class="kwrd">null</span>)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> _OrderItems.Add(<span class="kwrd">new</span> OrderItem { Product = product, Quantity = quantity });</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd">else</span> orderitem.Quantity += quantity;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="rem">// Write the collection out to the state service</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> _StateService.SessionState[CurrentOrderKey] = _OrderItems.ToArray();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> }</pre> <!--CRLF--></div> </div> <p>Notice the last line of code there, simply using the exposed SessionState Dictionary to write the current state of the service into it.</p> <p>Finally, I need to make sure that the state of the service is initialized based on the state service if there is any state there from a previous session. So I modify the constructor of the service, which will only be called once the first time some other code (i.e. the ViewModel) takes a dependency on it because it is set up as a singleton through the container. When the app starts up after termination, it does still have to reconstruct everything because everything about the app is cleared from memory on termination. So the repository constructor now looks like this:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> OrderRepository(ISessionStateService stateService)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> _StateService = stateService;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">if</span> (_StateService.SessionState.ContainsKey(CurrentOrderKey))</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> IEnumerable<OrderItem> sessionItems = </pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> _StateService.SessionState[CurrentOrderKey] <span class="kwrd">as</span> IEnumerable<OrderItem>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd">if</span> (sessionItems != <span class="kwrd">null</span>)</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd">foreach</span> (OrderItem item <span class="kwrd">in</span> sessionItems)</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> _OrderItems.Add(item);</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> </pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> }</pre> <!--CRLF--></div> </div> <p>And because this is the first time a ViewModel has taken a dependency on the ISessionStateService, we need to make sure the Container knows how to resolve it. So we add one more registration to our OnInitialize method in the App.xaml.cs file to expose the singleton SessionStateService created by the MvvmAppBase class to anyone who wants to dependency inject ISessionStateService. If you were not using a container, you could pass that SessionStateService reference to the constructor of the OrderRepository through manual dependency injection if you were constructing it in the app class as a singleton.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnInitialize(IActivatedEventArgs args)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">base</span>.OnInitialize(args);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> _Container.RegisterInstance<ISessionStateService>(SessionStateService);</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> ...</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span>  </pre> <!--CRLF--></div> </div> <p>Now you should be able to run, add items to the order, suspend and terminate, re-launch the app, and all your transient state is right where it was when the user left the app.</p> <h3>Summary</h3> <p>In this article I have demonstrated how to use the RestorableState attribute in your ViewModels in Prism for Windows Runtime as well as how to use the ISessionStateService. There is one thing I didn’t show – in the last article I showed the OnNavigatedTo and OnNavigatedFrom overrides in the ViewModel base class. Those both get passed a dictionary as one of their arguments. This is basically the dictionary that the view can write state into as well. You could explicitly read and write values into those dictionary when you are navigated to or from, and it would survive termination as well. The RestorableState attribute just makes it a lot more declarative and easy for your ViewModels since the state you care about will typically be in properties anyway. </p> <p>So remember to use RestorableState on properties that affect what the user sees on the screen if it is transient data. If you are already proactively loading and saving state as you are navigated to and from through a service, or to disk with Local Storage or into roaming settings, you just need to make sure you are symmetrical about that as your ViewModels are navigated to and from. But for those things that are logically just “held in memory”, realize they won’t be if you are terminated, but your app is still supposed to pretend they were. [RestorableState] and ISessionStateService make it easy to do that.</p> <p>In the next article I'll take a look at starting to validate data when the user enters it.</p> <h3>About the Author</h3> <p>Brian Noyes is CTO of Solliance (<a href="http://www.solliance.net/">www.solliance.net</a>), a software development company offering Architecture as a Service, end-to-end product development, technology consulting and training. Brian is a Microsoft Regional Director and MVP, <a href="http://www.pluralsight.com/">Pluralsight</a> author, and speaker at conferences worldwide.  Brian worked directly on the Prism team with Microsoft patterns and practices. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at <a href="http://briannoyes.net/">http://briannoyes.net/</a> or on Twitter @briannoyes.</p> http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-App-State-Management.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-App-State-Management.aspx#comments http://www.silverlightshow.net/items/WinRT-Business-Apps-with-Prism-App-State-Management.aspx Mon, 29 Apr 2013 14:26:00 GMT WinRT Business Apps with Prism: Commands, Dependencies, and Navigation <table width="20"> <tbody> <tr> <td> <div data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Commands-Dependencies-and-Navigation.aspx" data-font="segoe ui" data-layout="button_count" class="fb-like"></div> <br /> </td> <td><a data-via="silverlightshow" data-counturl="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Commands-Dependencies-and-Navigation.aspx" data-count="horizontal" data-text="Article by @briannoyes: '#WindowsStore #LOB Apps with Kona: Commands, Dependencies & Navigation'. #win8dev" data-url="http://slshow.net/ZgPzWq" href="https://twitter.com/share" class="twitter-share-button">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Commands-Dependencies-and-Navigation.aspx"></g:plusone><br /> </td> <td> </td> </tr> </tbody> </table> <div style="border: 1px solid #dddddd; width: 400px; padding-top: 10px; padding-left: 10px; margin-top: 5px; margin-left: 150px; background-color: #f3f3f3; text-align: center;"><strong><a href="http://www.silverlightshow.net/Storage/Sources/HelloPrismForWinRTPart2.zip">Download the source code for this article</a></strong> <ul></ul> </div> <p><span style="color: #ff0000;">UPDATE: This article was updated because the name of the guidance changed from it’s code name “Kona” to “Prism for Windows Runtime” for release. The content has not really changed since the original article, just updates for changes in the name of the guidance and for the change in code namespaces.</span></p> <p>This is part 2 in the series WinRT Business Apps with Prism.</p> <h3>Introduction</h3> <div style="border: 1px solid #dddddd; width: 200px; padding-top: 5px; padding-bottom: 5px; padding-left: 10px; margin-top: 5px; margin-left: 10px; float: right; background-color: #f3f3f3;"> <h3>Don't miss</h3> <ul style="margin: 0px; padding-left: 20px; font-size: 12px; list-style-type: circle;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/news/Free-SilverlightShow-Webinar-Windows-8-background.aspx">Join our webinar on May 9: Working in the background in Win8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx">András Velvárt's Article: Designer-friendly MVVM for XAML Windows Store Apps</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/MVVM-in-Win8-Webinar.aspx">Recording of webinar: MVVM in Windows 8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx">Samidip Basu's Win8 ebook</a>:</li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx"><img usemap="#rade_img_map_1291385581316" src="http://www.silverlightshow.net/Storage/Ebooks/win8_tricks.png" alt="Windows 8 Apps - 8 Must-Know Tricks: Ebook" style="border-width: 0px; border-style: solid; width: 80px; height: 113px;" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>In <a target="_blank" href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx">Part 1</a> of this series I covered the background of what Prism for Windows Runtime is and got you started building an app reusing the Microsoft.Practices.Prism.StoreApps project that contains the reusable code library of Prism. The sample application I put together in <a target="_blank" href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx">Part 1</a> was not very impressive, after seven steps, you had nothing more than a “Hello World” kind of application. But what may not have been apparent is that those steps let you lay down the foundation on which you could build a big, complex Windows Store business application with Prism, using the MVVM pattern, integrating with the navigation system, handling state management in the face of suspend/terminate easily and more.</p> <p>In this article I will continue to build out the application a little farther, showing you how you can manage view model dependencies, how to handle commands from the UI in your view models, and how to let the view model participate in navigation as well as having it command navigation.</p> <p>The starting point for the code in this article is the completed code from <a target="_blank" href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx">Part 1</a>, which you can <a href="http://www.silverlightshow.net/Storage/Sources/HelloPrismForWinRTPart1.zip">download here</a>.</p> <h3>Step 1: Add a navigation control to the MainPage</h3> <p>I could just be totally crude and throw a button on the main page, but in a Windows Store application, top level navigation is usually presented by showing items in a GridView and allowing the user to click on those items to make things happen. So I will add a GridView to the main content area of the MainPage and add a single item to it for now, which will be the moral equivalent of a big fat navigation button for the user.</p> <p>So I added the following to the outer Grid control that lays out the page with two rows – one for the header and one for the main content:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">GridView</span> <span class="attr">Margin</span><span class="kwrd">="120,10,0,0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">SelectionMode</span><span class="kwrd">="None"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="attr">ItemsSource</span><span class="kwrd">="{Binding NavCommands}"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd"><</span><span class="html">GridView.ItemTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd"><</span><span class="html">DataTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">Height</span><span class="kwrd">="500"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="attr">Width</span><span class="kwrd">="250"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="attr">Background</span><span class="kwrd">="#33CC33"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd"><</span><span class="html">StackPanel</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">="{Binding}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource SubheaderTextStyle}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Center"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="kwrd"></</span><span class="html">StackPanel</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd"></</span><span class="html">DataTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> <span class="kwrd"></</span><span class="html">GridView.ItemTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="kwrd"></</span><span class="html">GridView</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>Notice that I am expecting to expose a collection of strings I will name NavCommands from my view model. The ItemTemplate is set up to display those as big tall rectangles, with the display text in the rectangle as one string in the collection of NavCommands names.</p> <h3>Step 2: Add an Attached Behavior to hook up a command on ItemClick</h3> <p>Now the only trick is that I need a way to cause interaction with the GridView items – specifically clicking on an item – to dispatch a call into my view model. The GridView does not raise commands, which are a common way to communicate between a view and a view model. However, it does have an ItemClick event which you can enable with a flag called IsItemClickEnabled. A common approach in MVVM to pass an event from the UI to the view model is to use a behavior. to fire a command when the event fires. I wrote an article <a target="_blank" href="http://briannoyes.net/2012/12/20/AttachedBehaviorsVsAttachedPropertiesVsBlendBehaviors.aspx">on my blog</a> that explains what an Attached Behavior is and compares it to a simple attached property and to Blend Behaviors. Attached Behaviors are the only kind of behavior supported out of the box. </p> <p>The code below shows an Attached Behavior class that can be used with the GridView (or a ListView since they share a common base class ListViewBase where the ItemClick event is defined). </p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">class</span> ItemClickToCommandBehavior</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="preproc">#region</span> Command Attached Property</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> ICommand GetCommand(DependencyObject obj)</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">return</span> (ICommand)obj.GetValue(CommandProperty);</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> SetCommand(DependencyObject obj, ICommand <span class="kwrd">value</span>)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> obj.SetValue(CommandProperty, <span class="kwrd">value</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> DependencyProperty CommandProperty =</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> DependencyProperty.RegisterAttached(<span class="str">"Command"</span>, <span class="kwrd">typeof</span>(ICommand), </pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd">typeof</span>(ItemClickToCommandBehavior),</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> <span class="kwrd">new</span> PropertyMetadata(<span class="kwrd">null</span>, OnCommandChanged));</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="preproc">#endregion</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> <span class="preproc">#region</span> Behavior implementation</pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> OnCommandChanged(DependencyObject d, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> DependencyPropertyChangedEventArgs e)</pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> ListViewBase lvb = d <span class="kwrd">as</span> ListViewBase;</pre> <!--CRLF--> <pre class="alt"><span id="lnum25" class="lnum"> 25:</span> <span class="kwrd">if</span> (lvb == <span class="kwrd">null</span>) <span class="kwrd">return</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum27" class="lnum"> 27:</span> lvb.ItemClick += OnClick;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum29" class="lnum"> 29:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> OnClick(<span class="kwrd">object</span> sender, ItemClickEventArgs e)</pre> <!--CRLF--> <pre class="alt"><span id="lnum31" class="lnum"> 31:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> ListViewBase lvb = sender <span class="kwrd">as</span> ListViewBase;</pre> <!--CRLF--> <pre class="alt"><span id="lnum33" class="lnum"> 33:</span> ICommand cmd = lvb.GetValue(ItemClickToCommandBehavior.CommandProperty) <span class="kwrd">as</span> ICommand;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> <span class="kwrd">if</span> (cmd != <span class="kwrd">null</span> && cmd.CanExecute(e.ClickedItem))</pre> <!--CRLF--> <pre class="alt"><span id="lnum35" class="lnum"> 35:</span> cmd.Execute(e.ClickedItem);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum36" class="lnum"> 36:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum37" class="lnum"> 37:</span> <span class="preproc">#endregion</span></pre> <!--CRLF--></div> </div> <p>You can see that what the behavior does is to hook up to the ItemClick event when the Command attached property gets set. It expects that the property will be set through a binding to point to an ICommand object in the view model. When the ItemClick event fires, it gets a reference to the bound command off the GridView element and fires the command, passing the clicked item as a command parameter. This allows the view model to do all the handling of that interaction.</p> <p>To use this behavior, I add a setter for the Command attached property to the GridView like so, and enable IsItemClickEnabled:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">GridView</span> <span class="attr">Margin</span><span class="kwrd">="120,10,0,0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">SelectionMode</span><span class="kwrd">="None"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="attr">ItemsSource</span><span class="kwrd">="{Binding NavCommands}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="attr">beh:ItemClickToCommandBehavior</span>.<span class="attr">Command</span><span class="kwrd">="{Binding NavCommand}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="attr">IsItemClickEnabled</span><span class="kwrd">="True"</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <h3> </h3> <h3>Step 3: Flesh out the MainPageViewModel nav commands</h3> <p>First I need to expose a property named NavCommands from the MainPageViewModel that is a collection of strings, one for each big fat navigation item we want to present in the GridView. For now that will just be one called “Add Sale”. In addition (based on the binding shown on the Command attached property) I need to expose a command property called NavCommand. The view model now looks like this:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> MainPageViewModel : ViewModel</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> MainPageViewModel()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> NavCommands = <span class="kwrd">new</span> ObservableCollection<<span class="kwrd">string</span>></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="str">"Add Sale"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> };</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> NavCommand = <span class="kwrd">new</span> DelegateCommand<<span class="kwrd">string</span>>(OnNavCommand);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd">public</span> ObservableCollection<<span class="kwrd">string</span>> NavCommands { get; set; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd">public</span> DelegateCommand<<span class="kwrd">string</span>> NavCommand { get; set; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnNavCommand(<span class="kwrd">string</span> navCommand)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> </pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> }</pre> <!--CRLF--></div> </div> <p>At this point you should be able to set a breakpoint in the OnNavCommand method, run, click the Add Sale item in the grid and see that the command handler gets invoked.</p> <h3>Step 4a: Change to a Factory Method for ViewModel construction</h3> <p>In order to cause navigation to happen in the view model, it is going to need access to a NavigationService that gets set up in the MvvmAppBase class. That means we need to be able to inject that into the view model as a dependency. There are two ways to do that in Prism for Windows Runtime. The first is that you can set up a factory method for the view model type in the ViewModelLocator and write your own construction code for the view model, passing in whatever dependencies it needs. This is called manual dependency injection. The other is to use a dependency injection container, which I will also show in a later step.</p> <p>So first I declare the dependency that the view model is going to take on:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> MainPageViewModel : ViewModel</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> INavigationService _NavService;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">public</span> MainPageViewModel(INavigationService navService)</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> _NavService = navService;</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> ...</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> ...</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> }</pre> <!--CRLF--></div> </div> <p>Then I go to the App.xaml.cs code behind file and add an override for the OnInitialize method from the base class. In that method, I call the Register method on the ViewModelLocator to set up a factory method (in the form of a Func<object> lambda expression) for the MainPageViewModel type:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnInitialize(IActivatedEventArgs args)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">base</span>.OnInitialize(args);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> ViewModelLocator.Register(<span class="kwrd">typeof</span>(MainPage).ToString(),</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> () => <span class="kwrd">new</span> MainPageViewModel(NavigationService));</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> }</pre> <!--CRLF--></div> </div> <p>Now whenever the ViewModel locator View-to-ViewModel type mapping happens, it will then look to see if there is a registered factory method for the ViewModel type, and if so will use it to construct the view model instead of using the default logic that just constructs the ViewModel with a default constructor. You can see in the snippet above that this allows me to pass in the NavigationService from the MvvmAppBase class as the implementation of INavigationService that the view model is depending on.</p> <h3>Step 4b: Set up a Dependency Injection Container for the App</h3> <p>As an alternative to the approach shown in step 4a, if you are already comfortable with the concepts and usage of a dependency injection (or Inversion of Control – IOC) container, then you can use that instead of the manual dependency injection approach of using the factory methods. If you use a container like Unity that supports constructor injection, then you would define the view model dependency exactly the same as shown in the first code snippet of Step 4a.</p> <p>Next I pull in Unity as my container of choice for known dependencies in WinRT apps. At the time of this writing, Unity for WinRT has not yet been released, but it is available in pre-release form as a NuGet package. So I right click on my project in Solution Explorer, select Manage NuGet Packages, make sure “Include Prerelease” is selected at the top of the NuGet dialog, and do a search for Unity.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure1_4.png"><img width="696" height="362" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure1_thumb_1.png" alt="Figure1" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" title="Figure1" /></a></p> <p>After installing that NuGet package, The modifications to App.xaml.cs look like this:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">sealed</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> App : MvvmAppBase</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> IUnityContainer _Container = <span class="kwrd">new</span> UnityContainer();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">public</span> App()</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">this</span>.InitializeComponent();</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnLaunchApplication(LaunchActivatedEventArgs args)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> NavigationService.Navigate(<span class="str">"Main"</span>, <span class="kwrd">null</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnInitialize(IActivatedEventArgs args)</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd">base</span>.OnInitialize(args);</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> _Container.RegisterInstance<INavigationService>(NavigationService);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> ViewModelLocator.SetDefaultViewModelFactory(</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> (viewModelType) => _Container.Resolve(viewModelType));</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> }</pre> <!--CRLF--></div> </div> <p>Notice on line 3 I construct the container and keep it around as a singleton for the life of the application just by declaring it as a member variable on the App class. On lines 14-20 I override the OnInitialize method from the base class, set up a registration in the container for the INavigationService interface, and then change the default factory for the ViewModelLocator to construct all view models through the container. By doing so, the container will automatically try to resolve and pass in any dependencies indicated in the view model constructor.</p> <h3>Step 5: Navigate – To AddSalePage and Beyond!</h3> <p>Now that the view model has access to the navigation service, it can cause navigation to happen when it sees fit. Add the following code to the MainPageViewModel.OnNavCommand method:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnNavCommand(<span class="kwrd">string</span> navCommand)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> _NavService.Navigate(<span class="str">"AddSale"</span>, <span class="kwrd">null</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> }</pre> <!--CRLF--></div> </div> <p>As mentioned in <a target="_blank" href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx">Part 1</a> of this series, navigation is done based on string tokens for the pages, where the “Page” part of the page name is left off by convention. That convention is overridable in the MvvmAppBase.GetPageNameToTypeResolver method. If you have followed along to this point, you should be able to fire up the app at this point, click on the Add Sale tile in the MainPage and land on the AddSalePage (which is empty at this point).</p> <p>Once you have landed on the AddSalePage, it has a Back button in the upper left corner, but it is not hooked up to anything yet. To let the view model be in charge of all navigation logic, the AddSalePageViewModel needs access to the NavigationService as well. If you added a container in Step 4b, then you don’t have to do anything other than declare the dependency on INavigationService as a constructor argument. If you stuck with the container-less approach in Step 4a, then you will need to register another factory method for AddSalePageViewModel to the OnInitialize method:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> ViewModelLocator.Register(<span class="kwrd">typeof</span>(AddSalePageViewModel).ToString(),</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> ()=> <span class="kwrd">new</span> AddSalePageViewModel(NavigationService));</pre> <!--CRLF--></div> </div> <p>To set up the view model to take in the INavigationService and handle GoBack commands, it would look like this:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> AddSalePageViewModel : ViewModel</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> INavigationService _NavService;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">public</span> AddSalePageViewModel(INavigationService navService)</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> _NavService = navService;</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> GoBackCommand = <span class="kwrd">new</span> DelegateCommand(</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> () => _NavService.GoBack(),</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> () => _NavService.CanGoBack());</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd">public</span> DelegateCommand GoBackCommand { get; set; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> }</pre> <!--CRLF--></div> </div> <p>Now a simple modification to the backButton in AddSalePage gets it all lit up and ready to use:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">Button</span> <span class="attr">x:Name</span><span class="kwrd">="backButton"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">Command</span><span class="kwrd">="{Binding GoBackCommand}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource BackButtonStyle}"</span> <span class="kwrd">/></span></pre> <!--CRLF--></div> </div> <h3> </h3> <h3>Step 6: Add navigation from an AppBar</h3> <p>In addition to the GridView navigation on the home page, you might also want to let people navigate to specific pages regardless of where they are in the application. To do that you would include a top AppBar on each page with navigation buttons for the places in your application you want to allow them to navigate to from there. For example, I could add the following to my MainPage:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">Page.Resources</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd"><</span><span class="html">Style</span> <span class="attr">x:Key</span><span class="kwrd">="AddSaleAppBarButtonStyle"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">TargetType</span><span class="kwrd">="ButtonBase"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="attr">BasedOn</span><span class="kwrd">="{StaticResource AppBarButtonStyle}"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd"><</span><span class="html">Setter</span> <span class="attr">Property</span><span class="kwrd">="AutomationProperties.AutomationId"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="attr">Value</span><span class="kwrd">="AddAppBarButton"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd"><</span><span class="html">Setter</span> <span class="attr">Property</span><span class="kwrd">="AutomationProperties.Name"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="attr">Value</span><span class="kwrd">="Add Sale"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd"><</span><span class="html">Setter</span> <span class="attr">Property</span><span class="kwrd">="Content"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="attr">Value</span><span class="kwrd">="&#xE109;"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd"></</span><span class="html">Style</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd"></</span><span class="html">Page.Resources</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd"><</span><span class="html">Page.TopAppBar</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="kwrd"><</span><span class="html">AppBar</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd"><</span><span class="html">StackPanel</span> <span class="attr">Orientation</span><span class="kwrd">="Horizontal"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd"><</span><span class="html">Button</span> <span class="attr">Command</span><span class="kwrd">="{Binding AddSaleCommand}"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource AddSaleAppBarButtonStyle}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="kwrd"></</span><span class="html">StackPanel</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> <span class="kwrd"></</span><span class="html">AppBar</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> <span class="kwrd"></</span><span class="html">Page.TopAppBar</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>Then I would just add an AddSaleCommand to the view model:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> DelegateCommand AddSaleCommand { get; set; }</pre> <!--CRLF--></div> </div> <p>And wire up its handler to use the navigation service to cause the navigation.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> AddSaleCommand = <span class="kwrd">new</span> DelegateCommand(() => _NavService.Navigate(<span class="str">"AddSale"</span>, <span class="kwrd">null</span>));</pre> <!--CRLF--></div> </div> <p>Obviously in a complex app with many pages, this would be a bad idea to repeat across many pages if you wanted to be able to navigate to the AddSalePage from anywhere in the application. To avoid that, what I would do is wrap it up in a user control that I could add to any page’s app bar declaratively in the XAML.</p> <p> </p> <h3>Step 7: Let the ViewModel know when it is navigated to</h3> <p>Sometimes you might need to pass arguments between view models when navigation happens. For example if you were presenting a list of items to select in one view, and the next view you navigated to was going to present that item for editing or other interaction. You can see in the navigation service Navigate method in the first snippet of Step 5 that there is a second parameter that lets you pass some context. In that step I passed null, but that won’t always be sufficient. The way you can receive that parameter in the view model that is being navigated to is to override a method from the ViewModel base class called OnNavigatedTo. Additionally if you need to do some clean up when the user navigates away from a view, there is a corresponding OnNavigatedFrom method as well.</p> <p>If I add an override for OnNavigatedTo to the AddSalePageViewModel, the signature looks like this:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(<span class="kwrd">object</span> navigationParameter, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> NavigationMode navigationMode, Dictionary<<span class="kwrd">string</span>, <span class="kwrd">object</span>> viewState)</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">base</span>.OnNavigatedTo(navigationParameter, navigationMode, viewState);</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> }</pre> <!--CRLF--></div> </div> <p>The parameters to the method include the navigation parameter that can be passed from the view model that caused the navigation, a NavigationMode parameter, and a viewState parameter. The NavigationMode parameter is part of WinRT and tells you whether you arrived at your destination through a “New”, “Forward”, “Back”, or “Refresh” navigation. A call to INavigationService.Navigate results in a “New” navigation – meaning it will be another step in the navigation stack that is maintained by WinRT. INavigationService.GoBack will result in the “Back” value. The other two are exposed by the Frame class in WinRT when you use the GoForward or Refresh navigation methods. We chose not to implement those in the FrameNavigationService class in Prism since they are fairly uncommon to expose in a Windows Store app as explicit navigation controls, but you could easily extend the FrameNavgationService to add those if it made sense for your app, and their implementation would just be to wrap the Frame.GoForward or Frame.Refresh methods.</p> <p>The viewState argument is a dictionary that you can read and write values into that will participate in suspend/terminate state persistence – which will be the subject of my next article in the series, so just ignore that parameter for now.</p> <h3>Summary</h3> <p>In this article, I showed you how you can use the Prism DelegateCommand class to handle communications from the view down into the view model, with the assistance of a behavior to map GridView.ItemClick events into command invocations. You also saw how to wire up dependencies in your view models either through manual dependency injection with a factory method supplied to the ViewModelLocator (Step 4a) or by using an IOC/DI container (Step 4b). You saw how to use the INavigationService to control navigation from the view models, as well as how to let the view models know when they are being navigated to or from.</p> <p>In the next article, I will show how we can manage application state in the face of suspend/terminate/resume – which is an inherent part of WinRT application lifecycle.</p> <h3>About the Author</h3> <p>Brian Noyes is CTO of Solliance (<a href="http://www.solliance.net/">www.solliance.net</a>), a software development company offering Architecture as a Service, end-to-end product development, technology consulting and training. Brian is a Microsoft Regional Director and MVP, <a target="_blank" href="http://www.pluralsight.com/">Pluralsight</a> author, and speaker at conferences worldwide.  Brian worked directly on the Prism team with Microsoft patterns and practices. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at <a href="http://briannoyes.net/">http://briannoyes.net/</a> or on Twitter @briannoyes.</p> http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Commands-Dependencies-and-Navigation.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Commands-Dependencies-and-Navigation.aspx#comments http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Commands-Dependencies-and-Navigation.aspx Mon, 11 Mar 2013 14:11:00 GMT WinRT Business Apps with Prism: Getting Started <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-layout="button_count" data-font="segoe ui" data-href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx" data-send="false" data-show-faces="true"></div> <br /> </td> <td><a class="twitter-share-button" href="https://twitter.com/share" data-url="http://slshow.net/YmjwCc" data-text="Check out @briannoyes article: '#WindowsStore #LOB Apps with Kona: Getting Started'. #win8dev" data-count="horizontal" data-counturl="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx" data-via="silverlightshow">Tweet</a></td> <td><g:plusone href="http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx" size="medium"></g:plusone><br /> </td> <td> </td> </tr> </tbody> </table> <div style="border: 1px solid #dddddd; width: 400px; padding-top: 10px; padding-left: 10px; margin-top: 5px; margin-left: 150px; background-color: #f3f3f3; text-align: center;"><strong><a href="http://www.silverlightshow.net/Storage/Sources/HelloPrismForWinRTPart1.zip">Download the source code for this article</a></strong> <ul></ul> </div> <p><span style="color: #ff0000;">UPDATE: This article was updated from the original version because the name of the guidance changed from “Kona” to “Prism for Windows Runtime” after initial publication. The content has not changed in the update other than the name of the guidance and the namespaces in the code.</span></p> <p>This is Part 1 in the series WinRT Business Apps with Prism.</p> <h3>Introduction</h3> <p>Even if you are an experienced XAML developer, to be successful building business applications for the Windows Runtime (WinRT), you can't just start slinging code in the code behind of pages and let your application evolve into a pile of new spaghetti code. You need to focus on maintainability and testability of your application. You need loose coupling and separation of concerns. But if you get started by looking at the samples and documentation that comes with the platform, you will have a hard time figuring it how to get started with that.</p> <div style="border: 1px solid #dddddd; width: 200px; padding-top: 5px; padding-bottom: 5px; padding-left: 10px; margin-top: 5px; margin-left: 10px; float: right; background-color: #f3f3f3;"> <h3>Don't miss</h3> <ul style="margin: 0px; padding-left: 20px; font-size: 12px; list-style-type: circle;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/news/Free-SilverlightShow-Webinar-Windows-8-background.aspx">Join our webinar on May 9: Working in the background in Win8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx">András Velvárt's Article: Designer-friendly MVVM for XAML Windows Store Apps</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/MVVM-in-Win8-Webinar.aspx">Recording of webinar: MVVM in Windows 8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx">Samidip Basu's Win8 ebook</a>:</li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx"><img style="border-width: 0px; border-style: solid; width: 80px; height: 113px;" alt="Windows 8 Apps - 8 Must-Know Tricks: Ebook" src="http://www.silverlightshow.net/Storage/Ebooks/win8_tricks.png" usemap="#rade_img_map_1291385581316" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>Luckily someone has already blazed a trail for you - Microsoft patterns & practices (p&p). For the last 6 months or so I have had the privilege of working as a member of the p&p team whose charter is to provide guidance for line of business XAML developers starting to build Windows Store applications. This project was originally code named "Kona", but was renamed for release to Prism for Windows Runtime.  I will be referring to the code and samples and documentation that comes with the guidance collectively as "Prism" for short, but just realize I am referring to this new variant of Prism targeting WinRT apps, not Prism 4 which targets WPF and Silverlight apps. For Prism 4 you can check out my other article series <a href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-1-Getting-Started.aspx" target="_blank">Working with Prism 4</a>. </p> <p>In this article series I will be showing you everything that Prism has to offer to help you build your WinRT application right, to leverage the reusable code of Prism, to follow the coding patterns of Prism where no reusable code exists, and to leverage the features of the platform that most business applications will need to integrate with. A lot of these same things can apply whether you are building a game, productivity app, or line of business applications that only employees of your company will use. But the main focus of the guidance is for line of business applications including internal business applications (which will probably be side loaded and never go in the Windows Store, but are still referred to by Microsoft as “Windows Store apps”) as well as business-to-consumer applications where the end users of your application are mostly outside your control as the development organization.</p> <p>You will learn about structuring your application with MVVM, navigation, application state management, loosely coupled communications, validation, calling Web APIs, and leveraging platform features including Settings panels, Search charm integration, Live Tile updates, Toast Notifications, Roaming Settings, and more. I will do this mostly by building out a Windows Store application in the series, but for the things that are a little too involved to build up in a single sample, I will end up pointing to some example code in Prism.</p> <p>This is not a introductory tutorial in building Windows Store applications. I am assuming you have already had some exposure to the WinRT platform, Windows Store applications, and have some experience building XAML applications. I also expect you have some exposure to the MVVM pattern, its goals and structure. If you want a good comprehensive overview of all of these, check out my <a href="http://pluralsight.com/training/courses/TableOfContents?courseName=win8mvvm" target="_blank">Pluralsight course “Building Windows 8 MVVM XAML Apps”</a>. I also will have a Pluralsight course titled Building Windows Store Business Apps with Prism out by June 2013.</p> <h3>Prism Guidance Overview</h3> <p>A big part of the Prism guidance is a realistic sample application, the AdventureWorks Shopper application. This is referred to as a "Reference Implementation" (RI) by p&p. It is more than your average sample application, it is a complete end to end application that represents the kind of applications many businesses will need to build for WinRT, whether they deploy through the Windows Store to consumers or whether they deploy through side loading in the Enterprise. In building the AdventureWorks Shopper RI, the p&p team constantly looked for opportunities to write code in a reusable way so that developers could not only learn from the code of the application , they could also use some of the common code we were writing. The result of that is a library called Microsoft.Practices.Prism.StoreApps that is part of the Prism download that you can reuse in your own applications. There is also a separate reusable library called Microsoft.Practices.Prism.PubSubEvents that I will cover in a later article in the series. The RI also includes extensive unit and integration tests that you can use to learn how to write tests for your own application. Additionally, Prism comes with several Quickstart applications that demonstrate distinct features or capabilities of Prism in isolation, including a Hello World, Validation, PubSubEvents, and Search. Finally, there is fairly comprehensive documentation of the RI and Quickstarts that can walk you through that code.</p> <p>There is a conceptual tie between Prism for Windows Runtime and <a href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-1-Getting-Started.aspx" target="_blank">Prism 4</a>. Prism 4 was a previous set of guidance from Microsoft p&p focused on building loosely coupled, maintainable, and extensible desktop client applications with WPF and Silverlight. Some of the same concepts and even a tiny bit of the code was carried over where appropriate, but from the outset the goal of Prism was not to just port Prism 4 to WinRT, it was to build a good set of guidance for WinRT XAML applications without presuming that you should build WinRT applications in any way similar to WPF or Silverlight.</p> <p>One thing that was definitely carried over in concept was the presumption that we would be focused on writing maintainable code. That meant we wanted to make sure that the core logic of our application would be unit testable and well factored. We wanted the code that supported one view to be decoupled from the code that supported another view. That of course led us quickly to plan on using the Model-View-ViewModel (MVVM) pattern that is common in WPF and Silverlight and that was also used in Prism 4. But we also quickly found that the WinRT platform is substantially different in the way you go about doing MVVM and we had to come up with a number of new things that our view models were responsible for - including integrating nicely with the WinRT navigation system and with the application lifecycle and state management of the platform.</p> <p>So this series of articles will help you explore the concepts covered in Prism by demonstrating them in code.</p> <p>At the time of writing this article, the Prism team is in the process of getting Prism for Windows Runtime ready for release. However, the current source code for Prism is available as open source and can already be downloaded from <a href="http://konaguidance.codeplex.com/">http://konaguidance.codeplex.com</a>. </p> <h3>Getting Started</h3> <p>I have to start somewhere, so the most logical place to start is the same place you will – with a blank slate. In this article I will show you how to quickly put together a new application based on the Prism reusable class library (Microsoft.Practices.Prism.StoreApps). The code I write in this article will be the stuff you will end up doing in probably every Windows Store application you choose to build leveraging Prism – specifically it will lay down the patterns that enable you to use the MVVM pattern, manage your dependencies, integrate with the navigation system, and manage your application state through your view models and application services. I won’t go into detail in this article on the navigation and state management – those are both big enough topics that I will get into those in the next couple articles in the series. This one will just get you bootstrapped on using Prism.</p> <p>The scenario for the application I will be building up over the series is for a line of business worker whose job it is to take sales order calls and enter the sales. They may also need to look up past sale information, product information, and enter and modify customer information as part of their normal job task.</p> <h3>Step 1: Create a Windows Store Application</h3> <p>The first step is to open Visual Studio 2012  and create a new Windows Store Application. Select the Blank application template, and name the project HelloPrismForWinRT.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/_Figure1_4.png"><img width="628" height="384" title="Figure1" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" alt="Figure1" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/_Figure1_thumb_1.png" /></a></p> <p>After the project is created, you have a single page in the application named MainPage with no content to it.</p> <h3>Step 2: Create a couple Pages and ViewModels</h3> <p>In a Windows Store application, you design your application around Pages. The user navigates from Page to Page to get to all the functionality in your application. Your Pages are your top level Views from an MVVM sense, and you will set up ViewModels to support them. You might have views that are children of the pages – for example you could have a ContentControl within a page that you swap different child views into as the content. But this kind of composition is much less common than it was in WPF and Silverlight because of the Modern UI style guidelines – you should be keeping things a lot less dense than traditional line of business applications have tended to in the past, and spread the functionality of the application over multiple pages that the user navigates between instead of doing everything in one big complicated view.</p> <p>Prism uses convention over configuration for a number of things. There is a ViewModelLocator class that makes it really easy to get views (Pages primarily) wired up to their ViewModels following the conventions of MVVW. This ViewModelLocator has a default convention that assumes you will put your Pages in a subfolder of the project named Views, and your ViewModels in a subfolder named – you guessed it – ViewModels. If you don’t like that convention, there are hooks to put them wherever you want.  But a lot of the reusable code of Prism is designed around doing things based on common patterns, and if you follow those patterns you have less work to do in getting your application up and running.</p> <p>So to start structuring things this way, delete the MainPage.xaml that was added to the root of the project by the template. Add two project folders: Views and ViewModels. Next, right click on the Views folder and select Add > New Item from the context menu. In the Windows Store category, select the “Basic Page” item template and name the first one “MainPage”.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/_Figure2_4.png"><img width="665" height="376" title="Figure2" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" alt="Figure2" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/_Figure2_thumb_1.png" /></a></p> <p>When you click Add, you will be prompted to add some common files to your project that Visual Studio wants to add for every Windows Store application. Go ahead and click Yes, even though in the end we won’t use most of those classes – there are Prism equivalents that fit better with the MVVM pattern that we will use instead.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure3_4.png"><img width="465" height="221" title="Figure3" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" alt="Figure3" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure3_thumb_1.png" /></a></p> <p>Go into the XAML of MainPage and change “My Application” to “Hello Prism” in the resources section.</p> <p>Repeat Add > New Item to add a second Basic Page named AddSalePage to the Views folder. </p> <p>Now you can see we have some duplicate resources in the different pages declaring the application name.  I moved those up into the App.xaml resources dictionary and removed them from each of the pages to eliminate the duplication.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd"><</span><span class="html">Application.Resources</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd"><</span><span class="html">ResourceDictionary</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd"><</span><span class="html">ResourceDictionary.MergedDictionaries</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd"><</span><span class="html">ResourceDictionary</span> <span class="attr">Source</span><span class="kwrd">="Common/StandardStyles.xaml"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum5"> 5:</span> <span class="kwrd"></</span><span class="html">ResourceDictionary.MergedDictionaries</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> <span class="kwrd"><</span><span class="html">x:String</span> <span class="attr">x:Key</span><span class="kwrd">="AppName"</span><span class="kwrd">></span>Hello Prism<span class="kwrd"></</span><span class="html">x:String</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum7"> 7:</span>  </pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> <span class="kwrd"></</span><span class="html">ResourceDictionary</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum9"> 9:</span> <span class="kwrd"></</span><span class="html">Application.Resources</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>Next add two classes to the ViewModels folder: MainPageViewModel and AddSalePageViewModel. At this point, your project should look like this in Solution Explorer:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure4_4.png"><img width="316" height="422" title="Figure4" style="display: inline; background-image: none; border-width: 0px; border-style: solid;" alt="Figure4" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure4_thumb_1.png" /></a></p> <h3>Step 3: Add Microsoft.Practices.Prism.StoreApps to your solution</h3> <p>Now it is time to get Prism involved. If you haven’t already, go download the Prism bits from <a href="http://konaguidance.codeplex.com/">http://konaguidance.codeplex.com</a>. It is a self extracting executable that will unpack all the samples and code to a local folder. I extracted mine to the same root solution folder that was created when I created the project so that the references can remain local and I can just zip things up for the samples. </p> <p>Once you have done that, go ahead and add the Microsoft.Practices.Prism.StoreApps project to your solution – right click on the solution root node in Solution Explorer, select Add > Existing Project, and navigate to the Microsoft.Practices.Prism.StoreApps project in the extracted code from Prism. This is a Windows Store Class Library project that contains all the classes that were designed for direct reuse in Prism. I will be using base classes for our application, views, and view models from it.</p> <p>Once you have added the project to your solution, add a reference to Microsoft.Practices.Prism.StoreApps to your HelloPrismForWinRT application.</p> <h3>Step 4: Replace the App base class with MvvmAppBase</h3> <p>The App.xaml.cs code behind of your App.xaml file in the project contains the definition for the App class – which derives from the WinRT Application class by default. It also has a bunch of code in there for managing the lifetime of the application, creating the first view, handling suspension and some other stuff. All of this has been encapsulated into the MvvmAppBase base class with some overridable methods for the hooks that you may need to customize on an application by application basis.</p> <p>So strip out all the code in the App class except the constructor that calls InitializeComponent, and change the base class to inherit from MvvmAppBase. You will also need to override OnLaunchApplication and navigate to the main page using the NavigationService that is exposed from the base class. Note that there is also an OnLaunched base class method that you should not override.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">using</span> System;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">using</span> System.Collections.Generic;</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">using</span> System.Linq;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">using</span> Microsoft.Practices.Prism.StoreApps;</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum5"> 5:</span> <span class="kwrd">using</span> Windows.ApplicationModel.Activation;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> 6:</span>  </pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum7"> 7:</span> <span class="kwrd">namespace</span> HelloPrismForWinRT</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> {</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum9"> 9:</span> <span class="kwrd">sealed</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> App : MvvmAppBase</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> {</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum11"> 11:</span> <span class="kwrd">public</span> App()</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum12"> 12:</span> {</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum13"> 13:</span> <span class="kwrd">this</span>.InitializeComponent();</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum14"> 14:</span> }</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum15"> 15:</span>  </pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum16"> 16:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnLaunchApplication(LaunchActivatedEventArgs args)</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum17"> 17:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum18"> 18:</span> NavigationService.Navigate(<span class="str">"Main"</span>, <span class="kwrd">null</span>);</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum19"> 19:</span> }</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum20"> 20:</span> }</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum21"> 21:</span> }</pre> <!--CRLF--></div> </div> <p>Note that I am overriding the OnLaunchApplication method in the App class. This is an abstract method in the base class and the minimum thing you need to do in this override is what I am showing here: you need to navigate to the right initial view for your application. For a “cold start” of your application, that means navigating to whatever the “main” page of your application is. But keep in mind that your Windows Store application can be launched in a number of ways, including being launched as a target for a Search charm operation, a secondary tile on the Start screen, or even an application protocol mapping launch. In these cases you might need to navigate somewhere different based on the launch arguments that come into this method. To make that more clear, MvvmAppBase has other overrides for handling search or settings activations. But for now just going to the MainPage from the OnLaunchApplication override is good enough. </p> <p>Note that we navigate to “Main”, not MainPage as a type. This was a design decision we made in Prism that navigation requests like this should not be coupled to the specific type of the view or page. Keep in mind that if you are really planning your application appropriately, you will first storyboard or wireframe out what the pages are in your application and what the navigation between them is. You will probably define logical names for the views even though you probably won’t have decided on specific type names for the views at that point, even though they will most likely start with type names that are those view names + Page. Nor should you couple code that (as you will see in a future article) will often live in a decoupled view model to a specific view type. So the convention used for navigation in Prism by default is that you navigate to a  logical view name, and it assumes that the type name is that logical view name + Page. </p> <p>If this is not your convention, you can override a method on the MvvmAppBase class named GetPageNameToTypeResolver. This method returns a Func<string,Type>, so you are expected to return a delegate that points to a method that takes in a logical view name and returns a type. So for example if you wanted to adopt a convention where you would navigate to views based on their view type name, and they would live in the application root namespace + “.Views”, you would define a GetPageNameToTypeResolver that looks like this:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">override</span> Func<<span class="kwrd">string</span>, Type> GetPageNameToTypeResolver()</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">return</span> (viewName) =></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> {</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum5"> 5:</span> var rootNamespace = <span class="kwrd">this</span>.GetType().Namespace;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> var viewNamespace = rootNamespace + <span class="str">".Views"</span>;</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum7"> 7:</span> <span class="kwrd">return</span> Type.GetType(String.Format(<span class="str">"{0}.{1}"</span>, viewNamespace, viewName));</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> };</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum9"> 9:</span> }</pre> <!--CRLF--></div> </div> <p> </p> <p>But I won’t do that in the sample application, I’m going to stick to the Prism conventions that the page token is simply the Page type name with Page left off.</p> <p>Next open the App.xaml file and replace the root element opening and closing XML elements with ones that use the MvvmAppBase base class, as well as adding a XAML namespace for Microsoft.Practices.Prism.StoreApps:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd"><</span><span class="html">prism:MvvmAppBase</span> <span class="attr">x:Class</span><span class="kwrd">="HelloPrismForWinRT.App"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="attr">xmlns</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="attr">xmlns:x</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="attr">xmlns:prism</span><span class="kwrd">="using:Microsoft.Practices.Prism.StoreApps"</span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum5"> 5:</span> <span class="attr">xmlns:local</span><span class="kwrd">="using:HelloPrismForWinRT"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> 6:</span>  </pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum7"> 7:</span> <span class="kwrd"><</span><span class="html">Application.Resources</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> <span class="kwrd"><</span><span class="html">ResourceDictionary</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum9"> 9:</span> <span class="kwrd"><</span><span class="html">ResourceDictionary.MergedDictionaries</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> <span class="kwrd"><</span><span class="html">ResourceDictionary</span> <span class="attr">Source</span><span class="kwrd">="Common/StandardStyles.xaml"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum11"> 11:</span> <span class="kwrd"></</span><span class="html">ResourceDictionary.MergedDictionaries</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum12"> 12:</span> <span class="kwrd"><</span><span class="html">x:String</span> <span class="attr">x:Key</span><span class="kwrd">="AppName"</span><span class="kwrd">></span>Hello Prism<span class="kwrd"></</span><span class="html">x:String</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum13"> 13:</span>  </pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum14"> 14:</span> <span class="kwrd"></</span><span class="html">ResourceDictionary</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum15"> 15:</span> <span class="kwrd"></</span><span class="html">Application.Resources</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum16"> 16:</span> <span class="kwrd"></</span><span class="html">prism:MvvmAppBase</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>At this point you should be able to launch the app and land on a totally underwhelming main page that says Hello Prism.</p> <h3>Step 5: Change the Page base class to ViewStateAwarePage</h3> <p>Prism has a base Page class that is similar to the LayoutAwarePage that Visual Studio injects, but it is just about layout and not state management and navigation. In an MVVM application, you really want the navigation and state management code to live in the ViewModel, so the Prism ViewModel base class takes care of those responsibilities, which we will hook up in the next step.</p> <p>For the Pages, replace LayoutAwarePage as the base class in both the XAML and the code behind, with the addition of a corresponding XAML namespace like we did in the App.xaml:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd"><</span><span class="html">prism:VisualStateAwarePage</span> <span class="attr">x:Name</span><span class="kwrd">="pageRoot"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> ...</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="attr">xmlns:prism</span><span class="kwrd">="using:Microsoft.Practices.Prism.StoreApps"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> ...</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum5"> 5:</span> <span class="kwrd"></</span><span class="html">prism:VisualStateAwarePage</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>You can also strip out all the other code in the code behind of the Pages other than the constructor with the InitializeComponent call:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">using</span> System;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">using</span> System.Collections.Generic;</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">using</span> System.Linq;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">using</span> Microsoft.Practices.Prism.StoreApps;</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum5"> 5:</span>  </pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> <span class="kwrd">namespace</span> HelloPrismForWinRT.Views</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum7"> 7:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> <span class="kwrd">public</span> <span class="kwrd">sealed</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> MainPage : VisualStateAwarePage</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum9"> 9:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> <span class="kwrd">public</span> MainPage()</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum11"> 11:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum12"> 12:</span> <span class="kwrd">this</span>.InitializeComponent();</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum13"> 13:</span> }</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum14"> 14:</span> }</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum15"> 15:</span> }</pre> <!--CRLF--></div> </div> <p>Make sure to make this same change for both MainPage and AddSalePage, and for each Page you add to the app after that.</p> <p>Any reader with experience in MVVM should already be giving a little sigh of relief – yes, you can stick to almost zero code in the code behind, even in the Windows Store world.</p> <p>You’ll need to get rid of one thing that is in the Basic Page template by default – it has a button wired up in the header for the GoBack navigation action, and it expects to find a Button.Click handler named GoBack in the code behind of the view. So in both the MainPage.xaml and AddSalePage.xaml, locate this code and remove the Click handler. Change this:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd"><</span><span class="html">Button</span> <span class="attr">x:Name</span><span class="kwrd">="backButton"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="attr">Click</span><span class="kwrd">="GoBack"</span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="attr">IsEnabled</span><span class="kwrd">="{Binding Frame.CanGoBack, ElementName=pageRoot}"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource BackButtonStyle}"</span> <span class="kwrd">/></span></pre> <!--CRLF--></div> </div> <p>to this:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd"><</span><span class="html">Button</span> <span class="attr">x:Name</span><span class="kwrd">="backButton"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="attr">Style</span><span class="kwrd">="{StaticResource BackButtonStyle}"</span> <span class="kwrd">/></span></pre> <!--CRLF--></div> </div> <p> </p> <h3>Step 6: Add the ViewModel base class to the ViewModels</h3> <p>Add a base class to the view models of ViewModel from the Microsoft.Practices.Prism.StoreApps namespace:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">using</span> System;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">using</span> System.Collections.Generic;</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">using</span> System.Linq;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">using</span> Microsoft.Practices.Prism.StoreApps;</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum5"> 5:</span>  </pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> <span class="kwrd">namespace</span> HelloPrismForWinRT.ViewModels</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum7"> 7:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> MainPageViewModel : ViewModel</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum9"> 9:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> }</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum11"> 11:</span> }</pre> <!--CRLF--></div> </div> <p>We won’t actually be doing anything in this article where it makes any difference what the view model base class is, but we will in future articles in the series, and in general when you are building out a Prism-based MVVM application, you will want to inherit from ViewModel for the Page view models so that you can integrate with the navigation and application lifecycle state management that I will cover in the next couple articles.</p> <h3>Step 7: Add the ViewModelLocator to the views to hook up their view models</h3> <p>Prism defines a reusable ViewModelLocator that can be used to hook up views and view models. It can do this automatically based on conventions, you can provide it factory methods that map a given view type to a given view model type, or you can override the default conventions of the ViewModelLocator to use your own conventions. </p> <p>The default conventions of the ViewModelLocator are that for a given View type, it will assume the view is defined in a “.Views” child namespace off the project root or a sub-namespace, and the view model type has the same type name of the View plus “ViewModel” on the end of it and lives in a sibling “.ViewModels” namespace to the view. And this is precisely the folder and namespace structure I had you set up by adding the Views and ViewModels project folders in Step 2.</p> <p>The way you use the ViewModelLocator from Prism is through an attached property on the view root element. So add the view model locator to the MainPage and AddSalePage root elements like so:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd"><</span><span class="html">prism:VisualStateAwarePage</span> ...</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="attr">xmlns:prism</span><span class="kwrd">="using:Microsoft.Practices.Prism.StoreApps"</span></pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> 3:</span> <span class="attr">prism:ViewModelLocator</span>.<span class="attr">AutoWireViewModel</span><span class="kwrd">="True"</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>The ViewModelLocator will take care of creating an instance of the view model type for this view instance, and will also set the view model as the DataContext for the view, which is standard MVVM structuring.</p> <p>After you have added this to MainPage.xaml, you could add a default constructor to MainPageViewModel and you should see that the constructor gets called as the app starts and navigates to the MainPage.</p> <p>So at this point you should be able to fire up the application, and you have MVVM structuring and you could start fleshing out your views and view models to do some more meaningful work. To do much more, we need to get into navigation a little deeper, as well as managing dependencies. For example, the next logical step is to add a button to the MainPage that will let us navigate to the AddSalePage. But to do that in an MVVM way, we should fire a command from the button into the MainPageViewModel and control the navigation from there. That requires commands, some sort of Navigation service, and dependency injection of that service into the view model. It’s all there in the Prism code, and I’ll cover it in the next article. But that is all I have room for in this installment. For those that can’t wait for the next article, you could go check out the HelloWorld Quickstart in the Prism bits. It covers some of the same stuff I will get into in the next article that lets you get to the point of controlling navigation in your view models.</p> <p>You can download the completed code <a href="https://dl.dropbox.com/u/7366831/downloads/Articles/SilverlightShow/AlohaKonaPart1.zip" target="_blank">for this article here</a>.</p> <h3>Summary</h3> <p>In this article I introduced you to the concepts behind the Prism guidance from Microsoft patterns & practices. I showed you how to create a simple application based on Prism, using the Prism MvvmAppBase class, VisualStateAwarePage, and ViewModel base classes. I also used the ViewModelLocator to get the views and view models hooked up to one another.</p> <p>Next time I’ll show you how you can use factories to construct the ViewModels so that you can inject dependencies into them manually, or how to instead use a container such as Unity to do Inversion of Control and Dependency Injection through a container to resolve dependencies when your view model gets constructed. You’ll see how to use Prism’s DelegateCommand, which is a ported version of the Prism 4 DelegateCommand it was based on, and you’ll also see how to have the view model know when it is navigated to, as well as how to control navigation.</p> <h3>About the Author</h3> <p>Brian Noyes is CTO of Solliance (<a href="http://www.solliance.net/">www.solliance.net</a>), a software development company offering Architecture as a Service, end-to-end product development, technology consulting and training. Brian is a Microsoft Regional Director and MVP, <a href="http://www.pluralsight.com/" target="_blank">Pluralsight</a> author, and speaker at conferences worldwide.  Brian worked directly on the Prism team with Microsoft patterns and practices. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at <a href="http://briannoyes.net/">http://briannoyes.net/</a> or on Twitter @briannoyes.</p> http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx#comments http://www.silverlightshow.net/items/Windows-Store-LOB-Apps-with-Kona-Getting-Started.aspx Wed, 20 Feb 2013 13:42:00 GMT Designer-friendly MVVM for XAML Windows Store applications <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx" data-font="segoe ui" data-layout="button_count"></div> </td> <td><a href="https://twitter.com/share" class="twitter-share-button" data-via="silverlightshow" data-counturl="http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx" data-count="horizontal" data-text="Check @vbandi's article: Designer-friendly #MVVM for #XAML #WindowsStore apps! #win8dev" data-url="http://slshow.net/UDWOe4">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <h1>Introduction</h1> <p>It was almost three years ago that I published my company’s preferred <a href="http://www.silverlightshow.net/items/A-Designer-friendly-Approach-to-MVVM-Part-I.aspx">approach to MVVM with Silverlight</a>. Time sure flies, and now I can say that the basic ideas and general way of thinking outlined in that article stood the test of time – we created dozens of applications that used that approach, many of them ended being in the top 5 apps in the Windows Phone Store in their own categories. </p> <div style="border: 1px solid #dddddd; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>Don't miss</h3> <ul style="list-style-type: circle; margin: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/news/Free-SilverlightShow-Webinar-Applied-MVVM-in-Windows-8-apps.aspx">Join our webinar on Feb 26: Applied MVVM in Win8 Apps</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/MVVM-in-Win8-Webinar.aspx">Recording of webinar: MVVM in Windows 8</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx">Samidip Basu's Win8 ebook</a>:</li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/win8_8tricks.aspx"><img style="width: 80px; height: 113px; border-width: 0px; border-style: solid;" alt="Windows 8 Apps - 8 Must-Know Tricks: Ebook" src="http://www.silverlightshow.net/Storage/Ebooks/win8_tricks.png" usemap="#rade_img_map_1291385581316" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>And then, WinRT happened. WinRT (or Windows 8 Store application) development does not support Behaviors, Actions or Triggers, which were the foundation of the two key pieces of our MVVM puzzle: CallDataContextMethodAction and VSMChangerBehavior. We found that we had to write a lot of repetitive code in the codebehind, and often could not avoid littering it with some business logic that belonged in the ViewModel instead. </p> <p><em>Note: I am not an MVVM purist – I think that using code behind is fine when it comes to manipulating the UI itself, and not the data that drives the UI. However, a lot of this functionality could be abstracted and reused with Behaviors – e.g. you could write a behavior that selected the content of an entire TextBox when it got focus, making it easier to replace the text within. Sadly, this is not really an option with WinRT without proper tool support.</em></p> <p>After gaining enough experience with WinRT development, I set out to port over our proven approach to WinRT. A lot had to be changed since we could not take advantage of Behaviors, but the basics remained the same. This article introduces the WinRT version of the Designer-friendly MVVM Helpers library. </p> <h2>A Word about MVVM</h2> <p>Discussing what MVVM is and why it’s useful is waaaay beyond the scope of this article. I am assuming that You already know what it is, at least on a conceptual level. If not, please read <a href="http://www.silverlightshow.net/items/A-Designer-friendly-Approach-to-MVVM-Part-I.aspx">the original Silverlight version of this article</a>, which discusses the most important things about MVVM, and also gives you pointers for further reading.</p> <h1>Goals of the Designer-friendly MVVM Helpers</h1> <p>The goals are mostly the same as they were in the Silverlight / Windows Phone version. </p> <p>For the project itself:</p> <ul> <li>Total separation of the designer and developer workflows </li> <li>Shallow learning curve for both the designer and the developer </li> <li>Allowing both the designer and the developer to remain in their comfort zone, and only use the tools they are familiar with </li> <li>Approachable solution for projects with low or medium complexity </li> </ul> <p>For the designer: </p> <ul> <li>As much Blend support as possible (this is not totally achieved yet due to limitations in Blend and lack of Behaviors) </li> <li>Use of Visual States to reflect different states of the application </li> <li>High level of flexibility </li> <li>Almost everything can be done in XAML </li> <li>Create a modern UI, including animations, transitions, custom skins, etc. </li> </ul> <p>For the developer:</p> <ul> <li>Focus only on coding </li> <li>Display logic (ViewModel) code is unit testable, including user actions </li> <li>Application states can be expressed naturally, via enum values </li> <li>Ability to include techniques from other MVVM approaches, such as the <a href="http://www.galasoft.ch/mvvm/getstarted/">MVVM Light Toolkit</a></li> </ul> <h1>Using the Designer-friendly MVVM Helpers</h1> <p>When discussing the relationship between a ViewModel and a View, XAML technologies use two key concepts:</p> <ul> <li>Data binding – to get data from the VM to the View and vice versa </li> <li>Commanding – to notify the VM of the user’s actions, such as the pressing of a button</li> </ul> <p>Our library extends data binding by creating a bi-directional link between a View’s Visual States and an Enum in the ViewModel, and also provides a way for the View to call ViewModel methods upon user interactions. This covers 90% of the use cases for a typical, well architected MVVM app. For the rest, we are still relying on code behind, and desperately wait for the arrival of Behaviors in an upcoming WinRT / Blend release.</p> <p>First, let’s see how the VM can be notified of user interactions.</p> <h2>The CallVMMethod Attached Property</h2> <p>For the <a href="http://www.silverlightshow.net/items/A-Designer-friendly-Approach-to-MVVM-Part-I.aspx">Silverlight / Windows Phone version</a>, this used to be the CallDataContextMethodAction. With Triggers, you had a very flexible way of specifying when the VM method should be called. While a similar approach could be used for WinRT using third party Behavior libraries, due to the lack of Blend support, these result in a ton of XAML code you had to write, making the solution designer-unfriendly. I looked at our usage of this pattern in our projects, and found that 98% of the time, we are just using a simple EventTrigger to trigger the CallDataContextMethodAction. So, for Windows 8, I focused on this use case, and I went for the most fluid experience I could achieve (leaving the other 2% to codebehind solutions). </p> <h3>Basic Example</h3> <p>Our first example simply shows the content of a TextBox in a dialog. Showing a MessageDialog from a ViewModel is not a good practice (beats testability and also separation of concerns), but I am using it as an example here to illustrate that the VM did receive a message. </p> <p>The entire Page has a DataContext (MainVM), defined as follows:</p> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd"><</span><span class="html">Page.DataContext</span><span class="kwrd">></span> </pre> <pre><span class="lnum"> 2: </span> <span class="kwrd"><</span><span class="html">df:MainVM</span><span class="kwrd">></</span><span class="html">df:MainVM</span><span class="kwrd">></span></pre> <pre class="alt"><span class="lnum"> 3: </span><span class="kwrd"></</span><span class="html">Page.DataContext</span><span class="kwrd">></span></pre> </div> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <pre></pre> <p>Here is the relevant code snippet from the ViewModel: </p> <pre> </pre> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">public</span> <span class="kwrd">string</span> Message { get; set; }</pre> <pre><span class="lnum"> 2: </span> </pre> <pre class="alt"><span class="lnum"> 3: </span><span class="kwrd">public</span> <span class="kwrd">void</span> ShowMessage()</pre> <pre><span class="lnum"> 4: </span>{</pre> <pre class="alt"><span class="lnum"> 5: </span> <span class="kwrd">string</span> msg = Message ?? <span class="str">"Enter something in the textbox"</span>;</pre> <pre><span class="lnum"> 6: </span> MessageDialog dialog = <span class="kwrd">new</span> MessageDialog(msg, <span class="str">"Dialog from ViewModel"</span>);</pre> <pre class="alt"><span class="lnum"> 7: </span> dialog.ShowAsync();</pre> <pre><span class="lnum"> 8: </span>}</pre> </div> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>The UI for this sample looks like this:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/andrasvelvart/_image_2.png"><img width="321" height="72" title="image" style="display: inline; border-width: 0px; border-style: solid;" alt="image" src="http://www.silverlightshow.net/Storage/Users/andrasvelvart/_image_thumb.png" /></a> </p> <p>And the XAML is:</p> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Text</span><span class="kwrd">="{Binding Message, Mode=TwoWay}"</span><span class="kwrd">/></span></pre> <pre><span class="lnum"> 2: </span><span class="kwrd"><</span><span class="html">Button</span> <span class="attr">Content</span><span class="kwrd">="Message!"</span> <span class="attr">df:CallVMMethod</span>.<span class="attr">Click</span><span class="kwrd">="ShowMessage"</span><span class="kwrd">/></span></pre> </div> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <pre></pre> <p>The ViewModel learns about the content of the TextBox with a simple binding –0 no surprises here. The more interesting part is the second line, where the new attached property is used to call the ShowMessage method of the ViewModel (or technically, the DataContext of the Button), when the Button’s Click event is fired.</p> <p>When you are typing the above line, Intellisense helps you as much as possible. Here is what it looks like: </p> <p><a href="http://www.silverlightshow.net/Storage/Users/andrasvelvart/image_4.png"><img width="622" height="259" title="image" style="display: inline; border-width: 0px; border-style: solid;" alt="image" src="http://www.silverlightshow.net/Storage/Users/andrasvelvart/image_thumb_1.png" /></a> </p> <p>As you can see, the most used event handlers are available – and if the one you are looking for is not, you can easily add a new one. </p> <h3>Using from an ItemTemplate</h3> <p>This is all nice, but often you want to call a VM method from a list. E.g. the VM should know when you selected an item, or clicked the “Delete” button next to an item. </p> <p>Suppose we have a list of strings, and want the user to choose one of those. Here is the VM (again, simplified to focus on the main point of the article):</p> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">public</span> MainVM()</pre> <pre><span class="lnum"> 2: </span>{</pre> <pre class="alt"><span class="lnum"> 3: </span> SomeStrings = <span class="kwrd">new</span> ObservableCollection<<span class="kwrd">string</span>>();</pre> <pre><span class="lnum"> 4: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i < 10; i++)</pre> <pre class="alt"><span class="lnum"> 5: </span> SomeStrings.Add(Guid.NewGuid().ToString());</pre> <pre><span class="lnum"> 6: </span>}</pre> <pre class="alt"><span class="lnum"> 7: </span> </pre> <pre><span class="lnum"> 8: </span><span class="kwrd">public</span> ObservableCollection<String> SomeStrings { get; <span class="kwrd">private</span> set; }</pre> </div> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>We have a ListView in the View to display these strings. Pretty straightforward so far:</p> <pre class="csharpcode"><span class="kwrd"><</span><span class="html">ListView</span> <span class="attr">ItemsSource</span><span class="kwrd">="{Binding SomeStrings}"</span> <span class="attr">ItemTemplate</span><span class="kwrd">="{StaticResource DataTemplate1}"</span><span class="kwrd">/></span></pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>You could bind the SelectedItem to a property in the VM and handle selection in the property setter, but the setter does not get called if you click on the item already selected. Instead, you could do something like this in the ItemTemplate:</p> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd"><</span><span class="html">DataTemplate</span> <span class="attr">x:Key</span><span class="kwrd">="DataTemplate1"</span><span class="kwrd">></span> </pre> <pre><span class="lnum"> 2: </span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">TextWrapping</span><span class="kwrd">="Wrap"</span> <span class="attr">Text</span><span class="kwrd">="{Binding}"</span> <span class="attr">df:CallVMMethod</span>.<span class="attr">Tapped</span><span class="kwrd">="StringSelected"</span><span class="kwrd">/></span></pre> <pre class="alt"><span class="lnum"> 3: </span><span class="kwrd"></</span><span class="html">DataTemplate</span><span class="kwrd">></span></pre> </div> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <pre></pre> <p>This would call the StringSelected method of the DataContext, except… the DataContext of the DataTemplate in this case is just a String, which does not have such a method. What happens in this case, is that the CallVMMethod <strong>starts to traverse the Visual Tree</strong>. If the DataContext of the TextBlock does not have a StringSelected method, maybe its parent does. Or maybe the parent of that… and so on, and so on, until the method with the right signature is found (see below), or the top of the Visual Tree is reached (in which case you get an ArgumentException).</p> <p>This way, as we go up, we reach the parent ListBox, the DataContext of which does have the StringSelected method defined in the MainVM class:</p> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">public</span> <span class="kwrd">void</span> StringSelected(<span class="kwrd">string</span> dataContext)</pre> <pre><span class="lnum"> 2: </span>{</pre> <pre class="alt"><span class="lnum"> 3: </span> MessageDialog msgd = <span class="kwrd">new</span> MessageDialog(<span class="str">"Selected: "</span> + dataContext);</pre> <pre><span class="lnum"> 4: </span> msgd.ShowAsync();</pre> <pre class="alt"><span class="lnum"> 5: </span>}</pre> </div> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <pre></pre> <p> This StringSelected method excepts a single parameter, with the type of String. This is important – since we have traversed up the Visual Tree until the point where the original DataContext of the tapped TextBlock is no longer visible, we have to have a way for the StringSelected method to know which string was tapped on. This technique can also be used to pass a business object, such as a Person or Company to the VM.</p> <h3>Method signatures</h3> <p>As you saw above, there are several ways you can define the methods in the ViewModel to be called by CallVMMethod. Here is a reference table of all the supported signatures:</p> <p><strong>MethodName()</strong><br /> No parameters, no data passed to the method</p> <p><strong>MethodName(T dataContext)</strong><br /> If the DataContext of the source FrameworkElement mathes the type T (or can be assigned to a variable of type T), this method is a match. The value passed is the DataContext of the source FrameworkElement</p> <p><strong>MethodName(T dataContext, Targs args)</strong><br /> It is rare, but sometimes you may want to pass the original event’s arguments to the ViewModel. If so, this signature is understood by CallVMMethod and invoked.</p> <p>The CallVMMethod will look for all these methods in the DataContext of the source FrameworkElement and its parents’ DataContext until it finds a suitable method or reaches the top of the tree.</p> <h3>Adding more events</h3> <p>You may find that the events implemented by CallVMMethod does not include the event you want to use. Luckily, it is easy to expand the list of events: open the CallMVVMMethodHandledEvents.tt file (which is a <a href="http://msdn.microsoft.com/en-us/library/bb126445.aspx">T4 template</a>), and add your event to the others by listing the event name, event handler type and event argument type. For example, this is what the first few events look like in the template:</p> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">string</span>[] handledEvents = <span class="kwrd">new</span> <span class="kwrd">string</span>[] {</pre> <pre><span class="lnum"> 2: </span> </pre> <pre class="alt"><span class="lnum"> 3: </span><span class="str">"Click,RoutedEventHandler,RoutedEventArgs"</span>,</pre> <pre><span class="lnum"> 4: </span><span class="str">"DoubleTapped,DoubleTappedEventHandler,DoubleTappedRoutedEventArgs"</span>,</pre> <pre class="alt"><span class="lnum"> 5: </span><span class="str">"DragEnter,DragEventHandler,DragEventArgs"</span>,</pre> </div> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>The T4 code generator will take care of the rest.</p> <h2>The EnumToVisualState Control</h2> <p>The other piece of the designer-friendly MVVM puzzle was the VSMChangerBehavior, which <strong>mapped ViewModel enums to Visual States in the View</strong>. Again, due to the lack of Behavior support in WinRT, this had to be rewritten, but the basic idea remained the same. </p> <p>The sample I am going to show for the EnumToVisualState control is a simple one: the ViewModel controls whether a panel is to be open or closed via a simple Toggle method. </p> <h3>Configuration</h3> <p>Let’s define a simple enum for the panel’s two states: On and Off:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">enum</span> PanelState { Off, On }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>…and use it in the ViewModel:</p> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">private</span> PanelState _panel = PanelState.Off;</pre> <pre><span class="lnum"> 2: </span><span class="kwrd">public</span> PanelState Panel</pre> <pre class="alt"><span class="lnum"> 3: </span>{</pre> <pre><span class="lnum"> 4: </span> get { <span class="kwrd">return</span> _panel; }</pre> <pre class="alt"><span class="lnum"> 5: </span> set</pre> <pre><span class="lnum"> 6: </span> {</pre> <pre class="alt"><span class="lnum"> 7: </span> _panel = <span class="kwrd">value</span>;</pre> <pre><span class="lnum"> 8: </span> <span class="kwrd">if</span> (PropertyChanged != <span class="kwrd">null</span>)</pre> <pre class="alt"><span class="lnum"> 9: </span> PropertyChanged(<span class="kwrd">this</span>, <span class="kwrd">new</span> PropertyChangedEventArgs(<span class="str">"Panel"</span>));</pre> <pre><span class="lnum"> 10: </span> }</pre> <pre class="alt"><span class="lnum"> 11: </span>}</pre> <pre><span class="lnum"> 12: </span> </pre> <pre class="alt"><span class="lnum"> 13: </span><span class="kwrd">public</span> <span class="kwrd">void</span> TogglePanel(<span class="kwrd">object</span> dataContext, TappedRoutedEventArgs args)</pre> <pre><span class="lnum"> 14: </span>{</pre> <pre class="alt"><span class="lnum"> 15: </span> Panel = Panel == PanelState.Off ? PanelState.On : PanelState.Off;</pre> <pre><span class="lnum"> 16: </span>}</pre> </div> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <pre></pre> <p>You can use a more sophisticated method for raising the PropertyChanged event, but it is important that you do perform this call. </p> <p>Next, you need to define the Visual States that correspond to the enum values and property names above. For this example, we need to define a Visual State Group called “Panel”, and two states within it: “Panel_On” and “Panel_Off”. Here is an example for a panel that slides in from the left:</p> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd"><</span><span class="html">VisualStateManager.VisualStateGroups</span><span class="kwrd">></span></pre> <pre><span class="lnum"> 2: </span> <span class="kwrd"><</span><span class="html">VisualStateGroup</span> <span class="attr">x:Name</span><span class="kwrd">="Panel"</span><span class="kwrd">></span></pre> <pre class="alt"><span class="lnum"> 3: </span> <span class="kwrd"><</span><span class="html">VisualStateGroup.Transitions</span><span class="kwrd">></span></pre> <pre><span class="lnum"> 4: </span> <span class="kwrd"><</span><span class="html">VisualTransition</span> <span class="attr">GeneratedDuration</span><span class="kwrd">="0:0:0.5"</span><span class="kwrd">></span></pre> <pre class="alt"><span class="lnum"> 5: </span> <span class="kwrd"><</span><span class="html">VisualTransition.GeneratedEasingFunction</span><span class="kwrd">></span></pre> <pre><span class="lnum"> 6: </span> <span class="kwrd"><</span><span class="html">CircleEase</span> <span class="attr">EasingMode</span><span class="kwrd">="EaseInOut"</span><span class="kwrd">/></span></pre> <pre class="alt"><span class="lnum"> 7: </span> <span class="kwrd"></</span><span class="html">VisualTransition.GeneratedEasingFunction</span><span class="kwrd">></span></pre> <pre><span class="lnum"> 8: </span> <span class="kwrd"></</span><span class="html">VisualTransition</span><span class="kwrd">></span></pre> <pre class="alt"><span class="lnum"> 9: </span> <span class="kwrd"></</span><span class="html">VisualStateGroup.Transitions</span><span class="kwrd">></span></pre> <pre><span class="lnum"> 10: </span> <span class="kwrd"><</span><span class="html">VisualState</span> <span class="attr">x:Name</span><span class="kwrd">="Panel_On"</span><span class="kwrd">/></span></pre> <pre class="alt"><span class="lnum"> 11: </span> <span class="kwrd"><</span><span class="html">VisualState</span> <span class="attr">x:Name</span><span class="kwrd">="Panel_Off"</span><span class="kwrd">></span></pre> <pre><span class="lnum"> 12: </span> <span class="kwrd"><</span><span class="html">Storyboard</span><span class="kwrd">></span></pre> <pre class="alt"><span class="lnum"> 13: </span> <span class="kwrd"><</span><span class="html">DoubleAnimation</span> <span class="attr">Duration</span><span class="kwrd">="0"</span> <span class="attr">To</span><span class="kwrd">="-340"</span> <span class="attr">Storyboard</span>.<span class="attr">TargetProperty</span><span class="kwrd">="(UIElement.RenderTransform).(CompositeTransform.TranslateX)"</span> <span class="attr">Storyboard</span>.<span class="attr">TargetName</span><span class="kwrd">="grid1"</span> <span class="attr">d:IsOptimized</span><span class="kwrd">="True"</span><span class="kwrd">/></span></pre> <pre><span class="lnum"> 14: </span> <span class="kwrd"></</span><span class="html">Storyboard</span><span class="kwrd">></span></pre> <pre class="alt"><span class="lnum"> 15: </span> <span class="kwrd"></</span><span class="html">VisualState</span><span class="kwrd">></span></pre> <pre><span class="lnum"> 16: </span> <span class="kwrd"></</span><span class="html">VisualStateGroup</span><span class="kwrd">></span></pre> <pre class="alt"><span class="lnum"> 17: </span><span class="kwrd"></</span><span class="html">VisualStateManager.VisualStateGroups</span><span class="kwrd">></span></pre> </div> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <pre></pre> <p>The last step is to add an EnumToVisualState control to your Page:</p> <pre class="csharpcode"><span class="kwrd"><</span><span class="html">df:EnumToVisualState</span> <span class="attr">Opacity</span><span class="kwrd">="0"</span> <span class="attr">VerboseInitialization</span><span class="kwrd">="True"</span> <span class="attr">ElementWithVisualStates</span><span class="kwrd">="{Binding ElementName=grid}"</span> <span class="kwrd">/></span></pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>The control is invisible. It has three important properties:</p> <p><strong>DataContext</strong><br /> The ViewModel where the enums are defined. Since DataContext is inherited in the Visual Tree, most of the time you can leave it as is – however, if you need to, you can bind it to something else, using the full binding arsenal of WinRT</p> <p><strong>ElementWithVisualStates</strong><br /> This is the FrameworkElement the Visual States of which we want to control. </p> <p><strong>VerboseInitialization</strong><br /> Set this to true to have EnumToVisualState write detailed initialization information to the Debug output window. This will show you what kind of properties and methods the control is looking for in the ViewModel, and help hunt down typos.</p> <p>Finally, we can add a Button to the UI to toggle the panel by calling the TogglePanel VM method using the CallVMMethod technique:</p> <pre class="csharpcode"><span class="kwrd"><</span><span class="html">Button</span> <span class="attr">Content</span><span class="kwrd">="Toggle Panel"</span> <span class="attr">df:CallVMMethod</span>.<span class="attr">Tapped</span><span class="kwrd">="TogglePanel"</span> <span class="kwrd">/></span></pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>Tapping the button now invokes the TogglePanel VM method, which in turn changes the PanelState enum, which causes the Visual State to change and the animation to be played. </p> <h3>Conventions</h3> <p>EnumToVisualState uses a convention-based approach. This means that instead of using a lot of binding, you only have to make sure that the enums in the ViewModel and the state names in the View match to work. Here are the naming conventions you have to follow:</p> <ul> <li>To map a Visual State Group to an enum, all you have to do is make sure they both have the same name. </li> <li>To map a Visual State to a value of an enum, you have to name the Visual State correctly: <Enum variable name>_<enum value name>. </li> <li>To get notified in the ViewModel when a visual state transition is finished, you need to have a method called <VisualStateGroup name>TransitionComplete() with no parameters.</li> </ul> <p>So, if you have an enum called PanelState, which has the possible values of “Off” and “On”, and you have a ViewModel property called “Panel”, you need to call your Visual State Group “Panel”, and the states withing it “Panel_Off” and “Panel_On”.</p> <h3>Callbacks</h3> <p>Since Visual States can have transition animations which can take a while to finish, it is sometimes useful to know when the user actually sees the final scene. EnumToVisualState provides you with this information: if you have a method called “PanelTransitionComplete”, this method will be called every time the “Panel” Visual State Group finishes a transition animation. Here is an example:</p> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">public</span> <span class="kwrd">void</span> PanelTransitionComplete()</pre> <pre><span class="lnum"> 2: </span>{</pre> <pre class="alt"><span class="lnum"> 3: </span> MessageDialog msgd = <span class="kwrd">new</span> MessageDialog(<span class="str">"Panel transition to "</span> + Panel.ToString() + <span class="str">" complete!"</span>);</pre> <pre><span class="lnum"> 4: </span> msgd.ShowAsync();</pre> <pre class="alt"><span class="lnum"> 5: </span>}</pre> </div> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <pre></pre> <p>The new state is not passed to this method, it can be determined from the value of the corresponding enum.</p> <h3>Initial State</h3> <p>You can also set an initial state for the enums in the VM, and the Visual States will be initialized in that state. For example, if you set the Panel to PanelState.Off, the Panel will not be visible when the Page first shows up. While this is achieved without a visible transition animation, the TransitionComplete method is still invoked.</p> <h1>Download</h1> <p>Finally, you can download <a href="http://sdrv.ms/WLPOqC">the entire demo project here</a>. You will need to copy four files to your project: CallVMMethod.cs, CallVMMethodHandledEvents.tt, EnumToVisualState.cs, and also . I will also prepare a Nuget package, and will upload it soon after this article is published.</p> <h1>Summary</h1> <p>Porting our tried and proven Behaviors to WinRT was not a simple task. However, I believe that in the end, the core values of the original solution are preserved despite the different architecture. Please let me know if you find this library useful, or if you have any feedback!</p> http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx editorial@silverlightshow.net (András Velvárt ) http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx#comments http://www.silverlightshow.net/items/Designer-friendly-MVVM-for-XAML-Windows-Store-applications.aspx Thu, 07 Feb 2013 13:49:00 GMT Metro style applications – designing for the user <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Metro-style-applications-designing-for-the-user.aspx" data-font="segoe ui" data-layout="button_count"></div> </td> <td><a href="https://twitter.com/share" class="twitter-share-button" data-via="silverlightshow" data-counturl="http://www.silverlightshow.net/items/Metro-style-applications-designing-for-the-user.aspx" data-count="horizontal" data-text="Reading SilverlightShow article 'Metro style apps – designing for the user' #win8dev #win8" data-url="http://slshow.net/KMMYzQ">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Metro-style-applications-designing-for-the-user.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p>It has been months since Windows 8 is available for developers and the need for new applications is growing in a fast pace. </p> <div style="border: 1px solid #dddddd; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; margin-right: 5px; padding-top: 5px;"> <h3>Don't miss...</h3> <ul style="list-style-type: circle; margin: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Webinars.aspx">Recordings of SilverlightShow Win 8 webinars</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Windows-8-and-the-future-of-XAML-Part-1-An-overview-of-the-Windows-8-platform.aspx">The article series: Windows 8 and the future of XAML</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/win8_odata.aspx">Ebook: Windows 8 XAML Metro Apps with OData</a> </li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/win8_odata.aspx" target="_self"><img style="width: 107px; height: 150px;" alt="Ebook: Windows 8 XAML Metro Apps with OData" src="http://www.silverlightshow.net/Storage/Ebooks/win8_odata.png" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> And nothing is more exacting than a computer user in 21<sup>st</sup> century. It’s quite difficult to build the <em>right</em> application, moreover – it’s even more difficult to stay on top and not to be, metaphorically, stepped over by the big players. They always know what exactly the user wants and have the resources to provide it to him. But that’s not always what has to happen after all.<br /> <p> You have the power to build what the user wants and even build it so that s/he would feel it so natural to use your Metro application. That is to design the application in a way that using the fingers on the display seems to be a pleasure, but not a challenge. <br />  </p> <h2>Okay, let’s make our Metro applications look great!</h2> <p>Designing the Metro application is different from designing the common and straightforward desktop application. Obviously, using fingers on touch instead of mouse cursor is a big difference. And the Metro style applications will soon become the mainstream. </p> <p><a href="http://msdn.microsoft.com/en-gb/library/windows/apps/hh700403">Here</a> you can find design assets for creating great Metro application mock-ups. The download contains layered PhotoShop files representing common controls and components, project layouts and templates. </p> <p>In the download you will find lots of .psd files that you can use to build a sketch or mocked prototype of your application. It seems that everything you would ever need is in:</p> <ul> <li><strong>Common controls.</strong> A variety of styles of all controls in dark and light Metro themes.</li> <li><strong>Common components.</strong> Tiles with the 1x1 and 2x1 ratio, contracts – the charms bar, search, share and settings side menus and more, and the keyboard.</li> <li><strong>Base layouts.</strong> For fill, full, portrait and snap views.</li> <li><strong>Project templates.</strong> For light and dark themes.</li> </ul> <p>Microsoft provides you with all you could need, but you are, of course, not limited only to the list. All files are layered and fully editable to stick with your mock-up design needs.</p> <h2>User experience design patterns</h2> <p>Here come the UX design patterns. They encapsulate the most important principles in Windows 8 Metro applications and guide you to the ultimate design. Using the patterns helps you in finding answers to questions related to content organization in pages, placing buttons and commands and the touch gestures and interactions.</p> <h3>Navigation design</h3> <p>The navigation design patters guide developers in organizing application content in pages, subpages, sections and categories so the users feel it comfortable and intuitively to switch between application screens and navigate through different views. It focuses mainly on two types of navigation.</p> <p> </p> <p><img alt="" src="http://www.silverlightshow.net/Storage/Users/lnikolov/MetroAppsDesign/hub.png" style="float: left; margin-right: 15px; border-width: 0px; border-style: solid;" /></p> <p>The <em>Hub</em> design pattern, or hierarchical system of navigation, is the most commonly used in the consumers preview. It is appropriate when the application consists of large amount of data that also varies a lot. The content is organized in levels and each level is responsible for a specific context. The top-most page – the Hub page, also referred as initial page, is where the content is presented in different sections with different contexts. The Hub page usually provides very different categories of content and less functionality. Its main focus is the content presentation. Each section of the Hub page is associated with a Section page that is more specific in its content presentation. It often contains a number of data items. Each item is then presented in details in the Details page – the third and last level of content.<!--</p--> </p> <p><img alt="" src="http://www.silverlightshow.net/Storage/Users/lnikolov/MetroAppsDesign/flat.png" style="float: left; margin-right: 15px;" />The Flat design system is used mostly in applications that have a single purpose and clear interaction and process flow. Such an application is document creation tool that has small number of pages that have to be executed all in a specific order.</p> <p><br /> </p> <p>On the navigation design documentation page <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh761500.aspx">here</a> you can also find guidelines and basic navigation concepts for Metro applications.</p> <h3>Commanding design</h3> <p><img alt="" src="http://www.silverlightshow.net/Storage/Users/lnikolov/MetroAppsDesign/communication.png" style="float: left; margin-right: 15px;" />The commanding design guidelines that you can find <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh761499.aspx">here</a> describe the best practices in Metro applications for placing and using command buttons in all possible ways. The focus is on what the user should be able to do and how this should happen. When possible you must allow manipulating items and executing commands directly from the canvas and not by the charms and the application bar. The command buttons have to be consistently used in all application views so it is the same and intuitively for users to execute commands from everywhere. To avoid complexity limit the number of commands and always consider the placement of the button – this could improve the speed a command can be acted upon.</p> <h3>Touch interaction design</h3> <p>On the Microsoft Build conference last year Jensen Harris of the Windows User Experience team announced the results from usability research conducted from Microsoft in their dedicated labs for the comfortable zones of interaction and behavior when using a touch screen device like the Metro tablet. Everyone uses the touch device in a slightly different way in different postures – on the knee, on tables, with two hands on the side, etc. The last turned to be the most common posture. </p> The touch interaction guidelines (that you can find in details <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh465415.aspx">here</a>) describe how to provide good touch interaction experience with your application partly relying on researches among users.<br /> <p><strong>Interaction comfortable area:</strong> Because the Windows 8 tablets are most often held along the side, the bottom corners and sides are ideal locations to put your interaction elements. To comfortably reach the center of the screen it takes you a posture change – put the important interaction interface close to the edges in the user’s comfortable zone.</p> <p><img alt="" src="http://www.silverlightshow.net/Storage/Users/lnikolov/MetroAppsDesign/touch_interaction.png" /></p> <p><strong>Reading comfortable area:</strong> Content in the top half of the screen is easier to read than content in bottom half or the middle because it is often partly covered by your fingers.</p> <p><img alt="" src="http://www.silverlightshow.net/Storage/Users/lnikolov/MetroAppsDesign/reading_comf.png" /></p> <p>Windows 8 has several standard touch interactions, which effects shouldn’t change when the display is touched with more fingers than expected. </p> <p><img alt="" src="http://www.silverlightshow.net/Storage/Users/lnikolov/MetroAppsDesign/Windows-8-Touch-Interactions.png" style="width: 450px; height: 258px;" /></p> <p>Elements from your interface that could be moved around should follow the finger direction while the display is touched. Just like in real world – the pen is in your hand while you don’t put it on the desk. All interactions should be observed, i.e. user should feel or see a feedback from his actions. It’s not acceptable to press a button with your finger and don’t see any flash or any kind of feedback. You could be misled that your touch hasn’t been registered from the device.  And last but definitely not least – always consider the size of the things. The error rate increases with the size getting smaller. The recommended minimum size for a touch target is 7x7 mm (40x40 pixels) with at least 2 mm padding. Of course, when the accuracy matters, the size gets bigger.</p> <p> Touch interactions are important. Think if the interactions as the language that your application uses to communicate with the user. You need this language fluent!</p> <h2>Conclusion</h2> Designing your application in a way that you put yourself in the user shoes is a key factor for the vitality of a future product. In a world where the user is ruling and defines the standards, the design and feel of your application is also the packaging. And the bad pack is even not considered as an option. This article is about attracting users with nice and intuitive user experience in Windows 8 Metro applications. To keep a user, though, you need also the content and value. Harnessing the power of the navigation, commands and touch interactions guidelines and patterns parallel with the content may be the key of your success! http://www.silverlightshow.net/items/Metro-style-applications-designing-for-the-user.aspx editorial@silverlightshow.net (Lazar Nikolov ) http://www.silverlightshow.net/items/Metro-style-applications-designing-for-the-user.aspx#comments http://www.silverlightshow.net/items/Metro-style-applications-designing-for-the-user.aspx Wed, 02 May 2012 12:21:00 GMT Working with Prism 4 Part 4: Region Navigation <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-4-Region-Navigation.aspx" data-font="segoe ui" data-layout="button_count"></div> </td> <td><a href="https://twitter.com/share" class="twitter-share-button" data-via="silverlightshow" data-counturl="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-4-Region-Navigation.aspx" data-count="horizontal" data-text="Reading the article 'Working with #Prism 4: Region Navigation' by @briannoyes" data-url="http://slshow.net/x6v7VK">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-4-Region-Navigation.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p>This is part 4 in the series Working with Prism 4.</p> <h3>Introduction</h3> <p>At Microsoft <a href="http://asp.net/" target="_blank">ASP.NET</a> <a href="http://devconnections.com/" target="_blank">Connections</a> March 26- 29 2012 I’ll be presenting a session on Prism development that includes the capabilities covered in this article – the URI-based navigation capabilities of Prism.  </p> <div style="border:1px solid #dddddd;border-image: initial; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>More resources...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Webinars.aspx">Upcoming SilverlightShow <strong>Webinars</strong></a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/WCF-RIA-Services-Webinar-4.aspx">Recordings of the Webinar Series: <strong>WCF RIA Services</strong></a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/prism4.aspx">The Prism 4 Series is also available as an Ebook:</a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/prism4.aspx"><img style="border:0px solid; border-image: initial; width: 121px; height: 170px;" alt="Working with Prism 4 - ebook by Brian Noyes" src="http://www.silverlightshow.net/Storage/Ebooks/prism.png" usemap="#rade_img_map_1291385581316" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> In this article I am going to right some wrongs in the code from the past couple articles that I put there to keep things simple and focused on other things for the first few articles. When using the MVVM pattern, one of the major goals is to maintain loose coupling and separation of concerns between views and their view models. But even more important is that different view models should not be coupled to each other unless it is a parent-child kind of relationship, and view models should not be coupled to other views or their own view either. When I set up the code in the previous article to load and switch CustomerEditView instances and their view models, I did it all from the CustomerListViewModel. That code involved using the Prism RegionManager to do the view loading and switching, but it required me to create instances of CustomerEditView and CustomerEditViewModel in the code of CustomerListViewModel. That is a violation of the decoupling goals of MVVM. <p>To fix this I am going to leverage one of the other features of Prism 4 – view switching navigation. In the previous articles, you have seen two parts of the API of the RegionManager service. One involved the Add and Activate methods of the IRegionManager interface. These allow you to explicitly add a view to a region and activate (or show) it at the appropriate times. You also saw in the last article that the AddToRegion method simplifies the process of adding a view if it will be the only. However, these approaches require you to have a view instance available to pass to the methods. That means the code that makes those calls is inherently coupled to the view instances. If you also need to initialize some state of the view model at the point where you are adding the views, that means you might also be coupled to the view model class in that same code. This is the code I placed in the CustomerListViewModel that really should not have been there.</p> <p>The sample code for this article builds on the code from the last article. You can download the <a href="http://www.silverlightshow.net/Storage/Sources/Prism4CompositeCommandAndEventsSample.zip" target="_self">completed code from Part 3</a> here. You can <a href="http://www.silverlightshow.net/Storage/Sources/Prism4ViewNavigationSample.zip" target="_self">download the completed code for this article here</a>.</p> <h3>View Switching Navigation</h3> <p>In Prism 4 the capability was added to have a more implicit and loosely coupled form of view switching that mimics the URI-based navigation of the web. If you think about what a user is doing when they navigate to a particular page on  a web site by putting in an address, they are not really requesting a specific implementation of a page, they are requesting a named view that is the relative portion of the URI (minus the site address at the root). Through mechanisms like the ASP.NET Routing Service, that URI could map to any kind of implementation behind the scenes, and the requester need not know what or where it is. They just need to know the logical name of the view they are trying to get to in the form of a URI. Additionally, the web addressing scheme allows you to pass additional information as part of the URI, including parameters to be passed to the receiver of the request.</p> <p>If a view model or other code is going to cause views to switch out in the user interface, it would be nice if that code had the same degree of decoupling from the implementation of the target views as well as a similar logical addressing mechanism. Prism added a great capability that mimics this to load and switch views within a region based on an extension method that was added to the IRegionManager interface, called RequestNavigate. This method has several overloads, but they all take two key parameters: the region name in which you want navigation to happen (similar to the site root address in the web browser analogy) and the logical name of the view you want to navigate to. The caller of the method does not have to know what view type or instance the request for navigation maps to, it just knows there is a logical view out there that is wants to see.</p> <p>This capability includes more than just the ability to load a view into a region. You can pass parameters to its view or view model as part of the navigation request, and the view or view model can use that information to initialize itself or to refresh its state. The view or view model can participate in the decision of whether to create a whole new view or to reuse one that has been shown before. The view can also participate in deciding if and when the navigation can be completed, so that it could for example prompt the user to save changes or to allow the view switching. I’ll be showing you how to leverage all of this in this article.</p> <h3>Step 1: Export the views by logical name</h3> <p>The first modification to make is to declare the logical name of the view as it will be requested by a piece of code wanting to navigate to it. The way this is done with MEF is by using the [Export] attribute with a contract name. When a view is first requested within a region, Prism will create a new instance of it, add it to the region, and activate it. Subsequent requests to navigate to that view type will either get a new instance or will reuse the existing instance, base on some interfaces I’ll discuss a little later in the article.</p> <p>The modifications to the views look like this:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> [Export(<span class="str">"CustomerListView"</span>)]</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> [PartCreationPolicy(CreationPolicy.NonShared)]</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> CustomerListView : UserControl</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> ...</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> }</pre> <!--CRLF--></div> </div> <p>Notice the association of the logical name with the class. In this case, they happen to be the same. But there is no requirement for them to match. The PartCreationPolicy is required because by default, MEF creates singleton instances of any class it exports unless you change the CreationPolicy to NonShared as shown. This allows us to have multiple instances of the view if desired.</p> <p>Do the same for the CustomerEditView:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> [Export(<span class="str">"CustomerEditView"</span>)]</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> [PartCreationPolicy(CreationPolicy.NonShared)]</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> CustomerEditView : UserControl</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">public</span> CustomerEditView()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> InitializeComponent();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> }</pre> <!--CRLF--></div> </div> <h3>Step 2: Switch to “View First” construction of the CustomerEditViewModel</h3> <p>In the previous article’s code, the CustomerEditViewModel and CustomerEditView were being constructed and married together by code in the CustomerListViewModel. That is part of what we are trying to fix. It is much easier and better from a development tools perspective (Visual Studio and Blend designers – aka “Blendability”) and code simplicity perspective if the view creates the view model declaratively in the XAML. The CustomerListView and OrdersView were already doing this, but I needed to switch the CustomerEditViewModel so that it is structured the same so that when the view gets constructed (which will happen in the Prism framework with the navigation features we are looking at), the view model is also created and wired up as the view’s DataContext.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">UserControl</span> <span class="attr">x:Class</span><span class="kwrd">="Prism101.Modules.Core.CustomerEditView"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">xmlns:local</span><span class="kwrd">="clr-namespace:Prism101.Modules.Core"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> ...<span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd"><</span><span class="html">UserControl.DataContext</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd"><</span><span class="html">local:CustomerEditViewModel</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd"></</span><span class="html">UserControl.DataContext</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd"></</span><span class="html">UserControl</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <h3>Step 3: Request navigation to the CustomerListView on initial load</h3> <p>This step is not explicitly required, but just want to show an alternative to the initial adding of the CustomerListView to the main region. In the previous few articles, the Core module’s IModule.Initialize code looked like this:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> Initialize()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> var view = <span class="kwrd">new</span> CustomerListView();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> RegionManager.AddToRegion(<span class="str">"MainContent"</span>, view);</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> }</pre> <!--CRLF--></div> </div> <p>Instead, using the navigation features, we could do this:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> Initialize()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> RegionManager.RequestNavigate(<span class="str">"MainContent"</span>, <span class="str">"CustomerListView"</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> }</pre> <!--CRLF--></div> </div> <p>Not a huge savings there, but at least this code no longer has to be coupled to the CustomerListView type and worry about its instance lifetime. In the next few steps you will see how it can really start to shine in other areas.</p> <h3>Step 4: Remove the view model coupled code</h3> <p>In the last article, I had the following code invoked when the Edit button was pressed in the CustomerListViewModel:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnEditCustomer()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> IRegion secondaryContentRegion = RegionManager.Regions[<span class="str">"SecondaryContent"</span>];</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">bool</span> alreadyExists = <span class="kwrd">false</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">foreach</span> (var view <span class="kwrd">in</span> secondaryContentRegion.Views)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> var custView = view <span class="kwrd">as</span> CustomerEditView;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> var custViewModel = custView.DataContext <span class="kwrd">as</span> CustomerEditViewModel;</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">if</span> (custViewModel.Customer == SelectedCustomer)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> secondaryContentRegion.Activate(view);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> alreadyExists = <span class="kwrd">true</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd">if</span> (!alreadyExists)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> CustomerEditView editView = <span class="kwrd">new</span> CustomerEditView();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> CustomerEditViewModel viewModel = <span class="kwrd">new</span> CustomerEditViewModel { Customer = SelectedCustomer };</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> editView.DataContext = viewModel;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> secondaryContentRegion.Add(editView);</pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> secondaryContentRegion.Activate(editView);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> }</pre> <!--CRLF--></div> </div> <p>This is the code that not only has coupling to the CustomerEditView and CustomerEditViewModel types, it is also doing instance management of those objects, which is really just wrong. Remove all the code in this method.</p> <h3>Step 5: Request navigation to the CustomerEditView for the right customer</h3> <p>Replace the code that was handling editing with the following code:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnEditCustomer()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> var uriQuery = <span class="kwrd">new</span> UriQuery();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">if</span> (SelectedCustomer != <span class="kwrd">null</span>)</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> uriQuery.Add(<span class="str">"customerId"</span>, SelectedCustomer.CustomerID);</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> var uri = <span class="kwrd">new</span> Uri(<span class="str">"CustomerEditView"</span> + uriQuery.ToString(), UriKind.Relative);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> RegionManager.RequestNavigate(<span class="str">"SecondaryContent"</span>, uri);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> }</pre> <!--CRLF--></div> </div> <p>Not only is this code much simpler, you can see that there is no type coupling in there at all. The first part of the method uses a helper object from Prism called UriQuery to formulate a query string with a name of customerId and the value from the selected customer. It then concatenates this with the logical view name it wants to request navigation to, and then calls the RegionManager.RequestNavigate extension method, identifying in which region it wants the view to be shown (SecondaryContent in this case). Could not be simpler, right?</p> <p>Because SecondaryContent happens to be a tab control, it means that each time navigation happens, it could do one of several things:</p> <ul> <li>Add a new tab to the control on every navigation, regardless of what customer is selected </li> <li>Add only one tab and replace its content with the information for the customer identified in the query string (in which case there would not be much point in having a tab control) </li> <li>Add a new tab when the customer identified does not already have an active tab, and if it does just activate it </li> </ul> <p>The last option is the one that will be most intuitive for the user, so that is the one we will go with here. But just realize with the mechanisms I’ll be showing shortly, you could do any of these with the exact same RequestNavigate call.</p> <h3>Step 6: Let the CustomerEditViewModel control its own initialization and instancing</h3> <p>In the code that I stripped out of the CustomerListViewModel, the code was not only managing the instancing of the edit view and view model, it was also initializing the state of the view model by setting the Customer property to the SelectedCustomer. Now that Prism is going to take care of creating the view (and implicitly the view model with the view-first construction), you still need a way to initialize the state of the view model. This can easily be done with an interface defined in Prism called INavigationAware. This interface has three members which allow your view or view model to</p> <ul> <li>Known when it has been navigated to and get access to the query string parameters to initialize state </li> <li>Known when it is being navigated away from (to do something like persist its state to a cache, service, or DB) </li> <li>Influence whether the view is the target of the navigation or should be reused for navigating to that view type but with different contents </li> </ul> <p>When RequestNavigate is called for a region, the navigation service that does the handling will check the views that are currently contained by that region. If one matches the URI for the view being requested, it will invoke the IsNavigationTarget method to allow that instance to decide whether it should be activated for the navigation to complete. If the view or view model returns true from that, it will be activated if its URI path matches the one being requested. If it returns false, Prism will create a new instance of the view type and place it in the region and activate it. The method is passed a NavigationContext object that contains the URI and parameters for the request to help guide it in its decision to answer the question “are you the one?”</p> <p>To accommodate the MVVM pattern but not force you to adopt it, whenever Prism looks for an interface implementation on a view, it also checks to see if the DataContext of the view (which should be the view model if doing MVVM) implements it. This allows you to put the logic that supports the interface only on the view model and leave the view as just the structural definition of the visual aspects of the view.</p> <p>After IsNavigationTarget is called, if it returns true, then the OnNavigatedTo method is called  with the same NavigationContext object. This is the chance for the view or view model to initialize itself (possibly based on URI parameters).</p> <p>The implementation of the INavigationAware interface in the CustomerEditViewModel looks like this:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">bool</span> INavigationAware.IsNavigationTarget(NavigationContext navigationContext)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">string</span> custId = navigationContext.Parameters[<span class="str">"customerId"</span>];</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">if</span> (!<span class="kwrd">string</span>.IsNullOrWhiteSpace(custId) && Customer != <span class="kwrd">null</span> && Customer.CustomerID == custId)</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">return</span> <span class="kwrd">true</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">return</span> <span class="kwrd">false</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">void</span> INavigationAware.OnNavigatedTo(NavigationContext navigationContext)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="rem">// Choosing to not refresh the customer every time the view is loaded</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd">if</span> (Customer != <span class="kwrd">null</span>) <span class="kwrd">return</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="rem">// Initial load - Load customer based on ID passed in</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="kwrd">string</span> custId = navigationContext.Parameters[<span class="str">"customerId"</span>];</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd">if</span> (<span class="kwrd">string</span>.IsNullOrWhiteSpace(custId)) <span class="kwrd">return</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> CustomersDomainContext context = <span class="kwrd">new</span> CustomersDomainContext();</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> EntityQuery<Customer> custQuery = context.GetCustomersQuery().Where(c => c.CustomerID == custId);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> context.Load(custQuery, OnCustomerLoadCompleted, <span class="kwrd">null</span>);</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnCustomerLoadCompleted(LoadOperation<Customer> obj)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> <span class="kwrd">if</span> (obj.HasError)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum25" class="lnum"> 25:</span> MessageBox.Show(<span class="str">"Error loading customer: "</span> + obj.Error.Message);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span> obj.MarkErrorAsHandled();</pre> <!--CRLF--> <pre class="alt"><span id="lnum27" class="lnum"> 27:</span> <span class="kwrd">return</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum29" class="lnum"> 29:</span> Customer = obj.Entities.FirstOrDefault();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum31" class="lnum"> 31:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> <span class="kwrd">void</span> INavigationAware.OnNavigatedFrom(NavigationContext navigationContext)</pre> <!--CRLF--> <pre class="alt"><span id="lnum33" class="lnum"> 33:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> }</pre> <!--CRLF--></div> </div> <p>You can see that the logic for IsNavigationTarget checks to see if the query string parameter customerId matches the CustomerID property of the Customer that the view model is managing. If you simply wanted to reuse the view and view model instance and only have one instance of that view type (for containment in a ContentControl for example), you could just hardcode a true return value from the IsNavigationTarget. But in our case we are going to have multiple instances of this view type in a tab control, so we want to use the IsNavigationTarget to drive the logic that if the navigation request is for a customer for which there is already a view, just activate that view. If not, create a new instance of that view type and initialize it based on the customerId.</p> <p>So the OnNavigatedTo method checks to see if the Customer is already set, this view would not be navigated to unless the IsNavigationTarget had found that the Customer matched the request, so there is no initialization needed (unless you wanted to always refresh the customer data from the back end for example). But if the Customer is null, it is the first time activating this view for a given CustomerId, so the code uses RIA Services to load a Customer from the back end. This approach has the additional advantage that the views are more self-deterministic – instead of requiring some other code to know how to get a Customer and shove the right one into the view, the view (or better yet its view model) knows how to go get the right state based on nothing more than a state identifier of some sort that is placed in the query string. This allows you to move the views around within the app, change who their parent view/view model is, and not have to change anything about how the view gets initialized.</p> <p>If you are concerned that this pattern will make you make more round trips to the back end, all you need to do is adopt <a href="http://www.martinfowler.com/eaaCatalog/repository.html" target="_blank">the Repository pattern</a> and have your view models call the repository with their state identifiers, and have the Repository cache the data client side and encapsulate what the cache invalidation scheme is so the views don’t have to worry about it and can just request their current state at any time.</p> <p>Finally, in this case, we have no logic to perform in the OnNavigatedFrom method so we can just leave that one blank.</p> <h3>Step 7: Let the view decide when navigation happens</h3> <p>There is a very important but subtle point in the way the RequestNavigate method is named. It is a request for something to happen, but it doesn’t say when it should happen or make the implication that navigation will be complete when the method returns. Navigation needs to be a non-blocking request because the view that is currently presented might need to do something (such as prompt the user to save) before allowing the navigation to complete. That is inherently a non-deterministic and potentially long-running block (the user might be distracted tweeting in another window for example). Additionally, a view needs to be able to reject navigation because it may be in the middle of an operation it cannot cancel immediately or you may want to let the user decide whether to dismiss a view for example.</p> <p>So the RequestNavigate method is a non-blocking asynchronous call. If the caller needs to know when navigation is complete, there is an overload that takes a callback reference that will be invoked by the Prism navigation service once the navigation happens or is rejected. If the view does want to decide if and when navigation should occur, it (or its view model) implements an interface called IConfirmNavigationRequest. This interface has one method, ConfirmNavigationRequest, which is passed a NavigationContext like the INavigationAware methods, and a callback for the method to invoke when it has decided to either allow the view to be deactivated (navigated away from) or to reject the navigation.</p> <p>In the same application, I chose to demonstrate this by using the IsDirty state of the edit views (the same one that is enabling and disabling Save commands as <a href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-3-Composite-Command-and-Pub-Sub-Events.aspx" target="_blank">discussed in the last article</a>). If the view state IsDirty, then the view model will prompt the user with a message box to let them confirm or deny navigation with an OK/Cancel action. </p> <p>The implementation of this interface is shown below. You can see that is IsDirty is true, it prompts the user. If they press OK, the callback is invoked with a true argument, meaning navigation can proceed. If Cancel, then it gets invoked with false. </p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">void</span> IConfirmNavigationRequest.ConfirmNavigationRequest(NavigationContext navigationContext, </pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> Action<<span class="kwrd">bool</span>> continuationCallback)</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">if</span> (IsDirty)</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">string</span> prompt = <span class="str">"The view's state has changed and has not been saved, do you want to allow view switching?"</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> var result = MessageBox.Show(prompt,<span class="str">"Confirmation"</span>,MessageBoxButton.OKCancel);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd">if</span> (result == MessageBoxResult.OK)</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> continuationCallback(<span class="kwrd">true</span>);</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd">return</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd">else</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> continuationCallback(<span class="kwrd">false</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd">return</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> continuationCallback(<span class="kwrd">true</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> }</pre> <!--CRLF--></div> </div> <p>Now the one hitch in the sample application is that because these views are presented in a tab control, the user can click on a tab header at any time and cause view switching to occur and the Prism navigation service would not be involved at all, so your view implementations of the INavigationAware and IConfirmNavigationRequest interfaces would not be called. To intercept and prevent tab switching would require a lot lower interception of events on the tab control. So this mechanism for preventing navigation is better suited for containment in a ContentControl where the user does not have a direct user interface mechanism to cause views to swap. But as long as the changing occurs through the navigation controls you put in place that call RequestNavigate, life will be good.</p> <h3>Summary</h3> <p>In this article, you learned how to leverage the navigation capabilities of Prism in a more loosely coupled and flexible way with the IRegionManager.RequestNavigate method, INavigationAware and IConfirmNavigationRequest interfaces. These capabilities allow you to compose a much more loosely coupled application where no code is explicitly tied to view or view model types. The view models can be designed to operate independently of their containers and the code that causes navigation or view switching to happen does not have to be coupled to what the specific implementation of the view is or how it needs to be initialized. This approach still gives you control over when views are created and added to regions and activated, but puts the control in the hands of the views themselves instead of the code that triggers the navigation.</p> <p>This capability can also be mixed in with the Silverlight navigation framework as shown in <a href="http://blogs.msdn.com/b/kashiffl/archive/2010/10/05/integrating-prism-v4-region-navigation-with-silverlight-frame-navigation.aspx" target="_blank">this article by Karl Shifflet</a>.</p> <p>You can <a href="http://www.silverlightshow.net/Storage/Sources/Prism4ViewNavigationSample.zip" target="_blank">download the completed code for this article here</a>.</p> <h3>About the Author</h3> <p>Brian Noyes is Chief Architect of <a href="http://www.idesign.net/">IDesign</a>, a Microsoft Regional Director, and Silverlight MVP. He is a frequent top rated speaker at conferences worldwide including Microsoft TechEd, DevConnections, VSLive!, DevTeach, and others. Brian worked directly on the Prism team with Microsoft patterns and practices and co-authored the book Developers Guide to Microsoft Prism 4. He is also the author of Developing Applications with Windows Workflow Foundation, Smart Client Deployment with ClickOnce, and Data Binding in Windows Forms 2.0. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at <a href="http://briannoyes.net/">http://briannoyes.net/</a> or on Twitter @briannoyes.</p> http://www.silverlightshow.net/items/Working-with-Prism-4-Part-4-Region-Navigation.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/Working-with-Prism-4-Part-4-Region-Navigation.aspx#comments http://www.silverlightshow.net/items/Working-with-Prism-4-Part-4-Region-Navigation.aspx Thu, 16 Feb 2012 16:02:00 GMT Working with Prism 4 Part 3: Composite Command and Pub/Sub Events <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-3-Composite-Command-and-Pub-Sub-Events.aspx" data-font="segoe ui" data-layout="button_count"></div> </td> <td><a href="https://twitter.com/share" class="twitter-share-button" data-via="silverlightshow" data-counturl="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-3-Composite-Command-and-Pub-Sub-Events.aspx" data-count="horizontal" data-text="Reading the article 'Working w/ #Prism 4: Composite Command and Pub/Sub Events' by @briannoyes" data-url="http://slshow.net/wvd1do">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-3-Composite-Command-and-Pub-Sub-Events.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p>This is part 3 in the series Working with Prism 4.</p> <h3>Introduction</h3> <p>In the last article, I showed how to structure your Prism application to use the MVVM pattern and use DelegateCommands to communicate between the view and view model. Additionally, I showed how to pull some data in using WCF RIA Services and display it in the view, as well as using Prism Regions and the ability to add and activate different views in a region to accomplish simple navigation for the user (view switching).</p> <div style="border:1px solid #dddddd;border-image: initial; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>More resources...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Webinars.aspx">Upcoming SilverlightShow Webinars</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/WCF-RIA-Services-Webinar-4.aspx">Recordings of the Webinar Series: WCF RIA Services</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/prism4.aspx">The Prism 4 Series is also available as an Ebook:</a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/prism4.aspx"><img style="border:0px solid; border-image: initial; width: 121px; height: 170px;" alt="Working with Prism 4 - ebook by Brian Noyes" src="http://www.silverlightshow.net/Storage/Ebooks/prism.png" usemap="#rade_img_map_1291385581316" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>In this article, I’ll extend that sample application a little farther and show you how to leverage two other loosely coupled communication features of Prism 4: CompositeCommands and Prism CompositePresentationEvents (aka pub/sub events). The code presented in this article builds on what was the completed code from the last article.</p> <p>You can <a href="http://www.silverlightshow.net/Storage/Sources/Prism4MVVMAndCommandsSamplePart2.zip" target="_blank">download the complete code from the last article that acts as the starting point here</a>. You can <a href="http://www.silverlightshow.net/Storage/Sources/Prism4CompositeCommandAndEventsSample.zip">download the completed code for this article here</a>.</p> <p>Note: Now that Silverlight 5 has released, the code for this article uses an updated version of the Prism 4 code recompiled to Silverlight 5 as a target. That code can be downloaded from <a href="http://prism.codeplex.com/" target="_blank">prism.codeplex.com</a> and is included in the completed code sample for this article.</p> <h3>CompositeCommands</h3> <p>CompositeCommands are another implementation of the ICommand interface defined by Silverlight and WPF. There are several differences about the CompositeCommand implementation and the DelegateCommand implementation. The first is that the CompositeCommand is an aggregation of other commands – a list of ICommand references internally. It allows you to hook up multiple command targets to a single root command that itself can be hooked up to a command source such as a button or menu item. Figure 1 shows this relationship. The CompositeCommand can hold references to any ICommand object, but typically you will use it in conjunction with DelegateCommands. When the CompositeCommand.Execute method is invoked, it will invoke the Execute method on each of the child commands. When CompositeCommand.CanExecute is called to determine whether the command is enabled, it polls its child commands for their result from CanExecute.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/___Figure1_2.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="Figure1" alt="Figure1" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/___Figure1_thumb.png" width="362" height="271" /></a></p> <p><strong>Figure 1: CompositeCommands contain other commands</strong></p> <p>Child commands register themselves with the composite command and can also unregister if appropriate. In this way, it is very similar to a subscribe/unsubscribe of an event, but with the additional functionality of commands to enable and disable the commands based on custom logic.</p> <p>Another thing different about CompositeCommands is that they can be hooked up to a source control ahead of time, before any child commands have registered. DelegateCommands have to be pointed to their target methods through a delegate at the point where they are constructed. As a result, CompositeCommands allow an extra layer of separation between the source (i.e. toolbar button or menu item) and the target (handling method) – decoupled in lifetime. Because they can target multiple child commands, they also work well for distributed logic such as a Save All command that needs to be dispatched to multiple open documents, each of which has their own handling logic in their view model.</p> <p>You will see both of these aspects at work in the sample code for this article – separated hook up of the command, and multiple handlers for command execution.</p> <h3>Pub/Sub Events</h3> <p>Another form of loosely coupled communications offered by Prism are pub/sub events. Normal events in .NET are fairly tightly coupled – both the publisher and subscriber objects have to be alive at the same time, the subscriber needs explicit type information and a reference to the publisher to hook up their event handler, and once subscribed, the publisher maintains a reference back to the subscriber through the delegate.</p> <p>Pub/sub events are designed to break that tight coupling. The idea is that you really want publishers and subscribers to not need either type information or coupled lifetimes. They should be able to come and go independently, and different types of subscribers and publishers should be able to participate in the same event scenario. The event is what is important, not the specific parties who raise or handle the events. To achieve this, you need a middleman or mediator between the publishers and subscribers. The <a href="http://www.martinfowler.com/eaaDev/EventAggregator.html" target="_blank">Event Aggregator</a> pattern is a means of achieving this. Prism provides an implementation of the Event Aggregator pattern that is easy to use and that provides several options including strong or weak references for subscribers, thread dispatching, and event filtering. </p> <p>Figure 2 shows the basic architecture of using the EventAggregator service in Prism. Publishers and Subscribers make calls directly against the EventAggregator to obtain references to event class instances. The EventAggregator is really nothing more than a <a href="http://martinfowler.com/eaaCatalog/registry.html" target="_blank">Registry</a> for event types. Publishers then use those event classes to publish an event with a strongly typed payload and subscribers hook up a listener through a delegate to a method that will accept the payload and handle the event for that subscriber. The event classes are derived from CompositePresentationEvent and do not need any implementation themselves, the class declaration is really just a way to tie together a base class reference with the strongly typed payload through the generic type definition. The CompositePresentationEvent base class provides all the infrastructure to maintain the list of subscribers, dispatch the calls on the appropriate thread, maintain weak or strong references, and filter the calls if desired.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure2_4.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="Figure2" alt="Figure2" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure2_thumb_1.png" width="669" height="301" /></a></p> <p><strong>Figure 2: Event Aggregator Architecture</strong></p> <h3></h3> <h3>Step 1: Add the Prism Libraries and Recompile for Silverlight 5</h3> <p>The first step for this article is that I downloaded a recently added source code release of Prism 4 from the <a href="http://compositewpf.codeplex.com/SourceControl/list/changesets" target="_blank">CodePlex site</a> and added the projects to the solution, as well as changing their compilation target to Silverlight 5. This is because there were a few incompatibilities discovered in using the Silverlight 4 versions of the libraries with Silverlight 5. And I actually stumbled upon one of those incompatibilities in putting together the sample for this article.</p> <h3>Step 2: Modify the application to present multiple edit views </h3> <p>To demonstrate the use of CompositeCommands, I wanted to have a reasonably realistic scenario of where you might use them. As mentioned earlier, CompositeCommands let you separate the hook up of the invoker from the hookup of the receiver in terms of the <a href="http://en.wikipedia.org/wiki/Command_pattern" target="_blank">Command pattern</a>. They also let you have multiple handlers for a given command, to address a Save All kind of scenario, which is what I will be putting together in this article.</p> <p>To do this, I need more than one thing open at a time to save. I added a TabControl to the MainPage shell view and made it a Prism Region so that multiple CustomerEditView instances could be opened in tabs there instead of swapping out the MainContent region view as was done in the last article.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">sdk:TabControl</span> <span class="attr">prism:RegionManager</span>.<span class="attr">RegionName</span><span class="kwrd">="SecondaryContent"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="2"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd"><</span><span class="html">prism:TabControlRegionAdapter.ItemContainerStyle</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd"><</span><span class="html">Style</span> <span class="attr">TargetType</span><span class="kwrd">="sdk:TabItem"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd"><</span><span class="html">Setter</span> <span class="attr">Property</span><span class="kwrd">="HeaderTemplate"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd"><</span><span class="html">Setter.Value</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd"><</span><span class="html">DataTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd"><</span><span class="html">StackPanel</span> <span class="attr">Orientation</span><span class="kwrd">="Horizontal"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="attr">Margin</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Title}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd"><</span><span class="html">Button</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="attr">Margin</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="attr">Content</span><span class="kwrd">="X"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="attr">Command</span><span class="kwrd">="{Binding CloseCommand}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd"></</span><span class="html">StackPanel</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> <span class="kwrd"></</span><span class="html">DataTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="kwrd"></</span><span class="html">Setter.Value</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> <span class="kwrd"></</span><span class="html">Setter</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> <span class="kwrd"></</span><span class="html">Style</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> <span class="kwrd"></</span><span class="html">prism:TabControlRegionAdapter.ItemContainerStyle</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> <span class="kwrd"></</span><span class="html">sdk:TabControl</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>Note the attached property to indicate that this is a Prism Region as discussed in the last two articles, as well as a Style to modify the HeaderTemplate of the TabItems in the TabControl to contain a TextBlock and an X Button to be able to close them. This style gets attached through a custom attached property provided by Prism called TabControlRegionAdapter.ItemContainerStyle. This is needed because the TabControlRegionAdapter is the thing in the Prism toolkit that generates the TabItems as views are added to the region. Also note that the template expects the DataContext to have a Title property for the text in the tab header, as well as a CloseCommand for the button Command. Those will be present on the view models for the individual views which are set as the DataContext based on the MVVM pattern.</p> <p>To populate the tabs, the EditCommand handling code in the CustomerListViewModel changed to the following:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnEditCustomer()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> IRegion secondaryContentRegion = RegionManager.Regions[<span class="str">"SecondaryContent"</span>];</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">bool</span> alreadyExists = <span class="kwrd">false</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">foreach</span> (var view <span class="kwrd">in</span> secondaryContentRegion.Views)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> var custView = view <span class="kwrd">as</span> CustomerEditView;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> var custViewModel = custView.DataContext <span class="kwrd">as</span> CustomerEditViewModel;</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">if</span> (custViewModel.Customer == SelectedCustomer)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> secondaryContentRegion.Activate(view);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> alreadyExists = <span class="kwrd">true</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd">if</span> (!alreadyExists)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> CustomerEditView editView = <span class="kwrd">new</span> CustomerEditView();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> CustomerEditViewModel viewModel = <span class="kwrd">new</span> CustomerEditViewModel { Customer = SelectedCustomer };</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> editView.DataContext = viewModel;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> secondaryContentRegion.Add(editView);</pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> secondaryContentRegion.Activate(editView);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> }</pre> <!--CRLF--></div> </div> <p>This code is very similar to what was discussed in the last article – it determines if there is a view already being presented within the “SecondaryContent” region for the selected customer. If so, it activates it. If not, it adds one. The main difference here is that the code is now targeting the SecondaryContent region, which is the tab control, and it allows more than one view to be created at a time.</p> <p>The structure of the CustomerEditView itself did not change at all, but the CustomerEditViewModel had to change quite a bit. First, it needed to have the Title and CloseCommand properties expected by the tab item headers.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">string</span> Title { get { <span class="kwrd">return</span> _Customer != <span class="kwrd">null</span> ? _Customer.CustomerID : <span class="str">"Empty"</span>; } }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> DelegateCommand CloseCommand { get; <span class="kwrd">private</span> set; }</pre> <!--CRLF--></div> </div> <p>Second, the CloseCommand handling needs to simply remove its view from the region, not swap views as the SaveCommand handling did from the last article:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnClose()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> IRegion secondaryContentRegion = RegionManager.Regions[<span class="str">"SecondaryContent"</span>];</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">foreach</span> (var view <span class="kwrd">in</span> secondaryContentRegion.Views)</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">if</span> (view <span class="kwrd">is</span> CustomerEditView && ((FrameworkElement)view).DataContext == <span class="kwrd">this</span>)</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> secondaryContentRegion.Remove(view);</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd">break</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> }</pre> <!--CRLF--></div> </div> <p>Third, it needed the SaveCommand logic to not swap views but to just manage the “saved” state of the view. In this case, for demo purposes, that meant just modifying the view model to support an IsDirty flag. That flag gets set when the customer is modified (one of its properties change). The flag gets cleared when the SaveCommand fires. Additionally, the SaveCommand was modified to have a CanExecute handler that checks that IsDirty flag. If the view’s state is not dirty, there is no reason to invoke the SaveCommand so its invoker should be disabled.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> Customer _Customer;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd">bool</span> _IsDirty = <span class="kwrd">false</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">public</span> CustomerEditViewModel()</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> SaveCommand = <span class="kwrd">new</span> DelegateCommand(OnSave, CanSave);</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> ...</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd">public</span> DelegateCommand SaveCommand { get; <span class="kwrd">private</span> set; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd">public</span> Customer Customer</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> get { <span class="kwrd">return</span> _Customer; }</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> set</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> <span class="kwrd">if</span> (_Customer != <span class="kwrd">value</span>)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> <span class="kwrd">if</span> (_Customer != <span class="kwrd">null</span>) _Customer.PropertyChanged -= OnCustomerChanged;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> _Customer = <span class="kwrd">value</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> <span class="kwrd">if</span> (_Customer != <span class="kwrd">null</span>) _Customer.PropertyChanged += OnCustomerChanged;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> RaisePropertyChanged(() => Customer);</pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum25" class="lnum"> 25:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum27" class="lnum"> 27:</span> <span class="kwrd">public</span> <span class="kwrd">bool</span> IsDirty</pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum29" class="lnum"> 29:</span> get</pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum31" class="lnum"> 31:</span> <span class="kwrd">return</span> _IsDirty;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum33" class="lnum"> 33:</span> set</pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum35" class="lnum"> 35:</span> _IsDirty = <span class="kwrd">value</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum36" class="lnum"> 36:</span> SaveCommand.RaiseCanExecuteChanged();</pre> <!--CRLF--> <pre class="alt"><span id="lnum37" class="lnum"> 37:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum38" class="lnum"> 38:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum39" class="lnum"> 39:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum40" class="lnum"> 40:</span> <span class="kwrd">private</span> <span class="kwrd">bool</span> CanSave()</pre> <!--CRLF--> <pre class="alt"><span id="lnum41" class="lnum"> 41:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum42" class="lnum"> 42:</span> <span class="kwrd">return</span> IsDirty;</pre> <!--CRLF--> <pre class="alt"><span id="lnum43" class="lnum"> 43:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum44" class="lnum"> 44:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum45" class="lnum"> 45:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnSave()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum46" class="lnum"> 46:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum47" class="lnum"> 47:</span> IsDirty = <span class="kwrd">false</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum48" class="lnum"> 48:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum49" class="lnum"> 49:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum50" class="lnum"> 50:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnCustomerChanged(<span class="kwrd">object</span> sender, PropertyChangedEventArgs e)</pre> <!--CRLF--> <pre class="alt"><span id="lnum51" class="lnum"> 51:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum52" class="lnum"> 52:</span> IsDirty = <span class="kwrd">true</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum53" class="lnum"> 53:</span> }</pre> <!--CRLF--></div> </div> <p>Notice that the CanSave handler just returns the flag. But since the enablement of the command depends on that flag, that means whenever that flag changes, the command should raise the CanExecuteChanged event. The best way to do that is to encapsulate the call to the DelegateCommand.RaiseCanExecuteChanged method in the setter for the IsDirty property and use that property internally throughout the view model instead of the member variable.</p> <p>At this point I have the setup to be able to edit multiple customer views at the same time in individual tabs. Next I want to be able to add a “Save All” command invoker at a shell level and have it invoke the SaveCommand on the individual open edit views as shown in Figure 3.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/__Figure3_2.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="Figure3" alt="Figure3" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/__Figure3_thumb.png" width="693" height="497" /></a></p> <p><strong>Figure 3: Multiple edit views active in the tab region</strong></p> <h3>Step 3: Add a CompositeCommand for the Save All command</h3> <p>A common way to define a CompositeCommand is similar to how WPF defines the built-in routed commands – as a public static readonly singleton instance of the command. In order for the invoker to be in one module and the handlers to be in different modules, they all need to be able to get to that definition of that command to hook up to it. So you will need to have a common or shared assembly that all the parts of your solution can reference to hold shared types like CompositeCommands and Pub/Sub events.</p> <p>The sample solution has a Silverlight Class Library project added with a Commands class to contain the CompositeCommand instances you want to define – in this case the SaveAllCommand.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> Commands</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> CompositeCommand SaveAllCommand = <span class="kwrd">new</span> CompositeCommand();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> }</pre> <!--CRLF--></div> </div> <h3> </h3> <h3>Step 4: Hook up the CompositeCommand Invoker</h3> <p>The invoker is simply a button in the MainPage.xaml:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">Button</span> <span class="attr">Content</span><span class="kwrd">="Save All"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">Command</span><span class="kwrd">="{Binding SaveAllCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"</span> <span class="kwrd">/></span></pre> <!--CRLF--></div> </div> <p>If you are using CompositeCommands in WPF, you can refer directly to the static instance with the {x:Static} markup extension. Because Silverlight does not have that markup extension in the framework, you will have to bind to a property exposed to your XAML. In this case to keep it simple, I expose that property from the code behind of the MainPage view itself and use a RelativeSource binding to get to the root element that corresponds to the code behind class. Then in the code behind I expose the static command variable via the property that the XAML is binding to. Alternatively I could have just hooked up the command in the code behind with a reference to the button.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> ICommand SaveAllCommand { get { <span class="kwrd">return</span> Commands.SaveAllCommand; } }</pre> <!--CRLF--></div> </div> <p>At this point the invoker is ready to invoke the command, but the button will be disabled because the CompositeCommand, as a container for command instances, is empty. The default logic of CompositeCommand is to be disabled unless <strong>all </strong>of its child commands are enabled. If there are no child commands, it is disabled because there is nothing to invoke. If you find you want different logic, such as enabling the command if <strong>any one</strong> of its child commands is enabled, all you need to do is derive a class from CompositeCommand and override the CanExecute method.</p> <h3>Step 5: Hook up the child command instances</h3> <p>As mentioned earlier, CompositeCommand exposes a Register/Unregister API for adding and removing child commands. To add a child command, simply call Register, passing an ICommand reference. Because the CustomerEditViewModel already has a SaveCommand that I want invoked when Save All is invoked, I just need to pass a reference to that in the constructor for the view model:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> Commands.SaveAllCommand.RegisterCommand(SaveCommand);</pre> <!--CRLF--></div> </div> <p>Likewise, when the view is going away (in the CloseCommand handler), you should unregister the command, otherwise the CompositeCommand will keep it, and be indirection, your view model, alive.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnClose()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> IRegion secondaryContentRegion = RegionManager.Regions[<span class="str">"SecondaryContent"</span>];</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">foreach</span> (var view <span class="kwrd">in</span> secondaryContentRegion.Views)</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">if</span> (view <span class="kwrd">is</span> CustomerEditView && ((FrameworkElement)view).DataContext == <span class="kwrd">this</span>)</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> secondaryContentRegion.Remove(view);</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> Commands.SaveAllCommand.UnregisterCommand(SaveCommand);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd">break</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> }</pre> <!--CRLF--></div> </div> <p>At this point you should be able to run the application and open several edit views as shown in Figure 3. Initially all of the Save buttons in the edit views as well as the Save All button will be disabled because none of the views are dirty. Go make an edit to each one of the views, and you will see their individual Save button become enabled. With the default CanExecute logic of the CompositeCommand, not until all of the child commands becomes enabled is the CompositeCommand itself enabled. So at the point where you have each of the child views Save enabled through an edit, the Save All button will become enabled. Clicking it invokes the SaveCommand handler in each instance of the CustomerEditViewModel, setting its IsDirty flag to false and raising the CanExecuteChanged handler for that command, which the CompositeCommand will monitor to refresh its own command enabled state.</p> <h3>Step 6: Add an Orders Module</h3> <p>A common usage of pub/sub events is to communicate between loosely coupled module components, particularly from one view model to another, especially if those view models are defined in separate modules. To demonstrate this, I want to add the capability to display the last 10 products ordered by a customer in a side panel whenever a customer is selected. I want this functionality to be decoupled from the customer listing and editing capabilities in the Core module, possibly developed by a separate team or added as a separate pluggable feature of the application.</p> <p>To do this, I added a new Orders module to the solution following the procedures outlined in the first article for defining a Prism module:</p> <ol> <li>Add a Silverlight Application project</li> <li>Delete MainPage.xaml and App.xaml</li> <li>Set the Startup Object in the project settings to Not Set.</li> <li>Add Prism references, setting the Copy Local property on  the references to false so that you don’t get multiple copies of the Prism libraries loaded when the module loads.</li> <li>Defined an OrdersModule class with a ModuleExport attribute and an implementation of the IModule interface.</li> <li>Added the Orders module to the Silverlight hosting settings of the Web project so that it is available for download by the module manager in Prism.</li> <li>Added module information to the ModuleCatalog.xaml in the shell project.</li> </ol> <p>Additionally, since now both the Core module and the Orders module will need to use WCF RIA Services to retrieve data from the back end, it makes sense to move the client WCF RIA Services code out to a shared library so that there is just one definition of the entity types and the DomainContext that lets the client code talk to the server. As a result, I also did the following in the solution:</p> <ol> <li>Removed the RIA Services link from all the client projects.</li> <li>Added a NorthwindRIAClientLibrary Silverlight Class Library project with the RIA Services link in the project properties set to the hosting web project where the domain services live.</li> <li>Added a reference to NorthwindRIAClientLibrary to each of the projects, with them all set to Copy Local = false except the reference in the shell application.</li> </ol> <h3> </h3> <h3>Step 7: Add another region for the view to plug into</h3> <p>In MainPage.xaml in the shell application, I added another region named SidePanel to the right of the listing of customers for the order summary to plug into.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd"><</span><span class="html">Grid.ColumnDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="*"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd"></</span><span class="html">Grid.ColumnDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd"><</span><span class="html">ContentControl</span> <span class="attr">prism:RegionManager</span>.<span class="attr">RegionName</span><span class="kwrd">="MainContent"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd"><</span><span class="html">ContentControl</span> <span class="attr">prism:RegionManager</span>.<span class="attr">RegionName</span><span class="kwrd">="SidePanel"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> <span class="attr">Margin</span><span class="kwrd">="5"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <h3> </h3> <h3>Step 8: Add a View and ViewModel to present the order summary</h3> <p>The view simply contains a DataGrid with three columns: Order date, product name, and quantity. The view model uses WCF RIA Services to retrieve the order information for a given customer and populate a collection of OrderItem data structures to populate the DataGrid with the three columns.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> OrdersViewModel : INotifyPropertyChanged</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> CustomersDomainContext _Context;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">public</span> OrdersViewModel()</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">if</span> (!DesignerProperties.IsInDesignTool)</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> _Context = <span class="kwrd">new</span> CustomersDomainContext();</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> ObservableCollection<OrderItem> _Orders = <span class="kwrd">new</span> ObservableCollection<OrderItem>();</pre> <!--CRLF--> <pre class="alt"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd">public</span> ObservableCollection<OrderItem> Orders</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum15" class="lnum"> 15:</span> get { <span class="kwrd">return</span> _Orders; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> set</pre> <!--CRLF--> <pre class="alt"><span id="lnum17" class="lnum"> 17:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="kwrd">if</span> (_Orders != <span class="kwrd">value</span>)</pre> <!--CRLF--> <pre class="alt"><span id="lnum19" class="lnum"> 19:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> _Orders = <span class="kwrd">value</span>;</pre> <!--CRLF--> <pre class="alt"><span id="lnum21" class="lnum"> 21:</span> PropertyChanged(<span class="kwrd">this</span>, <span class="kwrd">new</span> PropertyChangedEventArgs(<span class="str">"Orders"</span>));</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum23" class="lnum"> 23:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum25" class="lnum"> 25:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> OnCustomerSelected(Customer cust)</pre> <!--CRLF--> <pre class="alt"><span id="lnum27" class="lnum"> 27:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> Orders = <span class="kwrd">new</span> ObservableCollection<OrderItem>();</pre> <!--CRLF--> <pre class="alt"><span id="lnum29" class="lnum"> 29:</span> <span class="kwrd">if</span> (_Context == <span class="kwrd">null</span> || cust == <span class="kwrd">null</span>)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum31" class="lnum"> 31:</span> <span class="kwrd">return</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum33" class="lnum"> 33:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> EntityQuery<Order_Detail> detailQuery = _Context.GetOrder_DetailsQuery();</pre> <!--CRLF--> <pre class="alt"><span id="lnum35" class="lnum"> 35:</span> _Context.Load(detailQuery.Where(</pre> <!--CRLF--> <pre class="alteven"><span id="lnum36" class="lnum"> 36:</span> det => det.Order.Customer.CustomerID == cust.CustomerID).OrderByDescending(</pre> <!--CRLF--> <pre class="alt"><span id="lnum37" class="lnum"> 37:</span> det => det.Order.OrderDate).Take(10), OnDetailsLoaded, <span class="kwrd">null</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum38" class="lnum"> 38:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum39" class="lnum"> 39:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum40" class="lnum"> 40:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum41" class="lnum"> 41:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnDetailsLoaded(LoadOperation<Order_Detail> loadOp)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum42" class="lnum"> 42:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum43" class="lnum"> 43:</span> var details = loadOp.Entities;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum44" class="lnum"> 44:</span> <span class="kwrd">if</span> (details != <span class="kwrd">null</span>)</pre> <!--CRLF--> <pre class="alt"><span id="lnum45" class="lnum"> 45:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum46" class="lnum"> 46:</span> var detailsList = details.ToList();</pre> <!--CRLF--> <pre class="alt"><span id="lnum47" class="lnum"> 47:</span> detailsList.ForEach(det => Orders.Add(</pre> <!--CRLF--> <pre class="alteven"><span id="lnum48" class="lnum"> 48:</span> <span class="kwrd">new</span> OrderItem</pre> <!--CRLF--> <pre class="alt"><span id="lnum49" class="lnum"> 49:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum50" class="lnum"> 50:</span> ProductName = det.Product.ProductName,</pre> <!--CRLF--> <pre class="alt"><span id="lnum51" class="lnum"> 51:</span> Quantity = det.Quantity,</pre> <!--CRLF--> <pre class="alteven"><span id="lnum52" class="lnum"> 52:</span> OrderDate = det.Order.OrderDate.Value</pre> <!--CRLF--> <pre class="alt"><span id="lnum53" class="lnum"> 53:</span> }));</pre> <!--CRLF--> <pre class="alteven"><span id="lnum54" class="lnum"> 54:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum55" class="lnum"> 55:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum56" class="lnum"> 56:</span> }</pre> <!--CRLF--></div> </div> <p>Now the only thing left to do is call the OnCustomerSelected method whenever a Customer is selected in the main listing. But that code lives in a totally separate module that you are trying to keep decoupled. Prism events to the rescue.</p> <h3>Step 9: Add a Prism Event</h3> <p>When working with Prism events, the first thing to do is to declare the event type. You do this by deriving a type from CompositePresentationEvent as described earlier, and indicating through the generic type argument what the payload type will be:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> CustomerSelectedEvent : CompositePresentationEvent<Customer> { }</pre> <!--CRLF--></div> </div> <p>Like the CompositeCommand, this type will need to be referenced by both sides of the communication, even though those two sides need to be decoupled from each other. So this is another one of those types you will want to declare in a shared library that any modules in the solution can reference.</p> <h3>Step 10: Hook up the subscriber</h3> <p>To hook up a subscriber, the subscribing code first needs access to the EventAggregator service in Prism. This is a singleton service like the RegionManager that you can simply obtain by using dependency injection and importing it through the container. Add the following code to the OrdersViewModel:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> OrdersViewModel()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">if</span> (!DesignerProperties.IsInDesignTool)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> {</pre> <!--CRLF--> <pre class="alt"><span id="lnum5" class="lnum"> 5:</span> CompositionInitializer.SatisfyImports(<span class="kwrd">this</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> EventAggregator.GetEvent<CustomerSelectedEvent>().Subscribe(OnCustomerSelected);</pre> <!--CRLF--> <pre class="alt"><span id="lnum7" class="lnum"> 7:</span> _Context = <span class="kwrd">new</span> CustomersDomainContext();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> }</pre> <!--CRLF--> <pre class="alt"><span id="lnum9" class="lnum"> 9:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span>  </pre> <!--CRLF--> <pre class="alt"><span id="lnum11" class="lnum"> 11:</span> [Import]</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="kwrd">public</span> IEventAggregator EventAggregator { get; set; }</pre> <!--CRLF--></div> </div> <p>Because the view model will be constructed in the XAML of the view, the container will not be involved in its construction. To get the container to satisfy the imports in the class, which in this case includes the event aggregator, the CompositionInitializer class can be used. It is put in a guard condition as discussed in a previous article so that the designer does not break since it should not execute that code in the designer.</p> <p>After the SatisfyImports call, the Import property will be set by the container. So the next line of code can then use that IEventAggregator reference to subscribe. That involves calling the GetEvent<T>() method to get a reference to the event, then calling subscribe on the returned event, which can be done in a single line of code as shown. The Subscribe method just takes an Action<T> delegate, where T is the payload type defined by the event class. The OnCustomerSelected method was shown earlier. </p> <p>By default, Prism events maintain weak references to the subscribing class method. That means that if all other references to the object go away, the event reference will not keep it alive. This solves a lot of memory leak issues where you either forget or it is difficult to know where in the code to do the Unsubscribe call. If you want the event subscription to keep the object alive, there is an overload to the Subscribe method with a keepSubscriberReferenceAlive bool parameter.</p> <p>Additionally, by default the event publication will happen synchronously using the publisher’s thread. If you want control over what thread is used to call the target method pointed to by the Subscribe call, you can use another overload that takes a ThreadOption with three choices: use the Publisher’s thread (the default), use the UI thread, or use a background thread from the thread pool.</p> <p>Finally, there is an overload that also allows you to pass a Predicate<T> delegate for filtering purposes. This allows you to pass a lambda expression or point to a method that returns a boolean. The method or lambda will be passed the payload object of the event. It can use that to decide whether to return true or false. True means to call the subscription method, false means don’t.</p> <h3>Step 11: Publish the event</h3> <p>To publish a Prism event, it is just as simple as subscribing. you first need a reference to the EventAggregator service, which you get through dependency injection as shown earlier. Then you publish at the appropriate point in your code calling the Publish method on the event returned from the same GetEvent<T>() method shown earlier:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alt"><span id="lnum1" class="lnum"> 1:</span> EventAggregator.GetEvent<CustomerSelectedEvent>().Publish(_SelectedCustomer);</pre> <!--CRLF--></div> </div> <h3>Summary</h3> <p>In this article, you saw how to define multiple modules that can communicate with each other through a combination of CompositeCommands and Prism events. CompositeCommands let you have handlers registered or unregistered in a loosely coupled fashion, and allows you to have multiple handlers (child commands) that will be used by the CompositeCommand. Prism events are for situations that are not necessarily an action->reaction kind of set up where enablement and disablement is needed. You simply define the event type with its strongly typed payload and then subscribe or publish by obtaining the event reference through the EventAggregator. Both of these mechanisms give you a really powerful combination for having loosely coupled communications between composite parts of your application.</p> <p>You can <a href="http://www.silverlightshow.net/Storage/Sources/Prism4CompositeCommandAndEventsSample.zip">download the finished code from this article here</a>.</p> <h3>About the Author</h3> <p>Brian Noyes is Chief Architect of <a href="http://www.idesign.net/" target="_blank">IDesign</a>, a Microsoft Regional Director, and Silverlight MVP. He is a frequent top rated speaker at conferences worldwide including Microsoft TechEd, DevConnections, VSLive!, DevTeach, and others. Brian worked directly on the Prism team with Microsoft patterns and practices and co-authored the book Developers Guide to Microsoft Prism 4. He is also the author of Developing Applications with Windows Workflow Foundation, Smart Client Deployment with ClickOnce, and Data Binding in Windows Forms 2.0. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at <a href="http://briannoyes.net/">http://briannoyes.net/</a> or on Twitter @briannoyes.</p> http://www.silverlightshow.net/items/Working-with-Prism-4-Part-3-Composite-Command-and-Pub-Sub-Events.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/Working-with-Prism-4-Part-3-Composite-Command-and-Pub-Sub-Events.aspx#comments http://www.silverlightshow.net/items/Working-with-Prism-4-Part-3-Composite-Command-and-Pub-Sub-Events.aspx Tue, 24 Jan 2012 10:10:00 GMT Working with Prism 4 Part 2: MVVM Basics and Commands <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-2-MVVM-Basics-and-Commands.aspx" data-font="segoe ui" data-layout="button_count"></div> </td> <td><a href="https://twitter.com/share" class="twitter-share-button" data-via="silverlightshow" data-counturl="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-2-MVVM-Basics-and-Commands.aspx" data-count="horizontal" data-text="Reading SilverlightShow article 'Working w/ Prism 4: MVVM Basics and Commands' by @briannoyes" data-url="http://slshow.net/vLP4um">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-2-MVVM-Basics-and-Commands.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p>This is Part 2 in the series Working with Prism 4.</p> <h3>Introduction</h3> <p>In the <a href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-1-Getting-Started.aspx" target="_self">first part of this series</a>, I introduced you to the concepts of Prism 4 – what the toolkit is for, as well as what the top level features are. Additionally, I stepped through the basic setup of getting a Prism application up and running – creating the shell project, a module, declaring a region in the shell, and plugging a view into that region from the module.</p> <div style="border:1px solid #dddddd;border-image: initial; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>More resources...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Webinars.aspx">Upcoming SilverlightShow Webinars</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/WCF-RIA-Services-Webinar-4.aspx">Recordings of the Webinar Series: WCF RIA Services</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/prism4.aspx">The Prism 4 Series is also available as an Ebook:</a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/prism4.aspx"><img style="border:0px solid; border-image: initial; width: 121px; height: 170px;" alt="Working with Prism 4 - ebook by Brian Noyes" src="http://www.silverlightshow.net/Storage/Ebooks/prism.png" usemap="#rade_img_map_1291385581316" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>In this article, I will flesh out that application a little more and show you some of the basic support for the Model-View-ViewModel (MVVM) pattern that Prism has, as well as how to use the <strong>DelegateCommand</strong> type that Prism provides, which fits well with MVVM scenarios. An important thing to understand is that Prism is not first-and-foremost an MVVM framework. It is a toolkit for building composite applications, which may or may not choose to use the MVVM pattern. As a result, there is not a ton of framework infrastructure provided in Prism that is specifically focused on MVVM. There are other good toolkits out there, such as the <a href="http://mvvmlight.codeplex.com/" target="_blank">MVVM Light</a> or <a href="http://caliburnmicro.codeplex.com/" target="_blank">Caliburn Micro</a> toolkits that can be used in conjunction with Prism or instead of Prism if your primary goal is just to put together an MVVM application. However, I have found the combination of features of Prism for composition and MVVM to be more than sufficient for many big and small real world applications, so I usually just use Prism on its own without mixing in other toolkits, and I will keep the focus just on Prism in these articles. </p> <p>This article will build on the sample application developed in Part 1. You can <a href="http://www.silverlightshow.net/Storage/Sources/Prism101Part1.zip" target="_blank">download the starting point code from Part 1 here</a>. You can <a href="http://www.silverlightshow.net/Storage/Sources/Prism4MVVMAndCommandsSamplePart2.zip">download the finished sample for this article here</a>.</p> <h3>MVVM Basics</h3> <p>I don’t intend this article to be a starting point for learning the MVVM pattern. There are many other good resources out there for that, including the <a href="http://msdn.microsoft.com/en-us/magazine/dd419663.aspx" target="_blank">excellent article by Josh Smith</a> and the two chapters we wrote in the <a href="http://my.safaribooksonline.com/book/programming/microsoft-wpf/9780735660663" target="_blank">Prism book</a> which is also <a href="http://msdn.microsoft.com/en-us/library/gg406140.aspx" target="_blank">available online in various electronic forms</a>. But just so you don’t have to go brush up on MVVM too much to follow along with what I will show in this article, here are the key essentials.</p> <p>MVVM is a UI separation pattern for keeping the structural aspects of the UI (the XAML elements that you see on the screen) separated from the state and logic that supports that view. The view is just the structure of what you see on the screen. It may contain some dynamic elements such as animations, but it has no logic defining the behavior of the application from a user interaction perspective. Ideally in an MVVM application, there is no code in the code-behind class of a XAML view, just the constructor with its <strong>InitializeComponent</strong> method call. The state (data) that is presented in the view is provided and manipulated by the view model, and interactions from the user such as selections, button presses, etc. are handled in the view model. The data that the user interacts with is stored in the model, which may not structure the data exactly as it is shown on the screen. The model data structures should be chosen based on the needs of the application as a whole. Another responsibility of the view model is to transform, as necessary, the data from the way the model wants to store and manipulate it to the shape that the view wants to see the data in.</p> <p>The basic structure of MVVM is that the view’s <strong>DataContext</strong> property at the root of the view will be set to an instance of the view model (View.DataContext = ViewModel). There is typically a 1:1 relationship of the class defined for the view and the class defined for the view model – for example a <strong>CustomerListView</strong> will have a <strong>CustomerListViewModel</strong>. But there are situations where one view model definition might support more than one view or vice versa. But at runtime, the view’s <strong>DataContext</strong> gets set to a reference to some view model instance that will provide its data and interaction logic. There are many ways the <strong>DataContext</strong> of the view can get set to an instance of a view model. In this article I will just focus on a couple of those, specifically hooking them up statically from the XAML of the view or using <strong>DataTemplates</strong>. But you can find many other variants out there in samples of ways to get the two hooked up to one another.</p> <p>To hook up a view to its view model statically from the XAML, you simply create an instance of it in the XAML like the following snippet:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">UserControl</span> <span class="attr">x:Class</span><span class="kwrd">="Prism101.Modules.Core.CustomerListView"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> ...</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">xmlns:local</span><span class="kwrd">="clr-namespace:Prism101.Modules.Core"</span> ...<span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd"><</span><span class="html">UserControl.DataContext</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd"><</span><span class="html">local:CustomerListViewModel</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd"></</span><span class="html">UserControl.DataContext</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>To use a <strong>DataTemplate</strong> to get them hooked up, you bind something in a parent view (typically a <strong>ContentControl</strong> or <strong>ItemsControl</strong>) to an instance of the view model whose view you want to render. Then you define a data template in the resources of the parent view that ties the view and view model together, and through the way <strong>DataTemplates</strong> work, sets the <strong>DataContext</strong> of the rendered view to the bound instance of the view model.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">UserControl</span> <span class="attr">x:Class</span><span class="kwrd">="Prism101.Modules.Core.ParentView"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> ...</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">xmlns:local</span><span class="kwrd">="clr-namespace:Prism101.Modules.Core"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> ...<span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd"><</span><span class="html">UserControl.Resources</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd"><</span><span class="html">DataTemplate</span> <span class="attr">DataType</span><span class="kwrd">="local:CustomerListViewModel"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd"><</span><span class="html">local:CustomerListView</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd"></</span><span class="html">DataTemplate</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum9" class="lnum"> 9:</span> <span class="kwrd"></</span><span class="html">UserControl.Resources</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">="LayoutRoot"</span> <span class="attr">Background</span><span class="kwrd">="White"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd"><</span><span class="html">ContentControl</span> <span class="attr">Content</span><span class="kwrd">="{Binding ChildViewModel}"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> ...</pre> <!--CRLF--></div> </div> <h3>Commanding Basics</h3> <p>Commands in WPF and Silverlight are based on the <a href="http://en.wikipedia.org/wiki/Design_Patterns" target="_blank">Gang of Four</a> <a href="http://en.wikipedia.org/wiki/Command_pattern" target="_blank">Command</a> design pattern. With commands you have an invoker and a receiver and some infrastructure in between to keep those two parties decoupled from one another as much as possible. The invoker is typically a UI element of some sort like a button, menu, or possibly a <strong>ComboBox</strong> selection. The receiver is the handling code that takes some action based on the command being invoked. With traditional code-behind event handling of UI control events, the event handling code represented that receiver code, but it was tightly coupled to the UI element event and had to be co-located in the code behind of the view to work. With commands, particularly with the support of bindings in WPF and Silverlight, and with dependency injection support in Prism, you can have the command invoker and receiver be very loosely coupled from one another – often defined in separate modules that have no references to one another or knowledge of each other’s presence.</p> <p>Prism has two command types I’ll be covering in this series: the <strong>DelegateCommand</strong> type which is perfect for hooking up interaction logic between an MVVM view and its view model, and the <strong>CompositeCommand</strong>, which supports more loosely coupled, cross-module kinds of communication. Both are implementations of the <strong>ICommand</strong> interface defined in WPF and Silverlight, which defines three members: an <strong>Execute</strong> method, a <strong>CanExecute</strong> method, and a <strong>CanExecuteChanged</strong> event. The <strong>Execute</strong> method is the crux of the <strong>ICommand</strong> interface, it is what will be invoked whenever the invoker element has the triggering action happen to it (i.e. a button is clicked that has a command hooked up to it). The <strong>CanExecute</strong> method can be optionally hooked up to conditionally say whether the associated invoker should be enabled or not – for example if a document is not dirty, the Save command should be disabled. The associated <strong>CanExecuteChanged</strong> event is a way for the supporting logic that determines whether the command should be enabled to notify the invoker that it should re-evaluate the <strong>CanExecute</strong> state of the command and update the UI appropriately as things are changing behind the scenes (i.e. the document just went dirty because the user input some text or some other formatting command was invoked on the document that the Save command relates to).</p> <h3>Step 1: Getting Some Data Into the Application</h3> <p>Message boxes and Hello World prompts can only keep your attention for so long. So the first thing I am going to do is to use some Northwind data to add a little more real world structure to the application that I will be expanding on in this article. The sample code for this article includes a SQL script for creating the Northwind DB on your machine (assumes you have SQL Server on your machine in one of its forms). Additionally, the sample code has a WCF RIA Services domain service added to the host Web project to make it easy to retrieve and update the Northwind data from the Silverlight sample application. I am not going to go into any detail on the structure of how to do that since I have covered it in detail in my article series on <a href="http://www.silverlightshow.net/items/WCF-RIA-Services-Part-1-Getting-Started.aspx" target="_blank">WCF RIA Services here</a>. </p> <p>The steps I followed for the Silverlight sample application here is as follows:</p> <ul> <li>Ran the SQL script to create a clean copy of the Northwind database on my machine. </li> <li>Added an ADO.NET Entity Data Model to the Prism101.Web project from the Data project item templates in the Add New Item dialog, using the Database-first model approach to generate an entity framework model including the Customers, Orders, and Order Details tables from the Northwind database. </li> <li>Build the project so that the next step will see the EF model. </li> <li>Add a Domain Service Class to the Prism101.Web project from the Web project item templates in the Add New Item dialog, naming it <strong>CustomersDomainService</strong>. In the wizard, I selected those same three tables from the entity model. </li> <li>Build the project so that it code generates the client side support for consuming the domain service and the client side entity types. </li> </ul> <h3>Step 2: Creating a CustomerListView</h3> <p>To get started with some MVVM views, I will replace the <strong>WelcomeView</strong> view that was plugged in from the Core module in the last article with a <strong>CustomerListView</strong> with a supporting view model.</p> <p>In the Prism101.Modules.Core project, add a new Silverlight User Control to the project and name it <strong>CustomerListView</strong>. With the designer showing in the editor, bring up the Data Sources window (Data menu, Show Data Sources). This allows you to code generate user interface controls and have the bindings for them set up (at least partially) from data types in your application. I wrote about these features in details in my book <a href="http://www.amazon.com/Data-Binding-Windows-Forms-2-0/dp/032126892X" target="_blank">Data Binding with Windows Forms 2.0</a> a long time ago, but you can find a more recent coverage in this <a href="http://www.google.com/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=10&sqi=2&ved=0CHgQFjAJ&url=http%3A%2F%2Faz12722.vo.msecnd.net%2Fvs2010trainingcourse2-0%2Flabs%2Fwpf4datadrivenmasterdetailbusinessform1-1-0%2FWPF4DataDrivenMasterDetailBusinessForm.docx&ei=1bvHTqDeNuPW0QHLneUX&usg=AFQjCNHsE0J_iuJr2A3qSjUa8WW3sGAngA" target="_blank">Hands on Lab from Microsoft for WPF</a>.</p> <p>After a moment, if you have done the steps in Step 1, you should see the Data Sources window populate with the <strong>Customer</strong>, <strong>Order</strong>, and <strong>Order_Detail</strong> types.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/__Figure1_2.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="Figure1" alt="Figure1" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/__Figure1_thumb.png" width="244" height="182" /></a></p> <p>If you drag and drop the Customer type from this window into the Grid in the designer, it will code generate a <strong>DataGrid</strong> with the appropriate columns based on the properties of the <strong>Customer</strong> entity. Because these entities are generated by RIA Services, it will also add some additional stuff into the XAML that I stripped out to transform it into an MVVM structure, specifically a <strong>DomainDataSource</strong>. I did some other clean up in the sample code to reorder the columns from the order they were generated in. But after the cleanup, the XAML looks like that shown in the following code listing.</p> <div id="codeSnippetWrapper" class="csharpcode-wrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">UserControl</span> <span class="attr">x:Class</span><span class="kwrd">="Prism101.Modules.Core.CustomerListView"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">xmlns</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">xmlns:x</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="attr">xmlns:d</span><span class="kwrd">="http://schemas.microsoft.com/expression/blend/2008"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> <span class="attr">xmlns:mc</span><span class="kwrd">="http://schemas.openxmlformats.org/markup-compatibility/2006"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="attr">xmlns:sdk</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum7" class="lnum"> 7:</span> <span class="attr">mc:Ignorable</span><span class="kwrd">="d"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="attr">d:DesignHeight</span><span class="kwrd">="300"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum9" class="lnum"> 9:</span> <span class="attr">d:DesignWidth</span><span class="kwrd">="400"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">="LayoutRoot"</span> <span class="attr">Background</span><span class="kwrd">="White"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd"><</span><span class="html">sdk:DataGrid</span> <span class="attr">ItemsSource</span><span class="kwrd">="{Binding Customers}"</span> </pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> <span class="attr">AutoGenerateColumns</span><span class="kwrd">="False"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum13" class="lnum"> 13:</span> <span class="attr">Name</span><span class="kwrd">="customerDataGrid"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="attr">RowDetailsVisibilityMode</span><span class="kwrd">="VisibleWhenSelected"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd"><</span><span class="html">sdk:DataGrid.Columns</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd"><</span><span class="html">sdk:DataGridTextColumn</span> <span class="attr">x:Name</span><span class="kwrd">="customerIDColumn"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum17" class="lnum"> 17:</span> <span class="attr">Binding</span><span class="kwrd">="{Binding Path=CustomerID, Mode=OneWay}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="attr">Header</span><span class="kwrd">="Customer ID"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum19" class="lnum"> 19:</span> <span class="attr">IsReadOnly</span><span class="kwrd">="True"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> <span class="attr">Width</span><span class="kwrd">="SizeToHeader"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum21" class="lnum"> 21:</span> <span class="kwrd"><</span><span class="html">sdk:DataGridTextColumn</span> <span class="attr">x:Name</span><span class="kwrd">="companyNameColumn"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> <span class="attr">Binding</span><span class="kwrd">="{Binding Path=CompanyName}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum23" class="lnum"> 23:</span> <span class="attr">Header</span><span class="kwrd">="Company Name"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> <span class="attr">Width</span><span class="kwrd">="SizeToHeader"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum25" class="lnum"> 25:</span> <span class="kwrd"><</span><span class="html">sdk:DataGridTextColumn</span> <span class="attr">x:Name</span><span class="kwrd">="contactNameColumn"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span> <span class="attr">Binding</span><span class="kwrd">="{Binding Path=ContactName}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum27" class="lnum"> 27:</span> <span class="attr">Header</span><span class="kwrd">="Contact Name"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> <span class="attr">Width</span><span class="kwrd">="SizeToHeader"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum29" class="lnum"> 29:</span> <span class="kwrd"><</span><span class="html">sdk:DataGridTextColumn</span> <span class="attr">x:Name</span><span class="kwrd">="contactTitleColumn"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> <span class="attr">Binding</span><span class="kwrd">="{Binding Path=ContactTitle}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum31" class="lnum"> 31:</span> <span class="attr">Header</span><span class="kwrd">="Contact Title"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> <span class="attr">Width</span><span class="kwrd">="SizeToHeader"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum33" class="lnum"> 33:</span> <span class="kwrd"><</span><span class="html">sdk:DataGridTextColumn</span> <span class="attr">x:Name</span><span class="kwrd">="phoneColumn"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> <span class="attr">Binding</span><span class="kwrd">="{Binding Path=Phone}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum35" class="lnum"> 35:</span> <span class="attr">Header</span><span class="kwrd">="Phone"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum36" class="lnum"> 36:</span> <span class="attr">Width</span><span class="kwrd">="SizeToHeader"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum37" class="lnum"> 37:</span> <span class="kwrd"><</span><span class="html">sdk:DataGridTextColumn</span> <span class="attr">x:Name</span><span class="kwrd">="faxColumn"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum38" class="lnum"> 38:</span> <span class="attr">Binding</span><span class="kwrd">="{Binding Path=Fax}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum39" class="lnum"> 39:</span> <span class="attr">Header</span><span class="kwrd">="Fax"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum40" class="lnum"> 40:</span> <span class="attr">Width</span><span class="kwrd">="SizeToHeader"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum41" class="lnum"> 41:</span> <span class="kwrd"><</span><span class="html">sdk:DataGridTextColumn</span> <span class="attr">x:Name</span><span class="kwrd">="addressColumn"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum42" class="lnum"> 42:</span> <span class="attr">Binding</span><span class="kwrd">="{Binding Path=Address}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum43" class="lnum"> 43:</span> <span class="attr">Header</span><span class="kwrd">="Address"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum44" class="lnum"> 44:</span> <span class="attr">Width</span><span class="kwrd">="SizeToHeader"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum45" class="lnum"> 45:</span> <span class="kwrd"><</span><span class="html">sdk:DataGridTextColumn</span> <span class="attr">x:Name</span><span class="kwrd">="cityColumn"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum46" class="lnum"> 46:</span> <span class="attr">Binding</span><span class="kwrd">="{Binding Path=City}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum47" class="lnum"> 47:</span> <span class="attr">Header</span><span class="kwrd">="City"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum48" class="lnum"> 48:</span> <span class="attr">Width</span><span class="kwrd">="SizeToHeader"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum49" class="lnum"> 49:</span> <span class="kwrd"><</span><span class="html">sdk:DataGridTextColumn</span> <span class="attr">x:Name</span><span class="kwrd">="countryColumn"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum50" class="lnum"> 50:</span> <span class="attr">Binding</span><span class="kwrd">="{Binding Path=Country}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum51" class="lnum"> 51:</span> <span class="attr">Header</span><span class="kwrd">="Country"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum52" class="lnum"> 52:</span> <span class="attr">Width</span><span class="kwrd">="SizeToHeader"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum53" class="lnum"> 53:</span> <span class="kwrd"><</span><span class="html">sdk:DataGridTextColumn</span> <span class="attr">x:Name</span><span class="kwrd">="postalCodeColumn"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum54" class="lnum"> 54:</span> <span class="attr">Binding</span><span class="kwrd">="{Binding Path=PostalCode}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum55" class="lnum"> 55:</span> <span class="attr">Header</span><span class="kwrd">="Postal Code"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum56" class="lnum"> 56:</span> <span class="attr">Width</span><span class="kwrd">="SizeToHeader"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum57" class="lnum"> 57:</span> <span class="kwrd"></</span><span class="html">sdk:DataGrid.Columns</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum58" class="lnum"> 58:</span> <span class="kwrd"></</span><span class="html">sdk:DataGrid</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum59" class="lnum"> 59:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum60" class="lnum"> 60:</span> <span class="kwrd"></</span><span class="html">UserControl</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>You can see that the code just contains a <strong>DataGrid</strong> and its columns for the properties of a <strong>Customer</strong>. I’ve modified it to assume that the <strong>DataContext</strong> of the view has a property called <strong>Customers</strong> that the <strong>DataGrid.ItemsSource</strong> property is bound to. There is also a Loaded event handler for the <strong>DomainDataSource</strong> that is added into the code behind of the view from the Data Sources window drag/drop operation that I stripped out after deleting the <strong>DomainDataSource</strong>.</p> <h3>Step 3: Replace WelcomeView with CustomerListView</h3> <p>Open the <strong>CoreModule</strong> class in the Prism101.Modules.Core project and replace the creation of the <strong>WelcomeView</strong> with the <strong>CustomerListView</strong>.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> Initialize()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> var view = <span class="kwrd">new</span> CustomerListView();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> RegionManager.AddToRegion(<span class="str">"MainContent"</span>, view);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> }</pre> <!--CRLF--></div> </div> <p>You can now delete the <strong>WelcomeView.xaml</strong> from that project. You should be able to build and run at this point and see that the grid shows up in the MainContent region in the shell now instead of the Hello Prism of the <strong>WelcomeView</strong>. This helps to emphasize that when using regions in Prism, the hosting view that contains a region does not need to be touched to completely alter its content, you just change what is being plugged into that container.</p> <h3>Step 4: Add a View Model</h3> <p>Add a class named <strong>CustomerListViewModel</strong> to the Prism101.Modules.Core project. Add the following code to that class.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> CustomerListViewModel : NotificationObject</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> CustomersDomainContext _Context = <span class="kwrd">new</span> CustomersDomainContext();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> IEnumerable<Customer> _Customers;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">public</span> CustomerListViewModel()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum7" class="lnum"> 7:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd">if</span> (!DesignerProperties.IsInDesignTool)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum9" class="lnum"> 9:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> _Context.Load(_Context.GetCustomersQuery(), OnLoadComplete, <span class="kwrd">null</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum11" class="lnum"> 11:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum13" class="lnum"> 13:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="kwrd">public</span> IEnumerable<Customer> Customers</pre> <!--CRLF--> <pre class="alteven"><span id="lnum15" class="lnum"> 15:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> get { <span class="kwrd">return</span> _Customers; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum17" class="lnum"> 17:</span> set</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum19" class="lnum"> 19:</span> <span class="kwrd">if</span> (_Customers != <span class="kwrd">value</span>)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum21" class="lnum"> 21:</span> _Customers = <span class="kwrd">value</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> RaisePropertyChanged(() => Customers);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum23" class="lnum"> 23:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum25" class="lnum"> 25:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum27" class="lnum"> 27:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnLoadComplete(LoadOperation<Customer> loadOp)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum29" class="lnum"> 29:</span> <span class="kwrd">if</span> (loadOp.HasError)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum31" class="lnum"> 31:</span> MessageBox.Show(loadOp.Error.Message);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> loadOp.MarkErrorAsHandled();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum33" class="lnum"> 33:</span> <span class="kwrd">return</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum35" class="lnum"> 35:</span> Customers = _Context.Customers;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum36" class="lnum"> 36:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum37" class="lnum"> 37:</span> }</pre> <!--CRLF--></div> </div> <div>The view model provides the <strong>Customers</strong> collection of data that the view wants to bind to. It does that by having WCF RIA Services make a call to the back end and load the customer data using the <strong>CustomersDomainContext</strong> that is a member of the view model, then exposes the resulting customer data through a property on the view model that the view will bind to. The <strong>CustomersDomainContext</strong> is part of the code generated client code for RIA Services that acts as a proxy to the server side domain service. You can see that the Load call is an asynchronous service calls with a callback hooked up to the <strong>OnLoadComplete</strong> method to handle errors and to populate the Customers collection property once the call is complete.</div> <div> </div> <div>There are a couple of important things to point out about this code. One is that in the next step I will be hooking this view model up to the view statically. That means it will get created in the designer as well. The WCF RIA Service calls to load data are not going to work in the designer. Often you will have things in your view model initialization or construction that will break the designer. To guard against this, you can use the <strong>DesignerProperties</strong> class to avoid executing that code if you are in the designer. So the call to the <strong>CustomerDomainContext.Load</strong> method is only done at runtime, not at design time.</div> <div> </div> <div>Another is to notice the base class that I added to the view model class – <strong>NotificationObject</strong>. This is a base class that Prism provides that encapsulates the implementation of the <strong>INotifyPropertyChanged</strong> interface, which is important for your view models to support for the properties they expose. The base class exposes several overloaded <strong>RaisePropertyChanged</strong> methods you can call from your property set{} blocks to make sure that bindings in the view are refreshed when the underlying properties change. The call to <strong>RaisePropertyChanged</strong> in the Customers property set{} block shows that the Prism base class supporting using strongly typed lambda expressions to point to the property (Customers) itself, instead of using a string for the name of the property as is normally done when raising the <strong>PropertyChanged</strong> event directly. This makes the code more maintainable because refactoring the property name will update the <strong>RaisePropertyChanged</strong> calls as well. If declared as a string, it may not be picked up depending on what refactoring tools you use.</div> <div> </div> <h3>Step 5: Hook the view up to the view model</h3> <div>Add a XAML namespace to the <strong>CustomerListView</strong> so it has access to the types in its own assembly:</div> <div> </div> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> xmlns:local="clr-namespace:Prism101.Modules.Core"</pre> <!--CRLF--></div> </div> <p>Then set the <strong>DataContext</strong> of the view in the XAML to an instance of the view model as shown earlier:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">UserControl.DataContext</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd"><</span><span class="html">local:CustomerListViewModel</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd"></</span><span class="html">UserControl.DataContext</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <div>You should now be able to run and see the data pop into the view after the asynchronous call completes.</div> <div> </div> <div><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/_Figure2_2.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="Figure2" alt="Figure2" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/_Figure2_thumb.png" width="547" height="318" /></a></div> <div> </div> <div>This structuring of view and view model is often referred to as “view-first”, because the view is constructed, and then it constructs and wires up its own view model (either from XAML as done here or from code behind). View-first has advantages of simplicity as well as the fact that you can leverage the design time data support of Visual Studio and Expression Blend.</div> <div> </div> <h3>Step 6: Adding an Edit Command</h3> <div>To demonstrate using <strong>DelegateCommands</strong> to hook up communication between our view and view model for some interaction logic as well as navigating to another view using regions, I will modify the <strong>CustomerListView</strong> slightly to add an Edit button to the top of the form.</div> <div> </div> <div>The XAML for the button looks like this.</div> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">Button</span> <span class="attr">Content</span><span class="kwrd">="Edit"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">Command</span><span class="kwrd">="{Binding EditCustomerCommand}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">Height</span><span class="kwrd">="23"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Top"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="attr">Width</span><span class="kwrd">="75"</span> <span class="kwrd">/></span></pre> <!--CRLF--></div> </div> <div>Notice the binding on the <strong>Command</strong> property assumes there is a property on the <strong>DataContext</strong> (the view model) named <strong>EditCustomerCommand</strong>. Buttons in Silverlight and WPF have a <strong>Command</strong> property that can point to an instance of an <strong>ICommand</strong> object. If that is hooked up, the button will be enabled or disabled based on calls to the <strong>CanExecute</strong> method of the <strong>ICommand</strong> interface as described earlier. Additionally, when the button is clicked, it will call the <strong>Execute</strong> method of the <strong>ICommand</strong> object.</div> <div> </div> <div>Rather than implementing <strong>ICommand</strong> directly on an object, a common approach is to use an intermediary class that implements <strong>ICommand</strong> to dispatch the calls to target methods on some other object, which in this case will be our view model. The first command type that Prism provides is the <strong>DelegateCommand</strong> class. To add this support, first we declare the property that the button Command binding points to in the <strong>CustomerListViewModel</strong> class, passing the target <strong>Execute</strong> and <strong>CanExecute</strong> handling methods through <a href="http://msdn.microsoft.com/en-us/magazine/cc163970.aspx#S10" target="_blank">delegate inference</a> to the constructor.</div> <div> </div> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> DelegateCommand EditCustomerCommand { get; <span class="kwrd">private</span> set; }</pre> <!--CRLF--></div> </div> <div>Next we populate that property in the constructor of the view model class:</div> <div> </div> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> CustomerListViewModel()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> EditCustomerCommand = <span class="kwrd">new</span> DelegateCommand(OnEditCustomer, CanEditCustomer);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> ...</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> }</pre> <!--CRLF--></div> </div> <p>Then we define the handling method that those point to.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">bool</span> CanEditCustomer()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">return</span> <span class="kwrd">true</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnEditCustomer()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum7" class="lnum"> 7:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> }</pre> <!--CRLF--></div> </div> <p>At this point you should be able to build and run, set a breakpoint in the <strong>OnEditCustomer</strong> method and see that your command handler is being called. Because right now the <strong>CanEditCustomer</strong> method returns true, the command will always be enabled. I will remedy that shortly.</p> <h3>Step 7: Pushing selection state into the view model</h3> <p>An important aspect of user interaction is selection in the view. But as mentioned before, in an MVVM design, all state and state manipulation should happen in the view model, not in the view. So when the user selects something in the view, the view model needs to know about it so it can take any appropriate action at that point, as well as making that selection available to command handling logic like our edit command.</p> <p>Add the following property to the <strong>CustomerListViewModel</strong>.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> Customer _SelectedCustomer;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd">public</span> Customer SelectedCustomer</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> get { <span class="kwrd">return</span> _SelectedCustomer; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> set</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd">if</span> (_SelectedCustomer != <span class="kwrd">value</span>)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum9" class="lnum"> 9:</span> _SelectedCustomer = <span class="kwrd">value</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> RaisePropertyChanged(() => SelectedCustomer);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum11" class="lnum"> 11:</span> EditCustomerCommand.RaiseCanExecuteChanged();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum13" class="lnum"> 13:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> }</pre> <!--CRLF--></div> </div> <p>Notice that in addition to doing raising the <strong>PropertyChanged</strong> event through the base class <strong>RaisePropertyChanged</strong> method, whenever the selected customer changes, the code makes a call to the <strong>EditCustomerCommand.RaiseCanExecuteChanged</strong> method. This causes the <strong>CanExecuteChanged</strong> event of the <strong>DelegateCommand’s</strong> implementation of <strong>ICommand</strong> to fire, which causes any command invoker such as our Edit button to update its enabled state by calling <strong>CanExecute</strong> again.</p> <p>Change the <strong>CanEditCustomer</strong> method to the following.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">bool</span> CanEditCustomer()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">if</span> (SelectedCustomer == <span class="kwrd">null</span>) <span class="kwrd">return</span> <span class="kwrd">false</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">else</span> <span class="kwrd">return</span> <span class="kwrd">true</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> }</pre> <!--CRLF--></div> </div> <p>Finally, on the <strong>DataGrid</strong> in the view, bind the <strong>SelectedItem</strong> property to the <strong>SelectedCustomer</strong> property in the view model.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">sdk:DataGrid</span> <span class="attr">ItemsSource</span><span class="kwrd">="{Binding Customers}"</span> </pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">SelectedItem</span><span class="kwrd">="{Binding Path=SelectedCustomer, Mode=TwoWay}"</span> ...<span class="kwrd">/></span></pre> <!--CRLF--></div> </div> <p>As a result of this change, the Edit button will now be disabled if there is no selection in the <strong>DataGrid</strong>. One the user selects a row in the <strong>DataGrid</strong>, the <strong>SelectedItem</strong> binding will push a reference to that Customer bound object into the <strong>SelectedCustomer</strong> property in the view model. That will fire the <strong>CanExecuteChanged</strong> event on the command, which will cause the button to requery <strong>CanExecute</strong>, and it will enable the button since the <strong>SelectedCustomer</strong> will no longer be null at that point.</p> <h3>Step 8: Define an edit view to switch to</h3> <p>As you have already seen with the <strong>MainContent</strong> region in <a href="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-1-Getting-Started.aspx" target="_blank">Part 1</a>, regions in Prism allow you to plug a view into a parent view’s region for presentation. This can be used to logically navigate the user from view to view. What I want to do when the edit command is invoked is to swap out the main view from presenting a list of customers to one that presents an edit form for the selected customer. To do this, I can just plug another view into the <strong>MainContent</strong> region, replacing the list view as the active view.</p> <p>A region is a logical container for a collection of views that can be presented within that region. You can add multiple views into the region, and depending on what kind of control the region is, it can present those views either one at a time or all at once. So far I am using a <strong>ContentControl</strong> in the MainPage.xaml shell view as the <strong>MainContent</strong> region. A <strong>ContentControl</strong> can only have a single child element as its <strong>Content</strong> at one time. But the Prism <strong>IRegion</strong> abstraction can keep track of a collection of views and set the appropriate view as the <strong>Content</strong> for that control when you tell it to. This concept is called activating a view in a region in Prism. The thing that actually maps the abstract region to a concrete container control is called a region adapters. There are built in region adapters supporting <strong>ContentControl</strong>, <strong>ItemsControl</strong>, and <strong>Selector</strong> controls in Prism.</p> <p>To switch to the edit view for a customer, we first have to have one. I won’t go through all the details of defining the <strong>CustomerEditView</strong>, that is Silverlight basics and is similar to what I described earlier for creating the <strong>CustomerListView</strong>. Instead of dragging and dropping the <strong>Customer</strong> type from the Data Sources window with the default settings, you drop down the selection on the <strong>Customer</strong> type in that window and select Details. Then when you do the drag and drop onto the designer, it generates a data form for a single instance of the type instead of a data grid for a collection of the type. I again trimmed out the <strong>DomainDataSource</strong> that is added in that operation and patched up the bindings to expect a <strong>Customer</strong> property exposed from the view’s <strong>DataContext</strong> (view model) once it is hooked up. </p> <p>Notice the <strong>Button</strong> at the bottom of the listing that is bound to a <strong>SaveCommand</strong> property it also expects to be exposed from the view model. I will hook that up once I get to defining the view model for this view in the next step. Also notice that in this case I did not wire up the view model as the <strong>DataContext</strong> from the XAML. I will do that programmatically for this sample when the Edit command is invoked in the listing view.</p> <div id="codeSnippetWrapper" class="csharpcode-wrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd"><</span><span class="html">UserControl</span> <span class="attr">x:Class</span><span class="kwrd">="Prism101.Modules.Core.CustomerEditView"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="attr">xmlns</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> <span class="attr">xmlns:x</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="attr">xmlns:d</span><span class="kwrd">="http://schemas.microsoft.com/expression/blend/2008"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> <span class="attr">xmlns:mc</span><span class="kwrd">="http://schemas.openxmlformats.org/markup-compatibility/2006"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> <span class="attr">xmlns:sdk</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum7" class="lnum"> 7:</span> <span class="attr">mc:Ignorable</span><span class="kwrd">="d"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="attr">d:DesignHeight</span><span class="kwrd">="212"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum9" class="lnum"> 9:</span> <span class="attr">d:DesignWidth</span><span class="kwrd">="301"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">="LayoutRoot"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum11" class="lnum"> 11:</span> <span class="attr">Background</span><span class="kwrd">="White"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> </pre> <!--CRLF--> <pre class="alteven"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">DataContext</span><span class="kwrd">="{Binding Customer}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum15" class="lnum"> 15:</span> <span class="attr">Margin</span><span class="kwrd">="12,12,0,0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="attr">Name</span><span class="kwrd">="grid1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum17" class="lnum"> 17:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Top"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="attr">Width</span><span class="kwrd">="272"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum19" class="lnum"> 19:</span> <span class="kwrd"><</span><span class="html">Grid.ColumnDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum21" class="lnum"> 21:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> <span class="kwrd"><</span><span class="html">ColumnDefinition</span> <span class="attr">Width</span><span class="kwrd">="5*"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum23" class="lnum"> 23:</span> <span class="kwrd"></</span><span class="html">Grid.ColumnDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> <span class="kwrd"><</span><span class="html">Grid.RowDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum25" class="lnum"> 25:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum27" class="lnum"> 27:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum28" class="lnum"> 28:</span> <span class="kwrd"><</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">="Auto"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum29" class="lnum"> 29:</span> <span class="kwrd"></</span><span class="html">Grid.RowDefinitions</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum30" class="lnum"> 30:</span> <span class="kwrd"><</span><span class="html">sdk:Label</span> <span class="attr">Content</span><span class="kwrd">="Company Name:"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum31" class="lnum"> 31:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum32" class="lnum"> 32:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum33" class="lnum"> 33:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum34" class="lnum"> 34:</span> <span class="attr">Margin</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum35" class="lnum"> 35:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum36" class="lnum"> 36:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum37" class="lnum"> 37:</span> <span class="attr">Height</span><span class="kwrd">="23"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum38" class="lnum"> 38:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum39" class="lnum"> 39:</span> <span class="attr">Margin</span><span class="kwrd">="3,3,0,3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum40" class="lnum"> 40:</span> <span class="attr">Name</span><span class="kwrd">="companyNameTextBox"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum41" class="lnum"> 41:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Path=CompanyName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum42" class="lnum"> 42:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum43" class="lnum"> 43:</span> <span class="attr">Width</span><span class="kwrd">="164"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum44" class="lnum"> 44:</span> <span class="kwrd"><</span><span class="html">sdk:Label</span> <span class="attr">Content</span><span class="kwrd">="Contact Name:"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum45" class="lnum"> 45:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum46" class="lnum"> 46:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum47" class="lnum"> 47:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum48" class="lnum"> 48:</span> <span class="attr">Margin</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum49" class="lnum"> 49:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum50" class="lnum"> 50:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum51" class="lnum"> 51:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum52" class="lnum"> 52:</span> <span class="attr">Height</span><span class="kwrd">="23"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum53" class="lnum"> 53:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum54" class="lnum"> 54:</span> <span class="attr">Margin</span><span class="kwrd">="3,3,0,3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum55" class="lnum"> 55:</span> <span class="attr">Name</span><span class="kwrd">="contactNameTextBox"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum56" class="lnum"> 56:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Path=ContactName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum57" class="lnum"> 57:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum58" class="lnum"> 58:</span> <span class="attr">Width</span><span class="kwrd">="164"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum59" class="lnum"> 59:</span> <span class="kwrd"><</span><span class="html">sdk:Label</span> <span class="attr">Content</span><span class="kwrd">="Contact Title:"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum60" class="lnum"> 60:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum61" class="lnum"> 61:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="2"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum62" class="lnum"> 62:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum63" class="lnum"> 63:</span> <span class="attr">Margin</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum64" class="lnum"> 64:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum65" class="lnum"> 65:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum66" class="lnum"> 66:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="2"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum67" class="lnum"> 67:</span> <span class="attr">Height</span><span class="kwrd">="23"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum68" class="lnum"> 68:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum69" class="lnum"> 69:</span> <span class="attr">Margin</span><span class="kwrd">="3,3,0,3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum70" class="lnum"> 70:</span> <span class="attr">Name</span><span class="kwrd">="contactTitleTextBox"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum71" class="lnum"> 71:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Path=ContactTitle, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum72" class="lnum"> 72:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum73" class="lnum"> 73:</span> <span class="attr">Width</span><span class="kwrd">="164"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum74" class="lnum"> 74:</span> <span class="kwrd"><</span><span class="html">sdk:Label</span> <span class="attr">Content</span><span class="kwrd">="Phone:"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum75" class="lnum"> 75:</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum76" class="lnum"> 76:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum77" class="lnum"> 77:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum78" class="lnum"> 78:</span> <span class="attr">Margin</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum79" class="lnum"> 79:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum80" class="lnum"> 80:</span> <span class="kwrd"><</span><span class="html">TextBox</span> <span class="attr">Grid</span>.<span class="attr">Column</span><span class="kwrd">="1"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum81" class="lnum"> 81:</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">="3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum82" class="lnum"> 82:</span> <span class="attr">Height</span><span class="kwrd">="23"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum83" class="lnum"> 83:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum84" class="lnum"> 84:</span> <span class="attr">Margin</span><span class="kwrd">="3,3,0,3"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum85" class="lnum"> 85:</span> <span class="attr">Name</span><span class="kwrd">="phoneTextBox"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum86" class="lnum"> 86:</span> <span class="attr">Text</span><span class="kwrd">="{Binding Path=Phone, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum87" class="lnum"> 87:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Center"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum88" class="lnum"> 88:</span> <span class="attr">Width</span><span class="kwrd">="164"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum89" class="lnum"> 89:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum90" class="lnum"> 90:</span> <span class="kwrd"><</span><span class="html">Button</span> <span class="attr">Content</span><span class="kwrd">="Save"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum91" class="lnum"> 91:</span> <span class="attr">Command</span><span class="kwrd">="{Binding SaveCommand}"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum92" class="lnum"> 92:</span> <span class="attr">Height</span><span class="kwrd">="23"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum93" class="lnum"> 93:</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">="Left"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum94" class="lnum"> 94:</span> <span class="attr">Margin</span><span class="kwrd">="162,134,0,0"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum95" class="lnum"> 95:</span> <span class="attr">VerticalAlignment</span><span class="kwrd">="Top"</span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum96" class="lnum"> 96:</span> <span class="attr">Width</span><span class="kwrd">="75"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum97" class="lnum"> 97:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span id="lnum98" class="lnum"> 98:</span> <span class="kwrd"></</span><span class="html">UserControl</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <h3>Step 9: Define the CustomerEditViewModel</h3> <p>When you define a view like the edit view, you quickly identify what properties are needed from your view model to support the view, in this case a <strong>Customer</strong> property and a <strong>SaveCommand</strong> property. Add a <strong>CustomerEditViewModel</strong> class to the project and add the following contents to it.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> CustomerEditViewModel : NotificationObject</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> <span class="kwrd">public</span> CustomerEditViewModel()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> SaveCommand = <span class="kwrd">new</span> DelegateCommand(OnSave);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum7" class="lnum"> 7:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> <span class="kwrd">public</span> DelegateCommand SaveCommand { get; <span class="kwrd">private</span> set; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum9" class="lnum"> 9:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> Customer _Customer;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum11" class="lnum"> 11:</span> <span class="kwrd">public</span> Customer Customer</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum13" class="lnum"> 13:</span> get { <span class="kwrd">return</span> _Customer; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> set</pre> <!--CRLF--> <pre class="alteven"><span id="lnum15" class="lnum"> 15:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd">if</span> (_Customer != <span class="kwrd">value</span>)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum17" class="lnum"> 17:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> _Customer = <span class="kwrd">value</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum19" class="lnum"> 19:</span> RaisePropertyChanged(() => Customer);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum21" class="lnum"> 21:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum23" class="lnum"> 23:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum24" class="lnum"> 24:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnSave()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum25" class="lnum"> 25:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum26" class="lnum"> 26:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum27" class="lnum"> 27:</span> }</pre> <!--CRLF--></div> </div> <h3>Step 10: Switch to the edit view when the Edit command executes</h3> <p>As you learned in Part 1, the <strong>RegionManager</strong> service provides the mechanism for plugging views into regions. That means if you are going to switch to the edit view from the list view model, you will need access to that service there. To gain access, you can leverage dependency injection through MEF in your view model. Add the following property declaration in the <strong>CustomerListViewModel</strong>.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> [Import]</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd">public</span> IRegionManager RegionManager { get; set; }</pre> <!--CRLF--></div> </div> <p>This view model gets constructed from the XAML of the view, so the container is not involved and can’t do the dependency injection automatically. But thanks to the <strong>CompositionInitializer</strong> class, you can ask the container to do the injection as the view model gets constructed explicitly. Add line 7 in the the following code to the constructor of the <strong>CustomerListViewModel</strong>. </p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">public</span> CustomerListViewModel()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> EditCustomerCommand = <span class="kwrd">new</span> DelegateCommand(OnEditCustomer, CanEditCustomer);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">if</span> (!DesignerProperties.IsInDesignTool)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> _Context.Load(_Context.GetCustomersQuery(), OnLoadComplete, <span class="kwrd">null</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum7" class="lnum"> 7:</span> CompositionInitializer.SatisfyImports(<span class="kwrd">this</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum9" class="lnum"> 9:</span> }</pre> <!--CRLF--></div> </div> <p>That will get the <strong>IRegionManager</strong> reference injected (the set block of the property will be called to provide the reference) by the container. However, to make sure there is a single container used by both Prism and the <strong>CompositionInitializer</strong> class, you need to add one more overload to the <strong>Bootstrapper</strong> class in the Prism101 shell project. </p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> CompositionContainer CreateContainer()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> var container = <span class="kwrd">base</span>.CreateContainer();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> CompositionHost.Initialize(container);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">return</span> container;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> }</pre> <!--CRLF--></div> </div> <p>This makes it so the container that Prism sets up is the one that is used by the <strong>CompositionHost</strong> that sits underneath the <strong>CompositionInitializer</strong> class.</p> <p>Now you are ready to actually do the view switching with the region manager. Modify the <strong>OnEditCustomer</strong> code with the following.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnEditCustomer()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span> IRegion mainContentRegion = RegionManager.Regions[<span class="str">"MainContent"</span>];</pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">bool</span> alreadyExists = <span class="kwrd">false</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> <span class="kwrd">foreach</span> (var view <span class="kwrd">in</span> mainContentRegion.Views)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd">if</span> (view <span class="kwrd">is</span> CustomerEditView)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum9" class="lnum"> 9:</span> CustomerEditViewModel viewModel = ((FrameworkElement)view).DataContext <span class="kwrd">as</span> CustomerEditViewModel;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> viewModel.Customer = SelectedCustomer;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum11" class="lnum"> 11:</span> mainContentRegion.Activate(view);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span> alreadyExists = <span class="kwrd">true</span>;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum13" class="lnum"> 13:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum15" class="lnum"> 15:</span> <span class="kwrd">if</span> (!alreadyExists)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum17" class="lnum"> 17:</span> CustomerEditView editView = <span class="kwrd">new</span> CustomerEditView();</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> CustomerEditViewModel viewModel = <span class="kwrd">new</span> CustomerEditViewModel { Customer = SelectedCustomer };</pre> <!--CRLF--> <pre class="alteven"><span id="lnum19" class="lnum"> 19:</span> editView.DataContext = viewModel;</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> mainContentRegion.Add(editView);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum21" class="lnum"> 21:</span> mainContentRegion.Activate(editView);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum23" class="lnum"> 23:</span> }</pre> <!--CRLF--></div> </div> <p>If you look at what this code is doing, first it obtains a reference to the <strong>IRegion</strong> reference for the <strong>MainContent</strong> region. Then it loops through the <strong>Views</strong> collection exposed on the region to see if it contains an instance of a <strong>CustomerEditView</strong>. That would be the case if the user had already switched to the edit view at least once before. If so, it obtains a reference to the view model for that view by casting the <strong>DataContext</strong> of the view. Remember that in MVVM, View.DataContext = ViewModel. Once it has the view model reference, it can push the reference to the selected customer into the Customer property of the edit view model. Finally in that case it calls <strong>Activate</strong> on the region to get that as the currently presented view. </p> <p>If the view was not in the <strong>Views</strong> collection, it simply constructs a new instance and goes through a similar process, first calling <strong>Add</strong> before <strong>Activate</strong>. This chunk of code should only execute the first time the edit view is visited, because the region will cache the reference to the edit view in its Views collection.</p> <p>One thing to point out here is that I am kind of violating the principles of MVVM by explicitly constructing the <strong>CustomerEditView</strong> type in the list view model. Typically if you were going to do it this way you would factor this code out to a Controller that managed multiple views and their view models and use a <strong>CompositeCommand</strong> to hook things up. I’ll show that kind of structure in the next article, and in a later one I’ll highlight the newer navigation features of Prism regions that were added in Prism 4 as an even more decoupled way to switch views. But for now I wanted to show the basic view switching mechanisms of Prism regions and not have too many moving parts, so I am sacrificing a little bit of view model cleanliness for compactness for writing purposes here.</p> <p>Once you have this code in place, you should be able to build, fire up the application, select a <strong>Customer</strong> in the grid, press the Edit button and have the main view’s content switch to the edit form.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/_Figure3_2.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="Figure3" alt="Figure3" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/_Figure3_thumb.png" width="464" height="291" /></a></p> <p>The last piece for this article is to hook up the Save button in the edit form so that it can at least switch back to the main form. That means you need access to the region manager from that view model as well. The code there is very similar: </p> <ul> <li>Add an Import property for the <strong>IRegionManager</strong> </li> <li>Call <strong>CompositionInitializer.SatifyImports</strong> from the constructor in a guard clause checking to see if you are in the designer </li> <li>Use the region manager to activate the list view in the region </li> </ul> <p>The following code shows those changes to the <strong>CustomerEditViewModel</strong>.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" class="csharpcode"> <pre class="alteven"><span id="lnum1" class="lnum"> 1:</span> [Import]</pre> <!--CRLF--> <pre class="alteven"><span id="lnum2" class="lnum"> 2:</span> <span class="kwrd">public</span> IRegionManager RegionManager { get; set; }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum3" class="lnum"> 3:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum4" class="lnum"> 4:</span> <span class="kwrd">public</span> CustomerEditViewModel()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum5" class="lnum"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum6" class="lnum"> 6:</span> SaveCommand = <span class="kwrd">new</span> DelegateCommand(OnSave);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum7" class="lnum"> 7:</span> <span class="kwrd">if</span> (!DesignerProperties.IsInDesignTool)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum8" class="lnum"> 8:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum9" class="lnum"> 9:</span> CompositionInitializer.SatisfyImports(<span class="kwrd">this</span>);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum10" class="lnum"> 10:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum11" class="lnum"> 11:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum12" class="lnum"> 12:</span>  </pre> <!--CRLF--> <pre class="alteven"><span id="lnum13" class="lnum"> 13:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> OnSave()</pre> <!--CRLF--> <pre class="alteven"><span id="lnum14" class="lnum"> 14:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum15" class="lnum"> 15:</span> IRegion mainContentRegion = RegionManager.Regions[<span class="str">"MainContent"</span>];</pre> <!--CRLF--> <pre class="alteven"><span id="lnum16" class="lnum"> 16:</span> <span class="kwrd">foreach</span> (var view <span class="kwrd">in</span> mainContentRegion.Views)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum17" class="lnum"> 17:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum18" class="lnum"> 18:</span> <span class="kwrd">if</span> (view <span class="kwrd">is</span> CustomerListView)</pre> <!--CRLF--> <pre class="alteven"><span id="lnum19" class="lnum"> 19:</span> {</pre> <!--CRLF--> <pre class="alteven"><span id="lnum20" class="lnum"> 20:</span> mainContentRegion.Activate(view);</pre> <!--CRLF--> <pre class="alteven"><span id="lnum21" class="lnum"> 21:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum22" class="lnum"> 22:</span> }</pre> <!--CRLF--> <pre class="alteven"><span id="lnum23" class="lnum"> 23:</span> }</pre> <!--CRLF--></div> </div> At this point you have a simple but functioning example of an MVVM Prism application that uses a bit of view model base class infrastructure that Prism provides in the <strong>NotificationObject</strong> base class, <strong>DelegateCommands</strong> to communicate from the view to the view model, and regions to do the switching of views in the main window. <h3>Summary</h3> <p>You can see that it is not a lot of code, nor a lot of complexity that Prism provides  with respect to MVVM and commanding, but it provides the common pieces you need for a clean MVVM application. There is no built in implementation of the <strong>ICommand</strong> interface in Silverlight, so it provides the <strong>DelegateCommand</strong> to step in nicely for hooking up views to view model logic. There are other discrete pieces of functionality related to MVVM that Prism supports. I’ll touch on some of those when we get to the navigation services in Prism in a later article. There are also features like the <a href="http://briannoyes.net/2011/01/15/Prism4GemsRenderingHeterogeneousCollectionsWithDataTemplateSelector.aspx" target="_blank">DataTemplateSelector capabilities</a>, which are not as necessary in Silverlight 5 with the addition of implicit data templates, but can still come in handy in other scenarios. Another piece is the <a href="http://briannoyes.net/2010/11/15/PromptingTheUserFromAViewModelndashPrism4Gems.aspx" target="_blank">interaction request capabilities</a> that allow you to be more decoupled in your view model and not directly present pop ups but leave it up to the view to decide what the appearance of the notification to a user looks like.</p> <p>In the next article I will expand on the communication by looking at <strong>CompositeCommands</strong> and loosely coupled events in Prism. You can <a href="http://www.silverlightshow.net/Storage/Sources/Prism4MVVMAndCommandsSamplePart2.zip" target="_blank">download the completed code for this article here</a>.</p> <h3>About the Author</h3> <p>Brian Noyes is Chief Architect of <a href="http://www.idesign.net/" target="_blank">IDesign</a>, a <a href="http://theregion.com/" target="_blank">Microsoft Regional Director</a>, and Silverlight MVP. He is a frequent top rated speaker at conferences worldwide including Microsoft TechEd, DevConnections, VSLive!, DevTeach, and others. Brian worked directly on the Prism team with Microsoft patterns and practices and co-authored the book <a href="http://my.safaribooksonline.com/book/programming/microsoft-wpf/9780735660663" target="_blank">Developers Guide to Microsoft Prism 4</a>. He is also the author of Developing Applications with Windows Workflow Foundation, Smart Client Deployment with ClickOnce, and Data Binding in Windows Forms 2.0. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at <a href="http://briannoyes.net/">http://briannoyes.net/</a> or on Twitter @briannoyes.</p> http://www.silverlightshow.net/items/Working-with-Prism-4-Part-2-MVVM-Basics-and-Commands.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/Working-with-Prism-4-Part-2-MVVM-Basics-and-Commands.aspx#comments http://www.silverlightshow.net/items/Working-with-Prism-4-Part-2-MVVM-Basics-and-Commands.aspx Mon, 21 Nov 2011 00:13:00 GMT Working with Prism 4 Part 1: Getting Started <div style="text-align: right;"><br /> <a href="https://twitter.com/share" class="twitter-share-button" data-url="http://slshow.net/tso39e" data-text="Reading SilverlightShow article 'Working with Prism 4 Part 1: Getting Started' by @briannoyes" data-count="horizontal" data-counturl="http://www.silverlightshow.net/items/Working-with-Prism-4-Part-1-Getting-Started.aspx" data-via="silverlightshow">Tweet</a></div> <p>This is Part 1 in the series Working with Prism 4.</p> <h3>Introduction</h3> <p><a href="http://msdn.microsoft.com/en-us/library/gg406140.aspx" target="_blank">Prism</a> is a toolkit produced by Microsoft patterns & practices to aid you in building Silverlight and WPF <strong><em>composite applications</em></strong>. </p> <div style="border:1px solid #dddddd;border-image: initial; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>More resources...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Webinars.aspx">Upcoming SilverlightShow Webinars</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/WCF-RIA-Services-Webinar-4.aspx">Recordings of the Webinar Series: WCF RIA Services</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/prism4.aspx">The Prism 4 Series is also available as an Ebook:</a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/prism4.aspx"><img style="border:0px solid; border-image: initial; width: 121px; height: 170px;" alt="Working with Prism 4 - ebook by Brian Noyes" src="http://www.silverlightshow.net/Storage/Ebooks/prism.png" usemap="#rade_img_map_1291385581316" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> Now, that probably doesn’t tell you much unless you have been building composite applications with other toolkits or frameworks and know what that term really means, so let me expand on what that means and what the real purpose of Prism is to get started. <p>A composite application can be thought of as the opposite of a monolithic application. I can hear you thinking now: “Ah, now I see. I know monolithic applications are bad, therefore composite applications must be good. Yin/Yang, Dark/Light. I need to check this out!” Or at least that is what I hope you are thinking. Composite applications are built from more granular, loosely coupled parts. Two of the primary reasons for approaching application development in a composite way are for maintainability and extensibility. If your application is composed of fine grained, well-focused, loosely coupled parts, it should be easier to develop and easier to maintain and add new functionality over time. Things like the code that defines the structure of your user interface (XAML in Silverlight, WPF, and Metro), the code that supports the interaction logic with the user (view models in the MVVM pattern), the data structures and logic (the model in MVVM), and services that provide shared functionality for service or data access in your application are examples of things that are better separated into parts rather than getting all woven together in spaghetti code. The fact that building composite applications will help you with maintainability is a little hard to prove up front, but the over 50,000 downloads of Prism 4 should tell you that there are a lot of companies out there that get this and like Prism as a toolkit for building apps that way.</p> <p>To get more specific, Prism has a number of specific feature sets that I will explore in this series that helps you to build your client application as a composite application. These include:</p> <ul> <li>Modularity – Functionality to define and dynamically load chunks of loosely coupled functionality into a single running application instance. </li> <li>UI Composition – Functionality to plug in views into parent containers in a loosely coupled fashion where the parent and child do not need to know explicitly about one another with direct object references. </li> <li>Communications – Functionality to support loosely coupled commands and pub/sub events between the components of your application. </li> <li>Navigation – Functionality to switch views when the user interacts with the application within a container without every view and parent view needing to know about all the others. </li> <li>Application Structure – Support for the Model-View-ViewModel pattern, as well as a dependency injection container, and other implementation patterns to help set up your solution for the best separation of concerns for different kinds of code in your application. </li> </ul> <p>An important thing to understand about Prism is that it is not an all-or-nothing framework. You can use any one or several of the features in isolation and ignore the other parts if they do not make sense for your application or your requirements. In addition to these major features, there are many small little helper classes and utilities in Prism that can be used on their own as well.</p> <p>In the rest of this article, I will quickly step you through creating a simple Prism application that uses modularity and regions to plug a view into the main application. You will see that there are a number of steps that may seem a bit complicated at first. The first thing to keep in mind is that these activities are a one-time set up of your solution as you lay down the structure of your solution. The other is that at the end of the article I will point you to some project templates that make it all much quicker. But I think it is important to go through the steps manually at least once so you understand what all the moving parts are. In the next article, I will flesh that application out some more to use commands and events and later articles will explore other aspects of Prism.</p> <p><a href="http://www.silverlightshow.net/Storage/Sources/Prism101Part1.zip">Download the source code for the Prism 101 completed solution.</a></p> <h3>Step 1: Create your Prism application</h3> <p>To get started, create a new Silverlight Application project in Visual Studio and name it Prism101.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/_Figure1_2.png"><img title="Figure1" style="border:0px solid; border-image: initial; background-image: none; padding-left: 0px; width: 670px; padding-right: 0px; display: inline; height: 465px; padding-top: 0px;" alt="Figure1" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/_Figure1_thumb.png" /></a></p> <p>In the New Silverlight Application dialog that asks about creating a host application, accept the defaults by clicking OK. (Note: I am using Silverlight 5 RC for my example, but all of what I will show works equally well for Silverlight 4).</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure2_2.png"><img width="410" height="369" title="Figure2" style="border:0px solid; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Figure2" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure2_thumb.png" /></a></p> <h3>Step 2: Decide which Dependency Injection container to use</h3> <p>Prism uses the <a href="http://msdn.microsoft.com/en-us/magazine/cc337885.aspx" target="_blank">Inversion of Control</a> and <a href="http://msdn.microsoft.com/en-us/magazine/cc163739.aspx" target="_blank">Dependency Injection</a> patterns under the covers with the help of a Container. Out of the box, Prism supports using either Unity or Managed Extensibility Framework (MEF). You can also plug in other containers by implementing the <a href="http://msdn.microsoft.com/en-us/library/ff921140(v=PandP.40).aspx#sec10" target="_blank">IServiceLocator</a> interface similar to the implementations that are provided for Unity and MEF. </p> <p>I won’t go into a full discussion of the differences and similarities between Unity and MEF. Each has distinct capabilities, but for the purposes of what I will be covering in this article series, either one is equally sufficient. I generally prefer MEF myself since it is a part of the .NET and Silverlight Frameworks, and because I like the declarative approach that MEF uses. So I will be using MEF throughout the article series. The sample applications that come with Prism have numerous examples of using Unity instead.</p> <h3>Step 3: Add the Prism Library assemblies</h3> <p>To follow along with the coding, you will need to <a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=4922" target="_blank">download the Prism 4 toolkit</a>. It is a self-extracting executable that you can point to any folder on your machine where you want to store the libraries, source code, sample code, and documentation for Prism 4. Once you have extracted the files, add references to the Prism101 Silverlight client application project to the Microsoft.Practices.Prism, Microsoft.Practices.Prism.Interactivity, and Microsoft.Practices.Prism.MefExtensions libraries in the \Bin\Silverlight folder wherever you extracted Prism to: </p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure3_2.png"><img width="646" height="405" title="Figure3" style="border:0px solid; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Figure3" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure3_thumb.png" /></a></p> <p>For this sample article I will not be using any functionality from the Interactivity library, but it is easier to just always add references to all three of these libraries in your client projects so that you have the full Prism toolkit at your disposal. If you were using Unity instead of MEF, you can see that instead of adding the MefExtensions library, you would add the UnityExtensions  and Unity.Silverlight libraries instead</p> <p>Also add references to the System.ComponentModel.Composition, System.ComponentModel.Composition.Initialization and the System.Windows.Controls libraries.</p> <h3>Step 4: Add a Bootstrapper</h3> <p>If you are going to use modularity, UI composition, or navigation in your application, you will need to have some Prism-specific initialization code in your application. The standard way to set up this initialization code is to have it in a separate class called a bootstrapper. The bootstrapper is just a way to centralize all the initialization logic for your application in one well known location, separate from the App.xaml code behind. Prism provides a base bootstrapper class for each of the containers that takes care of initializing all the types and services in the Prism toolkit. All you need to do is derive from it and handle a couple of overrides to initialize the specifics of your application.</p> <p>Add a class named Bootstrapper to your Prism101 project. Modify the code to match the code below.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alteven"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> Bootstrapper : MefBootstrapper</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> DependencyObject CreateShell()</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum5"> 5:</span> MainPage shell = <span class="kwrd">new</span> MainPage();</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> Application.Current.RootVisual = shell;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum7"> 7:</span> <span class="kwrd">return</span> shell;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> }</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum9"> 9:</span> }</pre> <!--CRLF--></div> </div> <p>Part of the initialization of the application is to create the main page. The outermost UI (Window in WPF or RootVisual in Silverlight) is referred to as the Shell in a Prism application. Part of the design of a composite application is that the shell is just a place for content to live. The specific content and functionality of your application will be contributed by the modules that load into the shell. I will get to creating a module later in the article. The shell is responsible for setting up the overall look and feel of the application (i.e. contributing the application scoped resources), determining the top level window layout and navigation. However, the shell should remain ignorant of the details of what is going to load into the application other than those aspects. </p> <p>So the code above just initializes the application’s RootVisual to an instance of the MainPage class and returns a reference for that instance to the bootstrapper base class. Prism will use that reference to hook up some of the region functionality that I will be using shortly.</p> <p>As you may know, normally your RootVisual is set in the App.xaml.cs file of your project, and you can only set the RootVisual once per application. Additionally, for the bootstrapper to do anything, it has to be called from somewhere. Open your App.xaml.cs file and modify the Application_Startup event handler to run the bootstrapper instead of setting the RootVisual:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alteven"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">private</span> <span class="kwrd">void</span> Application_Startup(<span class="kwrd">object</span> sender, StartupEventArgs e)</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">new</span> Bootstrapper().Run();</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> }</pre> <!--CRLF--></div> </div> <p>The Run method on the MefBootstrapper base class will execute an intialization workflow that performs the following:</p> <ul> <li>Creates the container </li> <li>Adds MEF exports to the container for the types contributed by Prism </li> <li>Creates and initializes the shell </li> <li>Loads and initializes the modules </li> </ul> <p>The third bullet is the point where the overridden CreateShell method in your bootstrapper will be called. The main application project (Prism101) is referred to as the Shell application project since it is the root application that loads and hosts the shell.</p> <p>Build and run the application at this point to make sure all is well. Your Silverlight application should launch like normal with an empty main page, but you should not see any exceptions. There is not much there to see yet, but the addition of the bootstrapper has made it so all the functionality of Prism is now at your disposal in your application. Next I will show how to start harnessing some of that functionality by defining a module.</p> <h3>Step 5: Add a Module project to your solution</h3> <p>A Module in Prism is an abstract container for a set of functionality. The way you partition your sets of functionality into modules is completely arbitrary, but common lines of separation are to put individual feature sets that you want to be able to turn on or off as a whole in the application into separate modules. Another common approach is to separate modules based on team composition and which team will be working on which set of functionality. For this article, I will just add a single Core module with the main view that will load up to welcome the user and get them started using the application. In later articles I will add additional modules and show how you can plug functionality from multiple modules in at the shell level, or can even plug functionality into the views of one module from another module.</p> <p>Add another Silverlight Application project to your solution and name it Prism101.Modules.Core.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure4_2.png"><img width="600" height="416" title="Figure4" style="border:0px solid; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Figure4" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure4_thumb.png" /></a></p> <p>When the New Silverlight Application dialog pops up, uncheck the option at the top to host the application and click <strong>OK</strong>.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure5_2.png"><img width="455" height="440" title="Figure5" style="border:0px solid; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Figure5" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure5_thumb.png" /></a></p> <p>Normally you only create a Silverlight Application project type for your main application, and any types that you separate into other assemblies you would create with a Silverlight Class Library project type. A module in Prism is an independently loadable unit of functionality. By creating it as a Silverlight Application project, it will get compiled into its own XAP file and can be downloaded and loaded independently from the rest of the application. That is part of the decoupling you are going after when you develop an application as a composite application.</p> <p>Because this project will not launch as a standalone Silverlight Application itself though, delete the MainPage.xaml and App.xaml files from the project. Then go to the project properties and change the <strong>Startup object</strong> drop down to <strong>(not set)</strong>.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure6_2.png"><img width="687" height="178" title="Figure6" style="border:0px solid; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Figure6" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure6_thumb.png" /></a></p> <h3>Step 6: Add the Module class</h3> <p>The thing that identifies an assembly as a module to Prism is that it contains one or more module classes. A module class is just a class that implements the Prism IModule interface. When using MEF as the container, you also have to decorate the class with a [ModuleExport] attribute so that Prism can discover the module class through the container. Even though Prism supports defining more than one module class in a single assembly, my design recommendation is to only ever have one module class for a given module project. That allows you to treat the assembly boundary as the container for a single module’s functionality rather than trying to rationalize which types within the assembly are associated with which logical module.</p> <p>Before you add the module class, you will need the same references for each module that you added to the shell project:</p> <ul> <li>Microsoft.Practices.Prism </li> <li>Microsoft.Practices.Prism.Interactivity </li> <li>Microsoft.Practices.Prism.MefExtensions </li> <li>System.ComponentModel.Composition </li> <li>System.ComponentModel.Composition.Initialization </li> <li>System.Windows.Controls </li> </ul> <p>However, one important difference is that you need to set the Copy Local property for each of the Prism references to false so that those assemblies do not get copied into the application multiple times. They will be present at runtime because the Shell project will already have them in its XAP file. Having multiple copies load up causes problems in the module loading process.</p> <p>Add a class to the Prism101.Modules.Core project and name it CoreModule. Add code to the class so it matches the following code snippet:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alteven"><span class="lnum" id="lnum1"> 1:</span> [ModuleExport(<span class="kwrd">typeof</span>(CoreModule))]</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> CoreModule : IModule</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum3"> 3:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> Initialize()</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum5"> 5:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> MessageBox.Show(<span class="str">"Core Module initialized!"</span>);</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum7"> 7:</span> }</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> }</pre> <!--CRLF--></div> </div> <h3> </h3> <h3>Step 7: Define the Module catalog</h3> <p>Prism supports several ways of loading modules into the shell application. Modules can be downloaded along with the main application or they can be downloaded asynchronously in the background. They can be loaded as soon as they have been downloaded or you can defer loading of the module until the first point where the functionality is invoked from the module. You can declare which modules the application is composed of programmatically or declaratively in a module XAML file. The module loader is also extensible, so if you wanted to write your own module catalog implementation that went out and made a service call with the logged in user identity to get back a tailored list per user of what modules to download and load, you could easily do that as well. In fact, that might make a good future article… leave a comment if you would like to see that.</p> <p>For this sample, I will use a ModuleCatalog.xaml file to indicate which modules to load. For the Core module I will have it download and initialize as the application starts up since it represents the initial landing page for the user. In a later article I will show how to defer downloading and initialization until additional functionality is first invoked.</p> <p>Add a Text File from the General category of project item templates named ModuleCatalog.xaml to the Prism101 project.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure7_2.png"><img width="663" height="460" title="Figure7" style="border:0px solid; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Figure7" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure7_thumb.png" /></a></p> <p>Edit the contents of the file to contain the following markup.</p> <div class="csharpcode-wrapper" id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alteven"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd"><</span><span class="html">Modularity:ModuleCatalog</span> <span class="attr">xmlns</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="attr">xmlns:x</span><span class="kwrd">="http://schemas.microsoft.com/winfx/2006/xaml"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum3"> 3:</span> <span class="attr">xmlns:sys</span><span class="kwrd">="clr-namespace:System;assembly=mscorlib"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="attr">xmlns:Modularity</span><span class="kwrd">="clr-namespace:Microsoft.Practices.Prism.Modularity;assembly=Microsoft.Practices.Prism"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum5"> 5:</span> <span class="kwrd"><</span><span class="html">Modularity:ModuleInfo</span> <span class="attr">Ref</span><span class="kwrd">="Prism101.Modules.Core.xap"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> 6:</span> <span class="attr">ModuleName</span><span class="kwrd">="CoreModule"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum7"> 7:</span> <span class="attr">ModuleType</span><span class="kwrd">="Prism101.Modules.Core.CoreModule, Prism101.Modules.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> <span class="kwrd"></</span><span class="html">Modularity:ModuleCatalog</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>This markup identifies the module assembly information in a declarative fashion outside the compiled code so that it could potentially be changed on the deployment site to add or remove modules without needing to recompile anything. Go to the properties for the file and make sure its Build Action is set to Resource.</p> <h3>Step 8: Add the module XAP to the host site</h3> <p>For Prism to be able to download the module XAP file, it will have to be present in the hosting web applications \ClientBin folder. To add this, open the Prism101.Web project and go to its project properties. Select the Silverlight Applications tab and Click the Add button at the bottom.</p> <p>In the Add Silverlight Application dialog, select Prism101.Modules.Core from the drop down list for “Use and existing Silverlight application project in the solution”. Uncheck the option towards the bottom to “Add a test page that references the control”. Click Add. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure8_2.png"><img width="507" height="524" title="Figure8" style="border:0px solid; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Figure8" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure8_thumb.png" /></a></p> <p>You should now see both the Shell project (Prism101) and the module project (Prism101.Modules.Core) listed as hosted applications.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure9_4.png"><img width="686" height="92" title="Figure9" style="border:0px solid; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Figure9" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure9_thumb_1.png" /></a></p> <h3>Step 9: Read the ModuleCatalog.xaml from the bootstrapper</h3> <p>The final step to get the module loaded is to modify the bootstrapper so it knows where to find the module catalog information. Add this method to your Bootstrapper class:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alteven"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd">protected</span> <span class="kwrd">override</span> Microsoft.Practices.Prism.Modularity.IModuleCatalog CreateModuleCatalog()</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd">return</span> Microsoft.Practices.Prism.Modularity.ModuleCatalog.CreateFromXaml(</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd">new</span> Uri(<span class="str">"/Prism101;component/ModuleCatalog.xaml"</span>, UriKind.Relative));</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum5"> 5:</span> }</pre> <!--CRLF--></div> </div> <p>At this point you should be able to run the application again and you will see the message box pop up as the application loads, indicating that the module has in fact loaded.</p> <h3>Step 10: Add a Region to the Shell</h3> <p>Popping a message box at least tells us our module is loading and initializing, but is not very interesting. What you will typically do as a module loads up is start presenting some screens or at least commanding functionality to the user that lets them take advantage of the functionality that is encapsulated in the module. So now I will show how you can define a view in a module and present it to the user by plugging it into the shell as the module loads.</p> <p>The first step in doing that is to define somewhere for the view to plug in within the shell. The most common way to do this is to add either a ContentControl or ItemsControl (or derived type) to the shell and mark it as a Prism region.</p> <p>Open MainPage.xaml and add the Prism XAML namespace to the XML namespaces on the root UserControl element so that you can access types from the Prism Library in XAML</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alteven"><span class="lnum" id="lnum1"> 1:</span> xmlns:prism=<span class="str">"http://www.codeplex.com/prism"</span></pre> <!--CRLF--></div> </div> <p>Then add a ContentControl and mark it as a region named MainContent:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alteven"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">="LayoutRoot"</span> <span class="attr">Background</span><span class="kwrd">="White"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd"><</span><span class="html">ContentControl</span> <span class="attr">prism:RegionManager</span>.<span class="attr">RegionName</span><span class="kwrd">="MainContent"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum3"> 3:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <h3> </h3> <h3>Step 11: Add a View to the Core Module and plug it into the Shell region</h3> <p>Add a new Silverlight User Control to the Prism101.Modules.Core project named WelcomeView. In the XAML, add a TextBlock with its Text property set to “Hello Prism!” and set the font size big to celebrate your excitement with Prism.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alteven"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd"><</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">="LayoutRoot"</span> <span class="attr">Background</span><span class="kwrd">="White"</span><span class="kwrd">></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd"><</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">="Hello Prism!"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum3"> 3:</span> <span class="attr">FontSize</span><span class="kwrd">="24"</span> <span class="kwrd">/></span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="kwrd"></</span><span class="html">Grid</span><span class="kwrd">></span></pre> <!--CRLF--></div> </div> <p>Next, open the CoreModule class and replace the code there with the following code.</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alteven"><span class="lnum" id="lnum1"> 1:</span> [ModuleExport(<span class="kwrd">typeof</span>(CoreModule))]</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="kwrd">public</span> <span class="kwrd">class</span> CoreModule : IModule</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum3"> 3:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> [Import]</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum5"> 5:</span> <span class="kwrd">public</span> IRegionManager RegionManager { get; set; }</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> 6:</span>  </pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum7"> 7:</span> <span class="kwrd">public</span> <span class="kwrd">void</span> Initialize()</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> 8:</span> {</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum9"> 9:</span> var view = <span class="kwrd">new</span> WelcomeView();</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum10"> 10:</span> RegionManager.AddToRegion(<span class="str">"MainContent"</span>, view);</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum11"> 11:</span> }</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum12"> 12:</span> }</pre> <!--CRLF--></div> </div> <p>The import allows your module class to access the RegionManager service exposed by Prism. This manager knows about all regions declared in any view throughout the application and allows you to dynamically plug in child views into those regions. The Initialize method code then creates an instance of your module’s view and plugs it into the MainContent region you placed in the shell as a ContentControl. To do this without Prism you would somehow have to feed an object reference to that ContentControl from the MainPage down into the module code that is loading into the application so that it could programmatically set the Content property to the view instance. That would be an example of the kind of coupling that you are trying to avoid when building composite applications. At this point the only coupling between the main application and the module are the declaration of the module in the ModuleCatalog.xaml and the shared “contract” of the MainContent region name as a string.</p> <h3>Step 12: Making it easier</h3> <p>I’m sure that seemed like a lot of work to get a Hello Prism view displayed in your application. And if you app is fairly small – say less than a couple dozen screens, you might not bother with using modularity and regions at all. In later articles in the series I’ll get into other features of Prism including commands, events, and some of the Model-View-ViewModel pattern support that can be very handy regardless of the scale of your application.</p> <p>But even all this initial setup cries out for automation, and it happens to be readily available in the form of the <a href="http://dphill.members.winisp.net/Templates.html" target="_blank">Prism Template Pack</a> created by David Hill, a Microsoft Program Manager from the Prism team. </p> <p>If you follow the instructions at that link to download an install the template pack, you can quickly create a Prism starter app with a module following these steps:</p> <p>Create a new project, select the Prism templates in the New Project dialog, and pick the MEF category. Start by selecting the Prism Silverlight 4.0 Shell (MEF) project type. This will create a pre-populated shell project with several regions already defined in the shell, the bootstrapper all set up for you, references added, etc.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure11_2.png"><img width="663" height="378" title="Figure11" style="border:0px; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Figure11" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Figure11_thumb.png" /></a></p> <p>Next, add another project to the solution and this time select the Prism Silverlight 4.0 Module (MEF) project type. Keep the default name of Module1.</p> <p>Next go into the ModuleCatalog.xaml in the shell project and uncomment the Module1 information:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alteven"><span class="lnum" id="lnum1"> 1:</span> <span class="kwrd"><</span><span class="html">prism:ModuleInfo</span> <span class="attr">Ref</span><span class="kwrd">="Module1.xap"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> 2:</span> <span class="attr">ModuleName</span><span class="kwrd">="Module1.ModuleInit"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum3"> 3:</span> <span class="attr">ModuleType</span><span class="kwrd">="Module1.ModuleInit, Module1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> 4:</span> <span class="attr">InitializationMode</span><span class="kwrd">="WhenAvailable"</span><span class="kwrd">/></span></pre> <!--CRLF--></div> </div> <p>Next add a new ASP.NET Empty Web Application project to act as a host. The Readme.txt file in each project tells you how to configure it, but it is similar to what I showed in Step 8 of this article to configure the web application as the host for the Shell and to add the Module1 XAP to be hosted in the site as well for download. Then you will want to launch the app using the web project as the startup project with the test page for the Shell as the startup page. If you do that, viola – you have a running Prism app with a module and a bit more functionality than the one we put together in this article because it has some views wired up with some sample data and navigation commands and other things we will be talking about in later articles.</p> <p>These templates will need to be updated for Silverlight 5 and you can customize them yourself if you want to trim them down to get rid of all the sample data and such to be a better (empty) starting point for real projects.</p> <p><a href="http://www.silverlightshow.net/Storage/Sources/Prism101Part1.zip" target="_blank">Download the source code for the Prism 101 completed solution.</a></p> <h3>Summary</h3> <p>In this article I gave you a quick introduction to the concepts and capabilities of Prism and walked you through creating your first Prism application, explaining as we went what some of the moving parts and pieces are that make a Prism application a little different than a normal Silverlight app. You saw that there is some initialization required with the bootstrapper to get the Prism services and types initialized to support your application. The bootstrapper is also where you create your main shell view as your RootVisual and where you indicate, either directly or indirectly through a module catalog XAML file, which modules you want to load into your application. You then saw how to define a module and get it initialized, as well as how to plug views into the shell with Regions. In the next article, I’ll put a little more “meat” in the views to include some commands and the MVVM pattern. In later articles I’ll expand to multiple modules, navigation, events and more. </p> <h3>About the Author</h3> <p>Brian Noyes is Chief Architect of <a href="http://www.idesign.net/" target="_blank">IDesign</a>, a Microsoft Regional Director, and Silverlight MVP. He is a frequent top rated speaker at conferences worldwide including Microsoft TechEd, DevConnections, VSLive!, DevTeach, and others. Brian worked directly on the Prism team with Microsoft patterns and practices and co-authored the book Developers Guide to Microsoft Prism4. He is also the author of Developing Applications with Windows Workflow Foundation, Smart Client Deployment with ClickOnce, and Data Binding in Windows Forms 2.0. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at <a href="http://briannoyes.net/">http://briannoyes.net/</a> or on Twitter @briannoyes.</p> http://www.silverlightshow.net/items/Working-with-Prism-4-Part-1-Getting-Started.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/Working-with-Prism-4-Part-1-Getting-Started.aspx#comments http://www.silverlightshow.net/items/Working-with-Prism-4-Part-1-Getting-Started.aspx Mon, 07 Nov 2011 08:15:00 GMT WP7 for iPhone and Android Developers - MVC and MVVM <div style="border:1px solid #dddddd;border-image: initial; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>Don't miss...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Webinars.aspx">Free SilverlightShow Webinars</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Windows-Phone-7-Part-1-Getting-Started.aspx">WP7 series by Andrea Boschin</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/wp7_iphone_android.aspx">The WP7 for iOS and Android series now available as an Ebook:</a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/wp7_iphone_android.aspx%22"><img style="border-color: initial; border-color: initial; border-color: initial; width: 100px; height: 141px; border-color: initial; border-width: 0px;border-style: solid;" alt="Windows Phone 7 for Silverlight Developers Ebook" src="http://www.silverlightshow.net/Storage/Ebooks/wp7_iphone.png" usemap="#rade_img_map_1291385581316" /></a><br /> <strong><span style="font-size: 13px;">($2.99)</span></strong></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>So far in this series of articles, we have been taking topics that might be second nature to iOS developers and relating them to the relatively new feature set found in the Windows Phone 7 SDK. Typically this involves talking about a few classes and code samples as they might appear in iOS and then relating them to classes with a similar purpose in the WP7 SDK. </p> <p>This article focuses more on a set of design patterns to illustrate that patterns themselves are universal and the code used to implement them is secondary to the pattern and its purpose. In this article we’ll take a look at the Model – View – Controller pattern and a variant of it, the Model-View-ViewModel pattern.</p> <p>In a typical data-bound user interface you generally have a view composed of controls and these controls are usually bound to some underlying source of data. For example, if you have a customer edit form you might have controls like text fields for editing the customer’s name and address and other types of controls for editing additional customer data. The model in this scenario might be an object called Customer (which could be a regular Objective-C or C# object or it could have been served up by a database access library or an Object-Relational Mapper).</p> <p>If this were an iOS application you might have created a class called <strong>CustomerEditViewController</strong> which inherits from <strong>UIViewController</strong>. The view is actually a view hierarchy composed of controls that allow a user to edit customers. Because iOS doesn’t actually support bindings the way the full desktop version of Cocoa does (or WP7 for that matter) the controller has to do an awful lot of work to react to user input and manually force values into control properties. </p> <p>A typical Model-View-Controller interaction looks like the following diagram:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KotanCode/16fig01_2.png"><img style="border:0px; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px;" title="16fig01" alt="16fig01" src="http://www.silverlightshow.net/Storage/Users/KotanCode/16fig01_thumb.png" width="433" height="294" /></a></p> <p>In a bindings-capable environment, the model is bound to the view and the model is loaded and updated by the controller. Additional properties of the view are dealt with by the controller and user interaction events are passed on to the controller for handling.</p> <p>This works out pretty well in many scenarios and it’s original goal of separating concerns to make our applications easier to maintain and debug is still valid. Unfortunately what happens quite often is that with the MVC pattern we only have a single model. In order to keep bindings working, we end up making changes to the model to accommodate things that only have relevance in the UI. For example, we might add an <strong>isSelected</strong> property to the <strong>Customer</strong> class so that we can modify the background color of currently selected customers or, we’ll add a <strong>CurrentCustomer</strong> object to some other model and use that to help our UI maintain navigational consistency.</p> <p>In a typical iOS scenario, we might have a <strong>UITableViewController</strong> subclass. This class is responsible for handing instances of custom view cells to the UI subsystem. It performs the customization of these cells by pulling information from a model. </p> <p>What we really need are two different types of models. The first type is a model that represents the actual source of data which will more than likely be some kind of POCO (Plain-Old C# Object) that came from a database, an XML file, a Web Service, or somewhere else. The second type of model is a model whose properties and behaviors are designed specifically to support the view with which the user interacts. This type we call a <strong>View Model</strong>, and it is part of a variant of the MVC pattern called Model-View-ViewModel.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KotanCode/16fig03_2.png"><img style="border:0px; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px;" title="16fig03" alt="16fig03" src="http://www.silverlightshow.net/Storage/Users/KotanCode/16fig03_thumb.png" width="431" height="474" /></a></p> <p>In a Model-View-ViewModel pattern, we take advantage of the fact that virtually all aspects of our user interface can be controlled via data binding. We wouldn’t really need to add the complexity of this pattern to our iOS applications because we don’t have bindings support but it comes in <em>extremely</em> handy when building large Windows Phone 7 applications.</p> <p>Notice that this pattern doesn’t actually have a controller – there is no single over-arching all-powerful class that is responsible for coordinating everything. This takes a little getting used to at first, but, once you’ve gotten into the habit of building highly data-bound UIs in Windows Phone 7, the use of MVVM seems like a natural evolution.</p> <p>As mentioned, MVVM is a <em>pattern</em>, it is a way of doing things and, as such, there is no single right way of doing it. For example, one thing people strive for in MVVM is to have as little code in a view’s code-behind as possible (it’s really not possible to avoid this entirely). If you ask folks building MVVM applications today about code-behind, you will probably start an argument.</p> <p>One concept that is especially hard for iOS developers to let go of is the idea of the controller. If you find yourself writing code that looks like this:</p> <p><em>myControl.Text = myModel.Property;</em></p> <p>Then you need to stop right there – this isn’t MVVM. Your view needs to be bound to a view model and the properties of the various controls and sub-controls should all be set via bindings and converters wherever possible. The trick with MVVM is figuring out how your view needs to get instances of view models. You can do this by creating factory methods, or you can use a <em>view model locator</em>, which is a static helper class responsible for doling out instances of view models to views.</p> <p>Take a look at the following XAML, which illustrates how you might create a single customer view that is bound to a view model object:</p> <div style="border:1px solid silver;border-image: initial; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow-x: auto; overflow-y: auto; cursor: text; padding-top: 4px; text-align: left;" id="codeSnippetWrapper"> <div style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;" id="codeSnippet"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> 1:</span> <phone:PhoneApplicationPage x:Class=<span style="color: #006080;">"MyApp.CustomerPage"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> 2:</span> ...</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> 3:</span> DataContext=<span style="color: #006080;">"{Binding Customer,Source={StaticResource Locator}}"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> 4:</span> ...</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> 5:</span> </phone:PhoneApplicationPage></pre> <!--CRLF--></div> </div> <p>Basically what we’re saying is that there is a <em>view model</em> object called <em>Customer</em> to which this entire page is bound. This is also a very common practice with MVVM – try and make the binding as wide in scope as possible. It might be hard at first, but try and match your view models directly to pages and user controls. The benefit of having a view model in addition to a data-centric model is that you can have multiple view models for a single model, with each view model tailored specifically for a given control or page.</p> <p>Inside our <strong>App.xaml</strong> we can declare a global resource that points to the <em>view model locator</em>:</p> <div style="border:1px solid silver;border-image: initial; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow-x: auto; overflow-y: auto; cursor: text; padding-top: 4px; text-align: left;" id="codeSnippetWrapper"> <div style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;" id="codeSnippet"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> 1:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Application.Resources</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> 2:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">vm:ViewModelLocator</span> <span style="color: #ff0000;">x:Key</span><span style="color: #0000ff;">="Locator"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> 3:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">Application.Resources</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>Here “vm” is the namespace prefix of the CLR namespace where we have our view model locator defined. This class really just has public properties on it that allow our XAML to obtain instances of view models. This is also unfamiliar territory for iOS developers and developers who traditionally follow a more MVC style. Instead of having a controller object that knows about the view and knows about the model that is responsible for hooking the two up, the view declares its intent via bindings. In the sample case, the view says that it should be bound to a view model called <em>Customer</em> which can be found on the view model locator class. The view model locator is responsible for <em>instantiating </em>the view model. During this instantiation, the view model also typically has an <em>initialization</em> method which is called directly or indirectly (again, this is a source of difference and debate depending on how you decide to implement your MVVM pattern).</p> <p>So the flow of control and instantiation might go something like this: <em>Customer View Page –> Locator –> Customer View Model –> Customer Model (database or web service source)</em>.</p> <p>The UI intentionally has absolutely no idea how the bound data is actually persisted on disk (or in the cloud). All it cares about is how the data is represented visually to the user and made available for interaction – this is the job of the view model. Many of the tasks we traditionally keep in controllers, such as responding to user input and manipulating model values, all take place within the view model whenever possible.</p> <p>At first you might be thinking that MVVM seems a lot more complicated than just having code-behind in your WP7 views that manipulates controls directly, especially when this looks a lot like the code you may have been writing in iOS. For really small applications, this may be true. However, once you start writing applications that have several pages and these pages have multiple controls, different states, and need to respond to when users navigate to and away from those pages and finally when you try and attach an asynchronous data source (such as web services in the cloud) to your application – the small increase in complexity of code is well worth it in the long run.</p> <p>Bindings is only a small part of MVVM, it is far more than that. Let’s take another very common scenario – navigating between pages. In iOS, you might write code in a method that is invoked when a user selects a row in a table view. Here, you might create an instance of the view controller responsible for the next screen and then <em>pop</em> it into the stack via the navigation controller. If this view controller needs a model in order to prep the UI, the parent controller is often responsible for creating an instance of this model, loading it from some source, and then passing it as a parameter to the child controller.</p> <p>With MVVM we do things a little differently. A user might tap a button which results in the <em>execution</em> of a <em>Command</em> object that is actually a property of the view model (view models encapsulate both behavior <em>and </em>data!). As a result of this execution, a message might be broadcast indicating that Customer 123 has been selected. The <em>CustomerViewModel</em> class is listening for such a message. When it receives this message, it loads Customer 123 from disk, populates all of its properties accordingly, and then tells the WP7 navigation system to navigate to the <em>CustomerView.xaml</em> page. As you can see, the “concerns” here are even more separate than in MVC – the parent controller doesn’t actually know what happens when someone selects a customer and many proponents of MVVM argue that it shouldn’t. The view model that backs the view that should appear upon selecting a customer is responsible for listening for the event (or events, and this is key to re-usability) that trigger the appearance of that view.</p> <p>It might seem like a minor detail but if you go back into an application written MVC style a few months after writing it – it could take you a very long time to figure out all of the different paths through an application. If you’re looking at an MVVM view model, then a quick glance at the message subscribers on that model will tell you exactly the list of actions that can cause that view to appear.</p> <p>In this article I’ve tried to explain the basics of the MVVM pattern and how it differs from the MVC pattern that iOS developers are familiar with. I have deliberately avoided talking about any one MVVM implementation because the decision as to which MVVM library you use (or whether you roll your own) is entirely up to you. </p> <p>MVVM isn’t limited to just Windows Phone 7, and there are implementations on just about every platform you can imagine. For Windows Phone 7, the library that I have used most often is MVVM Lite. If you don’t feel like writing your own view model locator classes, your own pub/sub messaging system, and your own command helpers, then using a library like MVVM Lite will save you a lot of time and effort.</p> <p>At one point, the installation process for MVVM Lite was so cumbersome that many people just wrote their own stuff rather than attempting the install. Recently, they have released an automated installer that makes adopting MVVM Lite much easier. You can find the code for MVVM Lite, the downloader, and related documentation here: <a href="http://mvvmlight.codeplex.com/">http://mvvmlight.codeplex.com/</a>.</p> <p>In closing, iOS developers are very used to having to manually fetch objects from a data source via a controller and then, using that same controller, instantiate custom views and set view properties and manually build view hierarchies programmatically. Using the MVVM pattern on Windows Phone 7 allows developers to take full advantage of bindings, resource dictionaries, templating, and the flexibility of Xaml-based object hierarchies. As an iOS developer if you ever find yourself writing code like this:</p> <p><em>myControl.Text = myModel.TextProperty;</em></p> <p>Then you should take a step back and see if the MVVM pattern and possibly an MVVM toolkit might help you.</p> http://www.silverlightshow.net/items/WP7-for-iPhone-and-Android-Developers-MVC-and-MVVM.aspx editorial@silverlightshow.net (Kevin Hoffman ) http://www.silverlightshow.net/items/WP7-for-iPhone-and-Android-Developers-MVC-and-MVVM.aspx#comments http://www.silverlightshow.net/items/WP7-for-iPhone-and-Android-Developers-MVC-and-MVVM.aspx Thu, 01 Sep 2011 13:41:00 GMT The ABC of streaming in Silverlight <p style="text-align: justify;">Advanced media integration is one of Silverlight’s greatest strengths. In this tutorial we delve into this topic by carrying out some simple exercises. We will learn how to play a movie, how to interact with webcam and microphone and how to create a live streaming solution using Expression Encoder 4 and VLC and capture it in a Silverlight application.</p> <h2>Play a movie</h2> <p style="text-align: justify;">In Silverlight there is a native control called MediaElement which allows you to do a lot of things. The first thing obviously is the possibility to play a video: using its <em>Source</em> property you can define the location of the video you want to see and you can use either a relative or absolute URL. Suppose you have a collection of videos in a subdirectory called “Videos” of your web application and you want to play one of them. The xaml code snippet below is all you will need:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><Grid x:Name=<span style="color: #006080;">"LayoutRoot"</span> ></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><MediaElement x:Name=<span style="color: #006080;">"mediaEl"</span> Source=<span style="color: #006080;">"videos/video1.wmv"</span> /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"></Grid></pre> <!--CRLF--></div> </div> <p style="text-align: justify;">If you launch the application the movie will start automatically. This happens because the <em>Autostart</em> property of the MediaElement is true by default. To control the video, the MediaElement exposes the canonical Play(), Pause() and Stop() methods. At this point adding a commandbar to control the video is fairly easy ; just add a StackPanel in the xaml as below:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><StackPanel Name=<span style="color: #006080;">"CommandBar"</span> Orientation=<span style="color: #006080;">"Horizontal"</span> Background=<span style="color: #006080;">"Beige"</span> Height=<span style="color: #006080;">"39"</span> Width=<span style="color: #006080;">"783"</span> Margin=<span style="color: #006080;">"5"</span> HorizontalAlignment=<span style="color: #006080;">"Center"</span> Canvas.Left=<span style="color: #006080;">"3"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><Button Name=<span style="color: #006080;">"PlayMovie"</span> Background=<span style="color: #006080;">"AntiqueWhite"</span> Content=<span style="color: #006080;">"Play"</span> FontWeight=<span style="color: #006080;">"Bold"</span> Click=<span style="color: #006080;">"PlayMovie_Click"</span> Margin=<span style="color: #006080;">"50,5,0,5"</span> Width=<span style="color: #006080;">"100"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><Button Name=<span style="color: #006080;">"PauseMovie"</span> Background=<span style="color: #006080;">"AntiqueWhite"</span> Content=<span style="color: #006080;">"Pause"</span> FontWeight=<span style="color: #006080;">"Bold"</span> Click=<span style="color: #006080;">"PauseMovie_Click"</span> Margin=<span style="color: #006080;">"50,5,0,5"</span> Width=<span style="color: #006080;">"100"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><Button Name=<span style="color: #006080;">"VideoStop"</span> Background=<span style="color: #006080;">"AntiqueWhite"</span> Content=<span style="color: #006080;">"Stop"</span> FontWeight=<span style="color: #006080;">"Bold"</span> Click=<span style="color: #006080;">"VideoStop_Click"</span> Margin=<span style="color: #006080;">"50,5,0,5"</span> Width=<span style="color: #006080;">"100"</span> /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"></StackPanel></pre> <!--CRLF--></div> </div> <p> </p> <p>And, in the code behind, the following event handlers:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> PlayMovie_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span>(mediaEl.CurrentState != MediaElementState.Opening ||</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> mediaEl.CurrentState == MediaElementState.Stopped ||</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> mediaEl.CurrentState == MediaElementState.Paused)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> mediaEl.Play();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> PauseMovie_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (mediaEl.CurrentState == MediaElementState.Playing)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> mediaEl.Pause();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> VideoStop_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span>(mediaEl.CurrentState == MediaElementState.Playing ||</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> mediaEl.CurrentState == MediaElementState.Paused)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> mediaEl.Stop();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--></div> </div> <p> </p> <p>Let’s focus on the video formats supported. The list below recaps all the formats recognized by Silverlight 4:</p> <p> </p> <table width="539" border="0" cellspacing="0" cellpadding="2"> <tbody> <tr> <td valign="top" style="width: 149px;"><strong>Container</strong></td> <td valign="top" style="width: 388px;"><strong>Supported Codecs</strong></td> </tr> <tr> <td valign="top" style="width: 149px;"><span style="font-size: 13px;">ASF (Windows Media)</span></td> <td valign="top" style="width: 388px;"> <p><span style="font-size: 13px;">Windows Media Audio 7, 8, 9 (WMA Standard) <br /> Windows Media Audio 9, 10 (WMA Professional) <br /> WMV1 (Windows Media Video 7) <br /> WMV2 (Windows Media Video 8) <br /> WMV3 (Windows Media Video 9)</span></p> </td> </tr> <tr> <td valign="top" style="width: 149px;"><span style="font-size: 13px;">MP4</span></td> <td valign="top" style="width: 388px;"> <p><span style="font-size: 13px;">H.264, AAC-LC, HE-AAC v1 (AAC+), HE-AAC v2 (eAAC+)</span></p> </td> </tr> <tr> <td valign="top" style="width: 149px;"><span style="font-size: 13px;">MP3</span></td> <td valign="top" style="width: 388px;"><span style="font-size: 13px;">ISO MPEG-1 Layer III (MP3)</span></td> </tr> </tbody> </table> <p> </p> <h2>Drop & Know…</h2> <p style="text-align: justify;">How do we know if a video is supported? Well, instead of digging into the properties of the file and compare them with the list above, we can be way more pragmatic, i.e. by simply dragging the video from the file system to the Silverlight app and dropping it over the MediaElement. If the MediaElment does not recognize the video, it fires an exception that we can catch the internal error and redirect to the user as a comprehensible message. Let’s see how we can achieve that.</p> <p style="text-align: justify;">After seeing the list of the properties of the MediaElement you will find that it exposes an AllowDrop property since it derives from UIElement . Yet hooking a drop event here won’t work because the Mediaelement is not a container. No panic! You can embed the MediaElement in a Canvas container and handle the drop event of this one. In the xaml below the Canvas object incorporates the StackPanel above mentioned and the MediaElement:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><Canvas Drop=<span style="color: #006080;">"VideoCanvas_Drop"</span> x:Name=<span style="color: #006080;">"VideoCanvas"</span> Width=<span style="color: #006080;">"800"</span> Height=<span style="color: #006080;">"600"</span> AllowDrop=<span style="color: #006080;">"True"</span> Background=<span style="color: #006080;">"RosyBrown"</span> HorizontalAlignment=<span style="color: #006080;">"Center"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <StackPanel Name=<span style="color: #006080;">"CommandBar"</span> Orientation=<span style="color: #006080;">"Horizontal"</span> Background=<span style="color: #006080;">"Beige"</span> Height=<span style="color: #006080;">"39"</span> Width=<span style="color: #006080;">"783"</span> Margin=<span style="color: #006080;">"5"</span> HorizontalAlignment=<span style="color: #006080;">"Center"</span> Canvas.Left=<span style="color: #006080;">"3"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Button Name=<span style="color: #006080;">"PlayMovie"</span> Background=<span style="color: #006080;">"AntiqueWhite"</span> Content=<span style="color: #006080;">"Play"</span> FontWeight=<span style="color: #006080;">"Bold"</span> Click=<span style="color: #006080;">"PlayMovie_Click"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Margin=<span style="color: #006080;">"50,5,0,5"</span> Width=<span style="color: #006080;">"100"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Button Name=<span style="color: #006080;">"PauseMovie"</span> Background=<span style="color: #006080;">"AntiqueWhite"</span> Content=<span style="color: #006080;">"Pause"</span> FontWeight=<span style="color: #006080;">"Bold"</span> Click=<span style="color: #006080;">"PauseMovie_Click"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Margin=<span style="color: #006080;">"50,5,0,5"</span> Width=<span style="color: #006080;">"100"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Button Name=<span style="color: #006080;">"VideoStop"</span> Background=<span style="color: #006080;">"AntiqueWhite"</span> Content=<span style="color: #006080;">"Stop"</span> FontWeight=<span style="color: #006080;">"Bold"</span> Click=<span style="color: #006080;">"VideoStop_Click"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Margin=<span style="color: #006080;">"50,5,0,5"</span> Width=<span style="color: #006080;">"100"</span> /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </StackPanel></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <MediaElement x:Name=<span style="color: #006080;">"mediaEl"</span> Canvas.Top=<span style="color: #006080;">"50"</span> Width=<span style="color: #006080;">"800"</span> Height=<span style="color: #006080;">"450"</span> AutoPlay=<span style="color: #006080;">"False"</span> /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"></Canvas></pre> <!--CRLF--></div> </div> <p> </p> <p>Let’s take a look at the VideoCanvas_Drop event handler:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">void</span> VideoCanvas_Drop(<span style="color: #0000ff;">object</span> sender, DragEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> DragEventArgs dr = e <span style="color: #0000ff;">as</span> DragEventArgs;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (dr.Data == <span style="color: #0000ff;">null</span>)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> IDataObject dataObject = dr.Data <span style="color: #0000ff;">as</span> IDataObject;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> FileInfo[] files = dataObject.GetData(DataFormats.FileDrop) <span style="color: #0000ff;">as</span> FileInfo[];</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span>(files.Count() > 0)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> mediaEl.SetSource(files[0].OpenRead());</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <p> </p> <p style="text-align: justify;">The trick here is to use the <em>SetSource</em> property of the MediaElement instead of <em>Source.</em> Since it accepts a Stream as an argument, we can pass it the FileStream related to the dropped file. If the FileStream does not contain a natively supported media source then the MediaElement fires a <em>MediaFailed</em> event that we can catch as below:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> MainPage()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> InitializeComponent();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> mediaEl.MediaFailed += <span style="color: #0000ff;">new</span> EventHandler<ExceptionRoutedEventArgs>(mediaEl_MediaFailed);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> …</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">void</span> mediaEl_MediaFailed(<span style="color: #0000ff;">object</span> sender, ExceptionRoutedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> WarningTxtBlock.Text = <span style="color: #006080;">"Cannot open this media:\r\n"</span> + e.ErrorException.Message;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <p> </p> <h2>Using a webcam</h2> <p style="text-align: justify;">Starting From Silverlight 4 it is possible to access to webcam and microphone of the machine. Fortunately the steps required to get a working application are nicely easy. We need substantially two objects: a VideoCaptureDevice and a CaptureSource.</p> <p> </p> <div> <pre id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> VideoCaptureDevice myWebCam;<br /><span style="color: #0000ff;">private</span> CaptureSource myCaptureSource;</pre> </div> <div> </div> <p style="text-align: justify;">The first represents the physical webcam and the second one offers some methods to manage the webcam. In this case we won’t use a MediaElement but a VideoBrush object to paint a Rectangle with the video stream coming from the webcam. Let’s create a new Silverlight project and add the following xaml code to the MainPage.xaml:</p> <p> </p> <div> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><Grid x:Name=<span style="color: #006080;">"LayoutRoot"</span> Background=<span style="color: #006080;">"Black"</span> Width=<span style="color: #006080;">"1024"</span> Height=<span style="color: #006080;">"768"</span> ></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Grid.ColumnDefinitions></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <ColumnDefinition /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <ColumnDefinition /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </Grid.ColumnDefinitions></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Grid.RowDefinitions></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <RowDefinition Height=<span style="color: #006080;">"*"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <RowDefinition Height=<span style="color: #006080;">"70"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </Grid.RowDefinitions></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <StackPanel Orientation=<span style="color: #006080;">"Horizontal"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> HorizontalAlignment=<span style="color: #006080;">"Center"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Grid.ColumnSpan=<span style="color: #006080;">"2"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Grid.Row=<span style="color: #006080;">"1"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Button Width=<span style="color: #006080;">"70"</span> Height=<span style="color: #006080;">"30"</span> Margin=<span style="color: #006080;">"8"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> x:Name=<span style="color: #006080;">"StartButton"</span> Click=<span style="color: #006080;">"StartButton_Click"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Content=<span style="color: #006080;">"Start"</span> /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Button Width=<span style="color: #006080;">"70"</span> Height=<span style="color: #006080;">"30"</span> Margin=<span style="color: #006080;">"8"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> x:Name=<span style="color: #006080;">"StopButton"</span> Click=<span style="color: #006080;">"StopButton_Click"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Content=<span style="color: #006080;">"Stop"</span> /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Button Width=<span style="color: #006080;">"70"</span> Height=<span style="color: #006080;">"30"</span> Margin=<span style="color: #006080;">"8"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> x:Name=<span style="color: #006080;">"SnapshotButton"</span> Click=<span style="color: #006080;">"SnapshotButton_Click"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Content=<span style="color: #006080;">"Snapshot"</span> /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </StackPanel></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Border Background=<span style="color: #006080;">"DarkRed"</span> BorderBrush=<span style="color: #006080;">"Beige"</span> BorderThickness=<span style="color: #006080;">"5"</span> Height=<span style="color: #006080;">"380"</span> Margin=<span style="color: #006080;">"10,25,10,10"</span>> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Rectangle x:Name=<span style="color: #006080;">"webcamRectangle"</span> /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </Border></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Border Background=<span style="color: #006080;">"Gray"</span> BorderBrush=<span style="color: #006080;">"Beige"</span> Grid.Row=<span style="color: #006080;">"0"</span> Grid.Column=<span style="color: #006080;">"1"</span> BorderThickness=<span style="color: #006080;">"5"</span> Height=<span style="color: #006080;">"380"</span> Margin=<span style="color: #006080;">"10,25,10,10"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Rectangle x:Name=<span style="color: #006080;">"snapshotRectangle"</span> /></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </Border></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"></Grid></pre> <!--CRLF--></div> </div> </div> <div> </div> <p style="text-align: justify;">As you can see there are two rectangles; the first will be painted with the VideoBrush and the second will be used to show a snapshot from the video. Now in the .cs file we can initialize the two objects mentioned above (myWebCam and myCaptureSource) and prepare everything for the video capture:</p> <p style="text-align: justify;"> </p> <div> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> InitializeWebCam()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> myCaptureSource = <span style="color: #0000ff;">new</span> CaptureSource();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">//1° step: get the default capture device</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> myWebCam = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// 2° step: indicate the video capture device to be used by the CaptureSource </span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> myCaptureSource.VideoCaptureDevice = myWebCam;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// 3° step: initialize a VideoBrush with the CaptureSource just initialized </span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> myVideoBrush = <span style="color: #0000ff;">new</span> VideoBrush();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> myVideoBrush.SetSource(myCaptureSource);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// 4° step: fill the Rectangle with the stream provided by the VideoBrush</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> webcamRectangle.Fill = myVideoBrush;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--></div> </div> </div> <div> </div> <p style="text-align: justify;">As you see, getting the VideoCaptureDevice that represents the webcam available is just a matter of calling the <em>GetDefaultVideoCaptureDevice()</em> of the static CaptureDeviceConfiguration class. Then we have to indicate the myCaptureSource object which is the video capture device from which we want to actually capture. The following step is to initialize a VideoBrush object and set its source to the myCaptureSource. In this way the VideoBrush is ready to paint a target with the stream coming from the capture device. This is what has been done in the fourth step. We then have to handle the click events of the play and stop buttons to control the video:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> StartButton_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (CaptureDeviceConfiguration.AllowedDeviceAccess ||</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> CaptureDeviceConfiguration.RequestDeviceAccess())</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> myCaptureSource.Start();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> StopButton_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (CaptureDeviceConfiguration.AllowedDeviceAccess ||</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> CaptureDeviceConfiguration.RequestDeviceAccess())</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> myCaptureSource.Stop();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <div> </div> <p style="text-align: justify;">As you may notice before starting or stopping the capture we need to make a formal request in order to use the webcam and/or the microphone. The first time involves opening a dialog box asking for an explicit consent for access to the webcam and microphone as in the image below:</p> <p style="text-align: justify;"><img alt="" src="http://www.silverlightshow.net/Storage/AllowSL4toAccessWebcamMic.jpg" /></p> <div>Fortunately the following accesses can skip this request by checking if the AllowedDeviceAccess flag is set. This means that this explicit consent request saves you from being watched when you are picking your nose.</div> <p style="text-align: justify;">And what about a snapshot taken from the video? Nothing complicated! just modify the previous <em>InitializeWebcam()</em> method by adding this code snippet at the end:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">mySnapshotBrush = <span style="color: #0000ff;">new</span> ImageBrush();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">snapshotRectangle.Fill = mySnapshotBrush;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">myCaptureSource.CaptureImageCompleted +=<span style="color: #0000ff;">new</span> EventHandler<CaptureImageCompletedEventArgs>(myCaptureSource_CaptureImageCompleted);</pre> <!--CRLF--></div> </div> <p style="text-align: justify;">In the code above the snapshotRectangle is the Rectangle where we want to place the snapshot and its <em>Fill</em> property is set to an ImageBrush. So when the ImageBrush contains an image it is painted on the rectangle. How do we acquire an image from the video? You can use the <em>CaptureImageAsync()</em> method of the CaptureSource object. Since it is an asynchronous method you need to add an event handler to the CaptureImageCompleted event of the CaptureSource as shown below:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">void</span> myCaptureSource_CaptureImageCompleted(<span style="color: #0000ff;">object</span> sender, CaptureImageCompletedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> mySnapshotBrush.ImageSource = e.Result;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <p> </p> <p>You are almost done; </p> <p>the only thing to add is calling the async method when the snapshot button is clicked:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> SnapshotButton_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (myCaptureSource.VideoCaptureDevice != <span style="color: #0000ff;">null</span> &&</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> myCaptureSource.State == CaptureState.Started)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> myCaptureSource.CaptureImageAsync();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <p> </p> <h2>Capturing a live stream</h2> <p style="text-align: justify;">To capture a live stream we will use the MediaElement object again. But first we need a media streaming source. Fortunately there is more than one way to create your own little home streaming service to experiment a little. In the next paragraph we will learn how to broadcast the webcam on our pc live over the network using two different programs, Microsoft Expression Encoder 4 and VLC media player.</p> <p style="text-align: justify;"> </p> <h3>Live broadcasting with Expression Encoder</h3> <p style="text-align: justify;">Microsoft Expression Encoder 4 is freely downloadable from <a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=5c3c5f97-678c-4c99-a7fc-f84f320c626f#QuickDetails">here</a> . Unlike the professional version, i.e. Encoder PRO 4, it does not support live Smooth Streaming and does not have support for H.264 but it is more than enough for our purposes. When you start the program you will find three options as in the image below:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/Encoder1_2.png"><img width="635" height="484" title="Encoder1" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Encoder1" src="http://www.silverlightshow.net/Storage/Users/walterf/Encoder1_thumb.png" /></a></p> <p> </p> <p style="text-align: justify;">Then Expression Encoder offers you a rich UI to create your own streaming project. The first step to do is to add a Live Source. After doing so a yellow framed box appears in the “Live Sources” area on the left:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/Encoder2_2.png"><img width="644" height="364" title="Encoder2" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Encoder2" src="http://www.silverlightshow.net/Storage/Users/walterf/Encoder2_thumb.png" /></a></p> <p> </p> <p style="text-align: justify;">Focusing on the “Live Source 1” just created you can attach a video device to it by choosing “Video Device” from the drop down list. If you have at least one webcam on board it should be listed in the drop down as below:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/Encoder3_2.png"><img width="310" height="484" title="Encoder3" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Encoder3" src="http://www.silverlightshow.net/Storage/Users/walterf/Encoder3_thumb.png" /></a></p> <p style="text-align: justify;">Similarly you can add an audio device choosing from the drop down list below. By the way, there is no simple way here to set an IP webcam as a video source since Encoder 4 has no support for RTSP streams. In that case you need a directshow source filter. <br /> Once you have your working live source you have to activate it by clicking on the “Cue” button in the box:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/Encoder4_2.png"><img width="352" height="484" title="Encoder4" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Encoder4" src="http://www.silverlightshow.net/Storage/Users/walterf/Encoder4_thumb.png" /></a></p> <p style="text-align: justify;">Now let’s focus on the “Presets” section on the right. Starting from the top there is a System tab which collects several predefined encoding profiles. In my experience the best compromise between video quality and latency (I will go back to this later on) is the “Standard Encoding / VC-1 High Speed Broadband” preset.</p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/Encoder5_2.png"><img width="214" height="484" title="Encoder5" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Encoder5" src="http://www.silverlightshow.net/Storage/Users/walterf/Encoder5_thumb.png" /></a></p> <p style="text-align: justify;">You can try to change the video parameters, for instance reducing the Buffer Window but probably you will lose quality in the video.</p> <p style="text-align: justify;">The final step is set your output type. In order to be able to capture the live stream from a Silverlight application we will choose the broadcast - streaming option on port 8080 as below:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/Encoder6_2.png"><img width="291" height="484" title="Encoder6" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Encoder6" src="http://www.silverlightshow.net/Storage/Users/walterf/Encoder6_thumb.png" /></a></p> <p>Now you are ready to press the start button in the centre:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/Encoder7_2.png"><img width="433" height="159" title="Encoder7" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Encoder7" src="http://www.silverlightshow.net/Storage/Users/walterf/Encoder7_thumb.png" /></a></p> <p> </p> <h2>Live broadcasting with VLC</h2> <p style="text-align: justify;">VLC is known as an efficient and free multimedia player but perhaps not everybody knows that it can be used also as a streaming server. The nice thing is that it is able to stream all that it can read, for instance it can perform a live broadcasting stream even from an IP camera. But let’s stay on track: here as in the Expression Encoder tutorial above, we want to capture the video from the built-in webcam of our PC and stream it over the network. So let’s download the software from <a href="http://www.videolan.org/vlc/index.html">here</a> and read the following steps.</p> <p style="text-align: justify;">The first thing to do is to open the “Media” menu and choose “Open Capture Device…”:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/vlc1_2.png"><img width="282" height="339" title="vlc1" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="vlc1" src="http://www.silverlightshow.net/Storage/Users/walterf/vlc1_thumb.png" /></a></p> <p>In the dialog box make sure to select your built-in webcam in the “Video device name” section as in the image below:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/vlc2_2.png"><img width="498" height="484" title="vlc2" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="vlc2" src="http://www.silverlightshow.net/Storage/Users/walterf/vlc2_thumb.png" /></a></p> <p>As for the audio device, you can do the same. Then click on the pick button at the right of the play button to get the other button options as below:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/vlc3_2.png"><img width="437" height="484" title="vlc3" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="vlc3" src="http://www.silverlightshow.net/Storage/Users/walterf/vlc3_thumb.png" /></a></p> <p>A new stream configuration wizard will appear. On the first page just click on the “next” button to jump directly to the “Destinations” configuration:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/vlc4_2.png"><img width="562" height="484" title="vlc4" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="vlc4" src="http://www.silverlightshow.net/Storage/Users/walterf/vlc4_thumb.png" /></a></p> <p> </p> <p style="text-align: justify;">In the “Destinations” page there are two things to do: one is configuring the streaming method and the other is choosing the appropriate transcoding. Let’s start with the first one. Open the “New destination” dropdown list and choose the MS-WMSP (MMSH) option as below:</p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/vlc5_2.png"><img width="644" height="239" title="vlc5" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="vlc5" src="http://www.silverlightshow.net/Storage/Users/walterf/vlc5_thumb.png" /></a></p> <p style="text-align: justify;"> </p> <p style="text-align: justify;">Don’t forget to set the “Display locally” check box in order to be able to capture the live stream from the same PC. Then click to “Add” button on the right of the drop down list. You should see something like that:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/vlc6_2.png"><img width="644" height="176" title="vlc6" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="vlc6" src="http://www.silverlightshow.net/Storage/Users/walterf/vlc6_thumb.png" /></a></p> <p> </p> <p style="text-align: justify;">The streaming method configuration is completed. Lets’ focus on the transcoding options below now. Expand the Profile dropdown list and choose the “video – VMW + WMA (ASF) option. Then click on the edit button:</p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/vlc7_2.png"><img width="644" height="261" title="vlc7" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="vlc7" src="http://www.silverlightshow.net/Storage/Users/walterf/vlc7_thumb.png" /></a></p> <p style="text-align: justify;">In the Edit Trascoding dialog box, click on the “Video codec tab and select the WMV2 codec as below (it could be already automatically set):</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/vlc8_2.png"><img width="611" height="484" title="vlc8" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="vlc8" src="http://www.silverlightshow.net/Storage/Users/walterf/vlc8_thumb.png" /></a></p> <p style="text-align: justify;">Click on “Save” to return to the “Destinations” page. Click on “Next” to go to the final page where there is a useful output string which allows you to launch vlc.exe with the same configuration by adding it to the command line. Click on the “Stream” button and you are done.</p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/vlc9_2.png"><img width="563" height="484" title="vlc9" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="vlc9" src="http://www.silverlightshow.net/Storage/Users/walterf/vlc9_thumb.png" /></a></p> <p>The output string is (in case you want to skip all the boring steps above and launch VLC from cmd):</p> <div id="codeSnippetWrapper"> <pre class="csharpcode" id="codeSnippet">Vlc.exe :sout=#transcode{vcodec=WMV2,vb=800,scale=1,acodec=wma2,ab=64,channels=2,samplerate=22050} :no-sout-rtp-sap :no-sout-standard-sap :ttl=1 :sout-keep</pre> <br /> </div> <h2>Using the live broadcasting with Silverlight</h2> <p style="text-align: justify;">In the two previous paragraphs we have seen how to create a live broadcasting using two different softwares and you may expect that in Silverlight you have to configure the source of the stream differently in the two cases. Fortunately it is not true: if you use the configurations shown above you will be able to use one or the other option to your liking. The only requirement you need is to set the Source property of the MediaElement as below using the mms moniker:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><MediaElement x:Name=<span style="color: #006080;">"MediaElement"</span> Width=<span style="color: #006080;">"320"</span> Height=<span style="color: #006080;">"240"</span> Source=<span style="color: #006080;">"mms://127.0.0.1:8080"</span>/></pre> <!--CRLF--></div> </div> <p> </p> <p>Let’s start a new Silverlight project to create a very basic live TV. Include this xaml in the MainPage.xaml:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><Grid x:Name=<span style="color: #006080;">"LayoutRoot"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <StackPanel Orientation=<span style="color: #006080;">"Vertical"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <MediaElement x:Name=<span style="color: #006080;">"MediaElement"</span> Width=<span style="color: #006080;">"320"</span> Height=<span style="color: #006080;">"240"</span> Source=<span style="color: #006080;">"mms://127.0.0.1:8080"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <StackPanel Orientation=<span style="color: #006080;">"Horizontal"</span> HorizontalAlignment=<span style="color: #006080;">"Center"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <TextBlock x:Name=<span style="color: #006080;">"Status"</span> Text=<span style="color: #006080;">"status"</span> Margin=<span style="color: #006080;">"0,5"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <TextBlock x:Name=<span style="color: #006080;">"Buffer"</span> Text=<span style="color: #006080;">"buffer"</span> Margin=<span style="color: #006080;">"10,5"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </StackPanel></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <StackPanel Background=<span style="color: #006080;">"Beige"</span> Orientation=<span style="color: #006080;">"Horizontal"</span> HorizontalAlignment=<span style="color: #006080;">"Center"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Button x:Name=<span style="color: #006080;">"Play"</span> Content=<span style="color: #006080;">"Play"</span> Click=<span style="color: #006080;">"Play_Click"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Button x:Name=<span style="color: #006080;">"Pause"</span> Content=<span style="color: #006080;">"Pause"</span> Click=<span style="color: #006080;">"Pause_Click"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <Button x:Name=<span style="color: #006080;">"Stop"</span> Content=<span style="color: #006080;">"Stop"</span> Click=<span style="color: #006080;">"Stop_Click"</span>/></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </StackPanel></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </StackPanel></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">Grid></pre> <!--CRLF--></div> </div> <p>And in the code behind:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> MainPage()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> InitializeComponent();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> MediaElement.BufferingTime = <span style="color: #0000ff;">new</span> TimeSpan(0,0,0);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> MediaElement.CurrentStateChanged += (sender, e) => {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Status.Text = MediaElement.CurrentState.ToString(); </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Buffer.Visibility = MediaElement.CurrentState == MediaElementState.Buffering ? Visibility.Visible : Visibility.Collapsed;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> };</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">this</span>.MediaElement.BufferingProgressChanged += (sender, e) => {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">this</span>.Buffer.Text = <span style="color: #0000ff;">string</span>.Format(<span style="color: #006080;">"{0:0.0} %"</span>, <span style="color: #0000ff;">this</span>.MediaElement.BufferingProgress * 100);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }; </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> Play_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e) </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">this</span>.MediaElement.Play();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> Pause_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e) </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">this</span>.MediaElement.Pause();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> Stop_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e) </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">this</span>.MediaElement.Stop();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">} </pre> <!--CRLF--></div> </div> <p> </p> <p style="text-align: justify;">As you see, there is a rude panel which contains the basic functionalities (Play, Pause, Stop) to interact with the video. It is interesting that I set to zero the BufferingTime of the MediaElement in order to reduce as much as possible the delay between the real events and what we see through the MediaElement. In fact, in my attempts I measured a latency of around 7 seconds using EE4 and 1,5 seconds using VLC on a private LAN. This latter value is not too bad to me. </p> <h2>Conclusion</h2> <p style="text-align: justify;">Streaming media with Silverlight is easy and funny. The MediaElement object is like a Swiss army knife which allows you to create a complete media player capable of playing a movie, capturing the output of a webcam and even reproducing a live stream. Microsoft Expression encoder 4 and VLC are two great free programs which allow you to create multimedia platforms to play with Silverlight. For more advanced scenarios it could be useful to take a look at the following topics: </p> <ul> <li>MediaStreamSource: a part of the Silverlight runtime which allows direct access to APIs to manipulate audio and video streams. (An example application <a href="http://archive.msdn.microsoft.com/ManagedMediaHelpers">here</a>) </li> <li>IIS Smooth Streaming: an <a href="http://www.iis.net/download/SmoothStreaming">advanced platform</a> which enables you adaptive streaming of media to Silverlight over HTTP. </li> <li>Microsoft Media Platform-Player Framework v.2.5: an open source platform which allows developers to create sophisticated video players for IIS Smooth Streaming delivery. It is available on <a href="http://smf.codeplex.com/">Codeplex</a>. </li> </ul> <h3>About the Author</h3> <p><img alt="" style="width: 100px; float: left; height: 130px; margin-right: 5px;" src="http://www.silverlightshow.net/Storage/BikerWal.jpg" /></p> <p>Walter Ferrari is an environmental engineer and cultivates his passion for software development for a long time. He is currently a consultant working for his company, Abertech. He develops applications based on Microsoft technologies since 1995 and works primarily with .NET since 2003. He is currently focused on Silverlight and Sharepoint and acts as representative of <a href="http://www.completit.com/" target="_blank">CompletIT</a>/SilverlightShow. <br /> Walter is used to wearing a helmet while writing code..just to avoid serious damages when slamming his head against the monitor :) He blogs about his passion at <a href="http://www.snello.it/eng">http://www.snello.it/eng</a></p> <p> </p> http://www.silverlightshow.net/items/The-ABC-of-streaming-in-Silverlight.aspx editorial@silverlightshow.net (Walter Ferrari ) http://www.silverlightshow.net/items/The-ABC-of-streaming-in-Silverlight.aspx#comments http://www.silverlightshow.net/items/The-ABC-of-streaming-in-Silverlight.aspx Tue, 31 May 2011 00:00:00 GMT Silverlight WCF RIA Services: strategies for handling your Domain Context - Part 2 <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>Don't miss...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Deep-dive-into-WCF-part-1-TDD.aspx">Deep Dive Into WCF series</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/WCF-RIA-Services-Part-1-Getting-Started.aspx">WCF article series by B.Noyes</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Search.aspx?q=WCF+RIA+Services+&adv=true&ro=0&t=3&r=10&o=1">WCF RIA Services Shows</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/domain_context.aspx">The Domain Context series is now available as a fully offline resource: </a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/domain_context.aspx"><img style="border:0px solid;" alt="WCF RIA Services: Strategies for Handling Your Domain Context Ebook" src="http://www.silverlightshow.net/Storage/domain_context_thumb.png" usemap="#rade_img_map_1291385581316" /></a><br /> <strong><span style="font-size: 13px;">($0.99)</span></strong></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>This is the second in a two-part article series on the WCF RIA Services Domain Context.</p> <p>This article series is accompanied by source code, which can be downloaded <a href="http://www.silverlightshow.net/Storage/Sources/SilverlightShowDomainContextStrategies.zip" target="_blank">here</a>.</p> <p>In the first part, we went through a general introduction on what the WCF RIA Services Domain Context is, looked into different strategies on how to work with it, and had a detailed look at the first possible strategy: using one instance per ViewModel.  In this article, we’ll look into the other strategies. <br /> <br /> </p> <h3>Strategy 2: using one shared Domain Context Instance</h3> <p>Let’s have a look at the other approach: using one shared Domain Context instance across different ViewModels. As you might have guessed, the pros and cons are more or less the opposite of the previous approach: the good part is that you get automatically synced collections across your ViewModels: as they’re using the same Domain Context instance, adding a Book in one ViewModel will mean it’s also reflected in the other ViewModel (well, as long as you’re working directly with the EntitySet or with one of the built-in CollectionViews – eg, anything that tracks the collections on the Domain Context).</p> <p>This is the approach I tend to prefer for most intranet-applications we’re building these days. Keep in mind: you’ll still have multiple Domain Context instances because you should think about how to separate your operations in different Domain Services, however, that’s not the same as different instances of the same Domain Context.</p> <p>In our example, I’ve created a static LocalStateContainer class, which is where the Domain Context instance resides. The ViewModels have a Context property which links back to the Domain Context instance in the LocalStateContainer class:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">class</span> LocalStateContainer { <span class="kwrd">private</span> <span class="kwrd">static</span> BookDomainContext _context; <span class="kwrd">public</span> <span class="kwrd">static</span> BookDomainContext Context { get { <span class="kwrd">if</span> (_context == <span class="kwrd">null</span>) { _context = <span class="kwrd">new</span> BookDomainContext(); } <span class="kwrd">return</span> _context; } } }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>This results in the following application screen:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/dc3.png"><img width="668" height="387" title="dc3" style="display: block; float: none; margin-left: auto; margin-right: auto;" alt="dc3" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/dc3_thumb.png" /></a></p> <p>If you look into the code, you’ll notice the ViewModel of the View on the left loads the data, and the one on the right doesn’t, yet: the data is available on both screens.</p> <p>If you click the “Add both books” button on the View on your right, you’ll notice the Books that are submitted to the database are automatically reflected in both Views:</p> <p>One (possibly big) disadvantage is the fact that a submit operation is “all or nothing”: you cannot do partial submits, so submitting changes will submit all changes across different screens. Depending on how you design your application, this may or may not be a problem: an easy way to solve this would be to disallow your users to navigate away from pages which have unsaved changes. In such a case, a submit op would still only submit the changes from the last page, as you can be sure that will be the only page with possible changes.</p> <p>However, if you want to give your users a more open experience (multi-window MDI-like applications, or applications which allow the user to navigate back and forth between pages without having to save the changes), this could pose some problems: imagine changing an Entity in one part of your application, navigating to another part, changing another Entity and submitting the changes: what if the first Entity has some invalid values? You’ll end up with an error message which actually belongs to a page that isn’t active nor necessarily visible anymore to your user – not exactly user friendly. One way to solve this (an approach we used in one of our applications) could be to keep a list of “active screens” (much like a task bar) on your screen. If a submit operation fails, you could easily use that “task bar” to show your user which active screen has problems, so he can go and fix those before retrying the submit operation. But as you’ve probably guessed: this is not exactly trivial code.</p> <p>So let’s look into another way to solve this issue: partial saves. A partial save means you’ll only submit a part of the changed Entities: only the once you want to submit. Like this, you can submit the changes on one ViewModel without having to save changes on one of the other ViewModels.</p> <p>Wait a minute. I’ve been saying throughout this article that partial saves aren’t possible through a Domain Context, so how can this be done? Well, the workaround is easier than it might look. I’ve already talked about attaching an Entity to a Domain Context, which implies you can also detach an Entity. The reasoning here is quite simple: a partial save can be done by detaching the entities you want to save from your Domain Context (IF they are attached to it), creating a new Domain Context instance (which will only be used for the submit operation), attaching them to that new instance in the correct state, submitting the changes, and on the completion of the submit operation, re-attach the submitted entities to the original Domain Context.</p> <p>At least, that’s how it works in theory. In practice, you’ll find out that the part where you should attach entities in the correct state is the tricky part: if you attach an Entity, it’s attached with state “Unmodified” by default, and you cannot easily change that state. For our example, the solution is quite easy: attaching it in the correct state boils down to adding the Book to the Books collection on the new Domain Context.</p> <p>The code to achieve this looks as such:</p> <pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> AddFirstBookExecution() { <span class="rem">// for example purposes, we'll first add the two</span> <span class="rem">// books to the original context.</span> Context.Books.Add(NewBook); Context.Books.Add(SecondNewBook); <span class="rem">// create a new context instance</span> BookDomainContext submitContext = <span class="kwrd">new</span> BookDomainContext(); <span class="rem">// detach the book</span> Context.Books.Detach(NewBook); <span class="rem">// attach the book to the new context in the correct state,</span> <span class="rem">// eg: add it.</span> submitContext.Books.Add(NewBook); <span class="rem">// submit the new context</span> var submitOp = submitContext.SubmitChanges(); submitOp.Completed += (send, args) => { <span class="kwrd">if</span> (submitOp.HasError == <span class="kwrd">false</span>) { <span class="rem">// detach</span> Book submittedBook = (Book)submitOp.ChangeSet.AddedEntities[0]; submitContext.Books.Detach(submittedBook); <span class="rem">// attach the book back to the old context</span> Context.Books.Attach(submittedBook); <span class="rem">// inspecting the old context through</span> <span class="rem">// Context.HasChanges => will be true: the </span> <span class="rem">// SecondNewBook will not be submitted.</span> } }; }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>But what about modified entities, or deleted entities?  Essentially, you’re going to have to write custom code to handle these cases.  Luckily, a great starting point for these cases is <a href="http://riaservicescontrib.codeplex.com/" target="_blank">WCF RIA Services Contrib, by Colin Blair</a>. This project consists of a bunch of extensions on WCF RIA Services, one of which allows you to achieve partial saves through the Entity.ApplyState-method. </p> <h3>Strategy 3: a mix of 1 & 2?</h3> <p>The third approach is a mix of the approaches I’ve described above: the same pros and cons apply, but instead of having no cons at all, you might end up with all of them in the same project… In general, I’m not such a fan of this – often, this simply results in having to have all possible workarounds in one project. <br /> <br /> <br /> </p> <h3>Conclusion</h3> <p>The Domain Context is really powerful, but you should be aware of how it works, and what the different strategies are for working with it. Each strategy has its own advantages and disadvantages, and workarounds for those disadvantages. The right strategy will highly depend on your project. In general, I would use the “one Domain Context instance per ViewModel” in cases where you absolutely need to be able to submit only the changes that are made on one ViewModel, and I’d use the “one shared Domain Context for all ViewModels” approach in cases where keeping the data automatically synced is important. From experience however, I find that most projects use the shared Domain Context approach.</p> <p>Oh, and don’t forget: if you model your domain services right (eg: don’t design one Domain Service to track all your entities), you just might avoid a lot of problems, so that’s always the first thing to do. </p> <p> </p> <h3>About the author</h3> <p>Kevin Dockx lives in Belgium and works at <a href="http://www.realdolmen.com/">RealDolmen</a>, one of Belgium's biggest ICT companies, where he is a technical specialist/project leader on .NET web applications, mainly Silverlight, and a solution manager for Rich Applications (Silverlight, Windows Phone 7 Series, WPF, Surface). His main focus lies on all things Silverlight, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a Silverlight enthusiast, he's a regular speaker on various national and international events, like Microsoft DevDays in The Netherlands, Microsoft Techdays in Portugal and Belgium, or on BESUG events (the Belgian Silverlight User Group). Next to that, he also authored a best-selling Silverlight book, <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">Packt Publishing's Silverlight 4 Data and Services Cookbook</a>, together with Gill Cleeren. His blog, which contains various tidbits on Silverlight, .NET, and the occasional rambling, can be found at <a href="http://blog.kevindockx.com/">http://blog.kevindockx.com/</a>, and of course he can also be found on Twitter @KevinDockx.</p> http://www.silverlightshow.net/items/Silverlight-WCF-RIA-Services-strategies-for-handling-your-Domain-Context-part-two.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Silverlight-WCF-RIA-Services-strategies-for-handling-your-Domain-Context-part-two.aspx#comments http://www.silverlightshow.net/items/Silverlight-WCF-RIA-Services-strategies-for-handling-your-Domain-Context-part-two.aspx Sat, 19 Mar 2011 08:22:00 GMT Silverlight WCF RIA Services: Strategies for handling your Domain Context - Part 1 <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>Don't miss...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Deep-dive-into-WCF-part-1-TDD.aspx">Deep Dive Into WCF series</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/WCF-RIA-Services-Part-1-Getting-Started.aspx">WCF article series by B.Noyes</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Search.aspx?q=WCF+RIA+Services+&adv=true&ro=0&t=3&r=10&o=1">WCF RIA Services Shows</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/domain_context.aspx">The Domain Context series is now available as a fully offline resource: </a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/domain_context.aspx"><img style="border:0px solid;" alt="WCF RIA Services: Strategies for Handling Your Domain Context Ebook" src="http://www.silverlightshow.net/Storage/domain_context_thumb.png" usemap="#rade_img_map_1291385581316" /></a><br /> <strong><span style="font-size: 13px;">($0.99)</span></strong></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>This is the first in a two-part article series on the WCF RIA Services Domain Context.</p> <p>This article series is accompanied by source code, which can be downloaded <a href="http://www.silverlightshow.net/Storage/Sources/SilverlightShowDomainContextStrategies.zip">here</a>.</p> <h3>Introduction</h3> <p>A lot of business applications that are being developed in Silverlight today are built with the help of WCF RIA Services. This should come as no surprise, as it’s a really powerful, extensible framework which provides us with a lot of features out of the box (validation, authentication, authorization, …) that otherwise would require quite a lot of custom code, workarounds & plumbing. In WCF RIA Services, you’re going to be working with a client-side Domain Context instance. This article will look into a few strategies on working with this Domain Context, and is accompanied by a demo & source code, which you can download here. </p> <p>But let’s start with a short introduction on what a Domain Context actually is. <br /> <br /> </p> <h3>What is a Domain Context?</h3> <p>When you create a new Domain Service & build your project, you’ll notice a Domain Context class (a class inheriting DomainContext) has been generated for you on the client (in a Silverlight class library project if you’re using a WCF RIA Services class library, or straight into your Silverlight project): one for each Domain Service. If you create a Domain Service named MyDomainService, you’ll get a generated Domain Context on your client named MyDomainContext, which inherits from the DomainContext class. It contains query operations to fetch data, collections of the entities you’re exposing through the Domain Service, submit and reject operations, … It provides a lot of functionality to help you with change tracking & interacting with the underlying Domain Service. </p> <p>Those of you who are familiar with an object relation mapper (ORM), like the Entity Framework, will feel right at home: working with the WCF RIA Services Domain Context is quite similar to working with the Object Context you get when using the Entity Framework: you load data into the Context, the Context has collections of Entities you’re exposing through your Domain Service(s), it allows for change tracking on these entities, and you get your typical submit & reject-operations. Of course, you’re working in an asynchronous, service oriented environment when using WCF RIA Services: what actually happens when you submit the changes on your Domain Context is that that same context is rebuilt on the server side, and submitted once completely built. </p> <p>As an example, we’ll assume we’ve got an Entity Model with a Category & Book object (cfr <a href="http://johnpapa.net/silverlight/pdc10kungfu/" target="_blank">John Papa’s Bookstore Club example</a>). A Book belongs to a Category, so one Category can have multiple Book objects: we’ve got a Navigation Property Books on our Category. When you create a Domain Service, BookDomainService, and select these 2 entities, WCF RIA Services will generate all the CRUD operations for you.  Note that this “generation” is done once; it’s nothing more than a bit of help to get you started (however: in real-life scenarios, take care of this: you do not want operations to be exposed through your services which aren’t used) – this is different from the generation of the client-side Domain Context, which happens on each build.  </p> <p>  </p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/clip_image001_2.png"><img width="452" height="328" title="clip_image001" style="display: block; float: none; margin-left: auto; margin-right: auto;" alt="clip_image001" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/clip_image001_thumb.png" /></a> </p> <p>In your Silverlight application, you’ve now got a BookDomainContext. This Domain Context contains a list of Books and a list of Categories. Each Category from that list has a list, Books (eg: the NavigationProperty from the EntityModel). </p> <p>Image we load all the categories & their books. We change 1 book, add 1 category and add 1 new book to that category. When you submit these changes, the UpdateBook method will get executed once, the InsertCategory & InsertBook methods will get executed once as well, and only after that, the server-side Object Context is submitted, resulting in the necessary queries to your DB. You can easily check this behavior by overriding the Submit method on your Domain Service: if you set a breakpoint on it, you’ll notice it will only get hit after the CUD operations have been executed. </p> <p>So, in essence, what we’ve got is a client-side version of a server-side Object Context. Needless to say: this approach became very popular in a short amount of time, and WCF RIA Services is being used for large, line of business applications all over the world. </p> <p>However: when you choose this approach, you should be aware of how the DomainContext works and what the different strategies for using it are. The explanation above should already give you an idea of its inner workings, but when starting a new project, an important question will always rise up: should I use one or more instances of my Domain Context(s)? <br /> <br /> </p> <h3>Instance strategies for your Domain Context</h3> <p>In essence, you’ve got to choose between 3 different approaches: working with one general Domain Context instance, shared across all your ViewModels, working with a specific Domain Context instance on each ViewModel, or a mix of the previous 2 approaches, where some ViewModels share the same Domain Context instance, and others have their own. We will now look into these approaches, list a few reasons to choose (or reject) a certain approach, and look into the issues that you might face with each approach. </p> <p>First things first though: regardless of the chosen approach, it’s always a good idea to think about what should go in each Domain Service. Just a few months ago, we didn’t have a lot of choice: using the same entity in two different Domain Services wasn’t supported and resulted in an error. Since SP1, this has been solved: you can now easily share the same entity in different Domain Services (and thus have it tracked by different Domain Contexts). So that would be the first tip: split up your domain services depending on the functionality a certain module of your application requires. This not only keeps them much easier to maintain, it also allows for greater abstraction & code re-use. <br /> <br /> </p> <h3>Strategy 1: one Domain Context instance for each ViewModel</h3> <p>Choosing the right approach will typically depend on the (functional) requirements of your application. First of all, we’ll look into the “one Domain Context instance for each ViewModel” approach. This approach is used in a lot of examples you can find online, and it looks as the right way to go for a lot of applications. </p> <p>The advantages aren’t hard to see: as a Domain Context cannot do partial submits, a submit operation on your context will submit all the changed entities on that context at once. One instance per ViewModel allows you to easily submit only the changes that have been made to your data used in that ViewModel. Next to that, if you’ve got different VM’s working on different sets of data of the same type, you can keep on working straight on the EntitySets (or CollectionViews on those entity sets) of your Domain Context instance. For example: in one ViewModel you could load all new Books in the Book collection on your Domain Context instance, in another ViewModel you could load all Books from a certain author in that collection on your Domain Context (of course, there are other ways to achieve the same – for example, working with ICollectionViews and filtering the data on the client or server, using filters on your EntityQuery, …). The essence is: your Domain Context isn’t shared, so it’s kept within the boundaries of that ViewModel: whatever you do on it, it’s not reflected in other ViewModels. </p> <p>This is the approach we took when creating our 360 Review Application, of which I wrote a <a href="http://www.silverlightshow.net/items/360-Degrees-Feedback-by-Kevin-Dockx.aspx" target="_blank">white paper</a> a few weeks ago. Our main concerns here were: allow the user to navigate wherever he wants without requiring him to save changes before leaving an active screen (eg: a user could easily have 4, 5 active screens with unsubmitted changes), and only submit the data that is needed to the server per screen, not for all screens at once. </p> <p>However, this does pose a problem: keeping your Domain Contexts in sync across different ViewModels. For example, imagine two parts of an application, two different ViewModels working on the same (or rather, related) data. A simple example could be: in one ViewModel, for example the one used in a sort of Dashboard screen in your application, you get an overview of all the Books in your DB. In another ViewModel, you’re allowing the user to add, edit, delete, … one of those books. Image you’re adding a new Book, submit the changes to server, and go back to the other view: the new Book won’t show up there, as, at the moment, it’s not being tracked by that DomainContext instance. You could of course automatically refetch the Employee collection whenever a user navigates to the dashboard View (and underlying ViewModel), but that’s not too good, performance and bandwidth wise. </p> <p>How can we handle this? Well, out of the box, you can’t: there’s no way to automatically “sync” different Domain Context instances. It will require some custom code, and how do this, again, depends on your application requirements. </p> <p>I’ve created an example application to show this behavior (note: the example applications uses <a href="http://mvvmlight.codeplex.com/" target="_blank">Laurent Bugnions’ MVVM Light Toolkit</a> - powerful & really lightweight, check it out if you haven’t done so yet, and <a href="http://johnpapa.net/silverlight/pdc10kungfu/" target="_blank">John Papa’s Bookstore Club database</a>). </p> <p>In this application, you can see 2 views on the same page, of which the ViewModels have their own Domain Context instance. Both Views show a list of all the books in the database – they are bound to an EntitySet<Book> (Context.Books), which is loaded in the VM’s constructor. When you add a Book on the second view, a new Book (with some default values filled out) is added to the Domain Context, and the Domain Context is saved by calling its SubmitChanges() method. You’ll notice that the book is correctly added to the end of the book ListBox on the right, but it’s missing in the ListBox on the left. </p> <p>So, how do we make sure both Domain Contexts are kept in sync? One possible approach would be to manually redo the changes you’ve made on one instance on the other. As you might know, entities can be attached to a context in code: what you can do is send a message when the book has been submitted, containing the entity you’ve just added, to a ViewModel that’s handling entities of the same type. The receiving ViewModel would then attach the Entity you pass in to its Context, resulting in 2 synced Domain Context instances. You do need to create a copy of the Entity to attach, as an Entity can only be tracked by one Domain Context instance at the same time. In our example, the code would look like this: </p> <p>Submit the book in the ViewModel on the right, and create a new message:</p> <pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> AddBookAndAttachExecution() { <span class="rem">// add the book to the context, and save changes</span> Context.Books.Add(NewBook); var submitOp = Context.SubmitChanges(); submitOp.Completed += (send, args) => { <span class="kwrd">if</span> (submitOp.HasError == <span class="kwrd">false</span>) { <span class="rem">// send a message telling any registered VM's a book has been added</span> Messenger.Default.Send<BookAddedMessage>( <span class="kwrd">new</span> BookAddedMessage(NewBook)); <span class="rem">// create a new book with default values</span> NewBook = <span class="kwrd">new</span> Book() { ASIN = <span class="str">"123"</span>, AddedDate = DateTime.Now, Description = <span class="str">"Default description"</span>, Author = <span class="str">"Author"</span>, Title = <span class="str">"Title"</span>, PublishDate = DateTime.Now, CategoryID = 1, MemberID = 1 }; } }; }</pre> <pre> </pre> <p>The message constructor creates a copy of the Book:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> BookAddedMessage { <span class="kwrd">public</span> Book Book; <span class="kwrd">public</span> BookAddedMessage(Book book) { <span class="rem">// create a COPY of the book that's passed in. This one</span> <span class="rem">// is attached to another context, and you cannot attach the</span> <span class="rem">// same entity to two domain context instances.</span> <span class="kwrd">this</span>.Book = <span class="kwrd">new</span> Book() { BookID = book.BookID, ASIN = book.ASIN, AddedDate = book.AddedDate, Description = book.Description, Author = book.Author, Title = book.Title, PublishDate = book.PublishDate, CategoryID = book.CategoryID, MemberID = book.MemberID }; } }</pre> <style type="text/css"> .csharpcode { background-color: #ffffff; font-family: consolas, "Courier New", courier, monospace; color: black; font-size: small } .csharpcode pre { background-color: #ffffff; font-family: consolas, "Courier New", courier, monospace; color: black; font-size: small } .csharpcode pre { margin: 0em } .csharpcode .rem { color: #008000 } .csharpcode .kwrd { color: #0000ff } .csharpcode .str { color: #006080 } .csharpcode .op { color: #0000c0 } .csharpcode .preproc { color: #cc6633 } .csharpcode .asp { background-color: #ffff00 } .csharpcode .html { color: #800000 } .csharpcode .attr { color: #ff0000 } .csharpcode .alt { background-color: #f4f4f4; margin: 0em; width: 100% } .csharpcode .lnum { color: #606060 } </style> <p>The message recipient, in our example: the ViewModel on the left, attaches the Book to its context:</p> <pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> BookAddedMessageReceived(BookAddedMessage msg) { <span class="rem">// attach the newly added book (in an unmodified state)</span> Context.Books.Attach(msg.Book); }</pre> <style type="text/css"> .csharpcode { background-color: #ffffff; font-family: consolas, "Courier New", courier, monospace; color: black; font-size: small } .csharpcode pre { background-color: #ffffff; font-family: consolas, "Courier New", courier, monospace; color: black; font-size: small } .csharpcode pre { margin: 0em } .csharpcode .rem { color: #008000 } .csharpcode .kwrd { color: #0000ff } .csharpcode .str { color: #006080 } .csharpcode .op { color: #0000c0 } .csharpcode .preproc { color: #cc6633 } .csharpcode .asp { background-color: #ffff00 } .csharpcode .html { color: #800000 } .csharpcode .attr { color: #ff0000 } .csharpcode .alt { background-color: #f4f4f4; margin: 0em; width: 100% } .csharpcode .lnum { color: #606060 } </style> <p>This results in the following (Domain Context instances are in sync): </p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/dc2.png"><img width="676" height="386" title="dc2" style="display: block; float: none; margin-left: auto; margin-right: auto;" alt="dc2" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/dc2_thumb.png" /></a> </p> <p>The advantage of this approach is that it doesn’t require an extra load operation to refetch the list of books from the server – the Book is submitted once, and all the rest is handled on the client (you might want to write an extension method to copy Entities to make your life easier). However, you’ll quickly run into the fact that designing your application like this will require a lot of maintenance: in this example, we’re only talking about 1 list of books, but in a real-life application, you’ll typically be handling a multitude of possible objects & child objects, which could be added, updated or removed, on a multitude of ViewModels with a multitude of Domain Context instances. </p> <p>Another possible approach is to send messages to the related ViewModels, telling them that they have to refresh themselves. A refresh would re-load the data from the server, in this case: reload the list of books. In the example application, that would look like this: </p> <p>Submit the book in the ViewModel on the right, and create a new message:</p> <pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> AddBookAndRefreshExecution() { <span class="rem">// add the book to the context, and save changes</span> Context.Books.Add(NewBook); var submitOp = Context.SubmitChanges(); submitOp.Completed += (send, args) => { <span class="kwrd">if</span> (submitOp.HasError == <span class="kwrd">false</span>) { <span class="rem">// send a message telling any registered VM's to refresh</span> Messenger.Default.Send<RefreshBooksMessage>( <span class="kwrd">new</span> RefreshBooksMessage()); <span class="rem">// create a new book with default values</span> NewBook = <span class="kwrd">new</span> Book() { ASIN = <span class="str">"123"</span>, AddedDate = DateTime.Now, Description = <span class="str">"Default description"</span>, Author = <span class="str">"Author"</span>, Title = <span class="str">"Title"</span>, PublishDate = DateTime.Now, CategoryID = 1, MemberID = 1 }; } }; }</pre> <style type="text/css"> .csharpcode { background-color: #ffffff; font-family: consolas, "Courier New", courier, monospace; color: black; font-size: small } .csharpcode pre { background-color: #ffffff; font-family: consolas, "Courier New", courier, monospace; color: black; font-size: small } .csharpcode pre { margin: 0em } .csharpcode .rem { color: #008000 } .csharpcode .kwrd { color: #0000ff } .csharpcode .str { color: #006080 } .csharpcode .op { color: #0000c0 } .csharpcode .preproc { color: #cc6633 } .csharpcode .asp { background-color: #ffff00 } .csharpcode .html { color: #800000 } .csharpcode .attr { color: #ff0000 } .csharpcode .alt { background-color: #f4f4f4; margin: 0em; width: 100% } .csharpcode .lnum { color: #606060 } </style> <p>The message recipient, in our example: the ViewModel on the left, refetches the list of books:</p> <pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> RefreshBooksMessageReceived(RefreshBooksMessage msg) { <span class="rem">// reload the data</span> LoadData(); } <span class="kwrd">private</span> <span class="kwrd">void</span> LoadData() { Context.Load<Book>(Context.GetBooksQuery()); }</pre> <style type="text/css"> .csharpcode { background-color: #ffffff; font-family: consolas, "Courier New", courier, monospace; color: black; font-size: small } .csharpcode pre { background-color: #ffffff; font-family: consolas, "Courier New", courier, monospace; color: black; font-size: small } .csharpcode pre { margin: 0em } .csharpcode .rem { color: #008000 } .csharpcode .kwrd { color: #0000ff } .csharpcode .str { color: #006080 } .csharpcode .op { color: #0000c0 } .csharpcode .preproc { color: #cc6633 } .csharpcode .asp { background-color: #ffff00 } .csharpcode .html { color: #800000 } .csharpcode .attr { color: #ff0000 } .csharpcode .alt { background-color: #f4f4f4; margin: 0em; width: 100% } .csharpcode .lnum { color: #606060 } </style> <p>The disadvantage of this approach is that it comes with higher bandwidth usage: you’re refetching data from the server. But the advantage comes in the form of simplicity and lower maintenance: instead of having to pass through all the changed objects & child objects, you simply send one message: refresh entities of this type. Depending on how you wrote your EntityQueries, the child objects (when applicable) will be refetched if they need to be. </p> <p>That’s all for the first strategy.  Stay put for the second and third approach in the next part of this article series!</p> <p> </p> <h3>About the author</h3> <p>Kevin Dockx lives in Belgium and works at <a href="http://www.realdolmen.com/">RealDolmen</a>, one of Belgium's biggest ICT companies, where he is a technical specialist/project leader on .NET web applications, mainly Silverlight, and a solution manager for Rich Applications (Silverlight, Windows Phone 7 Series, WPF, Surface). His main focus lies on all things Silverlight, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a Silverlight enthusiast, he's a regular speaker on various national and international events, like Microsoft DevDays in The Netherlands, Microsoft Techdays in Portugal and Belgium, or on BESUG events (the Belgian Silverlight User Group). Next to that, he also authored a best-selling Silverlight book, <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">Packt Publishing's Silverlight 4 Data and Services Cookbook</a>, together with Gill Cleeren. His blog, which contains various tidbits on Silverlight, .NET, and the occasional rambling, can be found at <a href="http://blog.kevindockx.com/">http://blog.kevindockx.com/</a>, and of course he can also be found on Twitter @KevinDockx</p> http://www.silverlightshow.net/items/Silverlight-WCF-RIA-Services-strategies-for-handling-your-Domain-Context-part-one.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Silverlight-WCF-RIA-Services-strategies-for-handling-your-Domain-Context-part-one.aspx#comments http://www.silverlightshow.net/items/Silverlight-WCF-RIA-Services-strategies-for-handling-your-Domain-Context-part-one.aspx Thu, 17 Mar 2011 08:21:00 GMT Getting ready for Microsoft Silverlight Exam 70-506 (Part 3) <div style="border: 1px solid #dddddd; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; padding-top: 5px;"><strong>SilverlightShow</strong> and <strong>Gill Cleeren</strong> start a <strong>series of materials</strong> aimed at helping you get prepared for taking <a href="http://www.microsoft.com/learning/en/us/Exam.aspx?ID=70-506&Locale=en-us" target="_blank">Microsoft Silverlight Exam 70-506</a>. Through this series we will try to structure the resources available on the internet, grouping them by topic covered in the exam. <strong>Any feedback would be much appreciated</strong>! Thanks!  </div> <div style="border: 1px solid #dddddd; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>More resources...</h3> <ul style="list-style-type: circle; margin: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Webinars.aspx">Free SilverlightShow Webinars</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Search.aspx?q=+RichTextBox&adv=false">WCF RIA Services series</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/silverlight_exam.aspx">'Getting Ready for Microsoft Silverlight Exam 70-506' Ebook </a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/silverlight_exam.aspx"><img style="border: 0px solid;" alt="Getting Ready for Microsoft Silverlight Exam 70-506: Ebook" src="http://www.silverlightshow.net/Storage/sl_exam_thumb_small.png" usemap="#rade_img_map_1291385581316" /></a><br /> <strong><span style="font-size: 13px;">($9.99)</span></strong></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>This article is Part 3 of the series on Microsoft Silverlight Exam.</p> <p>In the previous parts of this series on getting yourself ready for the Silverlight exam, we mainly looked at UI related items. In the very first part, we looked at how Silverlight could help with layout, navigation, media and the core controls. In part 2, we focused on the many features Silverlight has on board to create better user interfaces, such as the Visual State Manager, styling, templating and animations.</p> <p>This third part is going to be more aimed at the code-side of things. We’ll start our journey by looking at specifics of Silverlight such as routed events (these also exist in WPF by the way and asynchronous communication with services. We’ll look at dependency and attached properties as well, these are very important to a deeper understanding of Silverlight. We’ll look at the ICommand interface as well, which forms the base of commanding support for the MVVM-pattern in Silverlight. As you can see, we’ll be spending more time looking at C# code this time!</p> <p>For your convenience, the following list contains links to the other parts of the article series which have been finished already:</p> <ul> <li><a href="http://www.silverlightshow.net/items/Getting-ready-for-the-exams-Part-1.aspx">Laying Out a User Interface (15%)</a> </li> <li><a href="http://www.silverlightshow.net/items/Getting-ready-for-Microsoft-Silverlight-Exam-70-506-Part-2.aspx">Enhancing the User Interface (14%)</a> </li> <li><strong>Implementing Application Logic (16%) -> this part</strong> </li> <li><a href="http://www.silverlightshow.net/items/Getting-ready-for-Microsoft-Silverlight-Exam-70-506-Part-4.aspx">Working with Data (17%)</a>  </li> <li><a href="http://www.silverlightshow.net/items/Getting-ready-for-Microsoft-Silverlight-Exam-70-506-Part-5.aspx">Interacting with a Host Platform (11%)</a>  </li> <li><a href="http://www.silverlightshow.net/items/Getting-ready-for-Microsoft-Silverlight-Exam-70-506-Part-6.aspx">Structuring Applications (13%)</a>  </li> <li><a href="http://www.silverlightshow.net/items/Getting-ready-for-Microsoft-Silverlight-Exam-70-506-Part-7.aspx">Deploying Applications (13%)</a>  </li> </ul> <h4>Part 3: Implementing Application Logic</h4> <p>Do you remember the name WPF/E (the E stands for Everywhere)? It was the name Silverlight was known by before it got its final name. The reason I bring this up here is that it shows that Silverlight has inherited from WPF (Windows Presentation Foundation). The original name gives this away. Much of the core development platform we have today in Silverlight found its origin in Silverlight. Things like dependency properties and attached properties were introduced in WPF and later were ported into Silverlight. Some of these implementations are identical in the 2 technologies, others are somewhat trimmed down in Silverlight. Still, the development model available in Silverlight is solid and ready to build all types of applications on. Let’s dive into writing some code for Silverlight applications!</p> <h5>Handle events</h5> <p>Working with events in Silverlight is not very different from any other technology (note that we’re not looking at MVVM/commanding here yet). When we have some control in the designer, we can select it and select an event in the event window. Visual Studio will generate the event handler for us then as well as generate the event on the control in XAML. Not very different from ASP.NET or WinForms indeed! We can also choose to attach the event handler in code-behind using a delegate or even a lambda expression. </p> <p>Silverlight has the notion of routed events. An event raised on a control nested within another control will bubble into the parent control so this parent can handle the event. This model is easy because Silverlight promotes nesting. This way, a TextBlock and an Image inside of a container (such as a Grid), all nested within a Button, will raise the click event to the Button, instead of us having to wire the event for the Button and its children manually.</p> <p>To learn more about event handling, take a look at the following links:</p> <ul> <li>Handling routed events / Bubbling events: <br /> <em>Bubbling of an event is a type of a routed event. At the time of writing, there’s only support for bubbling events in Silverlight. WPF also supports tunneling. Bubbling can be seen as a way to send an event higher in the hierarchy. Hence the name bubbling: it will bubble up in the XAML tree. Tunneling, which is only available for WPF, does the opposite, drilling down so to say in the XAML tree. </em> <ul> <li>Routed events in Silverlight 3: <a href="http://msdn.microsoft.com/en-us/library/cc189018(v=vs.95).aspx">http://msdn.microsoft.com/en-us/library/cc189018(v=vs.95).aspx</a> (contains information on AddHandler as well) </li> <li><a href="http://www.silverlightshow.net/items/Routed-Events-in-Silverlight.aspx">http://www.silverlightshow.net/items/Routed-Events-in-Silverlight.aspx</a> </li> <li><a href="http://www.silverlightshow.net/news/Training-Session-on-Silverlight-Routed-Events.aspx">http://www.silverlightshow.net/news/Training-Session-on-Silverlight-Routed-Events.aspx</a> </li> <li>Interesting thread on the Silverlight forums: <a href="http://forums.silverlight.net/forums/p/153909/343601.aspx">http://forums.silverlight.net/forums/p/153909/343601.aspx</a> </li> <li><a href="http://www.silverlightshow.net/items/More-on-Routing-and-Bubbling.aspx">http://www.silverlightshow.net/items/More-on-Routing-and-Bubbling.aspx</a> </li> <li><a href="http://www.kirupa.com/net/event_bubbling_tunneling.htm">http://www.kirupa.com/net/event_bubbling_tunneling.htm</a> </li> <li><a href="http://rongchaua.net/blog/silverlight-routed-event/">http://rongchaua.net/blog/silverlight-routed-event/</a> </li> </ul> </li> <li>Implementing AddHandler: <br /> Using the AddHandler, we can add an event handler for a routed event to the handler collection of an element. <ul> <li><a href="http://msdn.microsoft.com/en-us/library/ms598899(v=vs.95).aspx">http://msdn.microsoft.com/en-us/library/ms598899(v=vs.95).aspx</a> </li> </ul> </li> </ul> <h5>Consume services asynchronously</h5> <p>Services are a vital building block for Silverlight applications. As business applications become more and more the focus of where Silverlight is going, data is needed in any app. Since out-of-the-box, Silverlight has no support for client-side database (I specifically said out-of-the-box, since there are some custom implementations such as Sterling database but these are not the focus for the exam), it has to access services for its data needs. Client-side databases would not be the solution for all problems either: if we build a shopping website in Silverlight, no developer would get it in his mind to transfer the entire product database to the client (let’s hope so at least!).</p> <p>Luckily, Silverlight is well-equipped for working with all kinds of services. ASMX, WCF, REST, POX and RSS pose no problem for Silverlight. We can easily say that today, the default for building new services should be WCF or REST. However, if you have an existing implementation (legacy) in ASMX (plain web services), there’s no problem to consume these from a Silverlight environment. </p> <p>When working with WCF or ASMX services, Visual Studio helps us out by generating a proxy class when adding a reference to the service. This proxy will make the actual calls to our service. This is not different from adding service references in other .NET technologies.</p> <p>One big difference however is the fact that all communication happens asynchronously in Silverlight. No service can be communicated with in a synchronous manner. This would, while the Silverlight application waits for a response, lock the UI thread and therefore also the browser. Even in WCF RIA Services, where the async behavior is somewhat abstracted away, the communication still happens asynchronously.</p> <p>(Shameless plug: in my book <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">Silverlight 4 Data and Services Cookbook</a> (Gill Cleeren – Kevin Dockx, Packt Publishing 2010), we have a very deep coverage of all things happening around accessing services).</p> <p>Let’s look at some important information regarding working with services from Silverlight.</p> <ul> <li>Creating and adding service references / Handling asynchronous completed events <ul> <li>Services and Silverlight on MSDN: <a href="http://msdn.microsoft.com/en-us/library/cc197940(v=vs.95).aspx">http://msdn.microsoft.com/en-us/library/cc197940(v=vs.95).aspx</a> </li> <li><a href="http://www.silverlightshow.net/items/Silverlight-Data-and-Services-The-complete-story.aspx">http://www.silverlightshow.net/items/Silverlight-Data-and-Services-The-complete-story.aspx</a> </li> <li><a href="http://www.netfxharmonics.com/2008/11/Understanding-WCF-Services-in-Silverlight-2">http://www.netfxharmonics.com/2008/11/Understanding-WCF-Services-in-Silverlight-2</a> </li> <li><a href="http://www.silverlightshow.net/items/End-to-End-Data-Centric-Application-with-Silverlight-2.aspx">http://www.silverlightshow.net/items/End-to-End-Data-Centric-Application-with-Silverlight-2.aspx</a> </li> <li><a href="http://www.silverlightshow.net/items/Consuming-ASMX-Web-Services-with-Silverlight-2.aspx">http://www.silverlightshow.net/items/Consuming-ASMX-Web-Services-with-Silverlight-2.aspx</a> </li> <li><a href="http://www.silverlight.net/learn/quickstarts/webservices/">http://www.silverlight.net/learn/quickstarts/webservices/</a> </li> <li>Web service samples: <a href="http://code.msdn.microsoft.com/silverlightws">http://code.msdn.microsoft.com/silverlightws</a> </li> <li><a href="http://technet.microsoft.com/en-us/magazine/ff955754.aspx">http://technet.microsoft.com/en-us/magazine/ff955754.aspx</a> </li> <li><a href="http://www.dotnetfunda.com/articles/article279.aspx">http://www.dotnetfunda.com/articles/article279.aspx</a> </li> </ul> </li> <li>Configuring service endpoints <ul> <li><a href="http://wildermuth.com/2008/11/08/Controlling_Service_References_in_Silverlight_2">http://wildermuth.com/2008/11/08/Controlling_Service_References_in_Silverlight_2</a> </li> <li><a href="http://timheuer.com/blog/archive/2010/04/05/managing-service-references-in-silverlight-applications-for-different-environments.aspx">http://timheuer.com/blog/archive/2010/04/05/managing-service-references-in-silverlight-applications-for-different-environments.aspx</a> </li> </ul> </li> <li>Handling service exceptions <ul> <li><a href="http://msdn.microsoft.com/en-us/library/ee844556(v=vs.95).aspx">http://msdn.microsoft.com/en-us/library/ee844556(v=vs.95).aspx</a> </li> <li><a href="http://www.netfxharmonics.com/2008/11/Understanding-WCF-Services-in-Silverlight-2#WCFSilverlightHandlingFaults">http://www.netfxharmonics.com/2008/11/Understanding-WCF-Services-in-Silverlight-2#WCFSilverlightHandlingFaults</a> </li> </ul> </li> <li>Handling timeouts <ul> <li><a href="http://www.silverlightshow.net/items/Uploading-and-downloading-images-from-WCF-in-Silverlight.aspx">http://www.silverlightshow.net/items/Uploading-and-downloading-images-from-WCF-in-Silverlight.aspx</a> </li> <li><a href="http://stackoverflow.com/questions/689472/how-do-i-extend-the-timeout-for-a-web-service-in-silverlight-2-0">http://stackoverflow.com/questions/689472/how-do-i-extend-the-timeout-for-a-web-service-in-silverlight-2-0</a> </li> <li><a href="http://www.codeproject.com/KB/silverlight/DownloadingInChunks.aspx">http://www.codeproject.com/KB/silverlight/DownloadingInChunks.aspx</a> </li> </ul> </li> </ul> <h5><strong>Work with background threads</strong></h5> <p>Threading is the ability to push some long running task to a separate thread. By default, all the work is done on the single UI thread in Silverlight. If we launch for example a calculation that takes several seconds to complete in the main thread, the UI will be blocked and won’t be accepting any input until it has finished the calculation. By creating a separate thread to execute the work on, the UI thread won’t be blocked and the user can keep working with the application in the meantime. This is similar to what happens when connecting with a service: there’s also a time-consuming task that would block the UI if invoked synchronously.</p> <p>Silverlight has a threading stack on-board. While it doesn’t contain all threading options available in the full .NET framework, there’s more than enough for scenarios where Silverlight is to be used. Silverlight also contains the BackgroundWorker class which makes working with threads easier.</p> <p>One important thing concerning threading is that all code that executes on a separate thread has no access to the UI elements. It’s therefore not possible to write code in a callback that does something with a UI element (such as setting the Text of a TextBlock). There’s a workaround though in the form of the Dispatcher.BeginInvoke(), to which we can pass code that will be executed on the UI thread. </p> <p>To learn more about threading, take a look at the following links and articles:</p> <ul> <li>Spawning a background thread to execute code <ul> <li>Thread class on MSDN: <a href="http://msdn.microsoft.com/en-us/library/system.threading(v=VS.95).aspx">http://msdn.microsoft.com/en-us/library/system.threading(v=VS.95).aspx</a> </li> <li>BackgroundWorker on MSDN: <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=VS.95).aspx">http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=VS.95).aspx</a> and <a href="http://msdn.microsoft.com/en-us/library/cc221403(VS.95).aspx">http://msdn.microsoft.com/en-us/library/cc221403(VS.95).aspx</a> </li> <li><a href="http://10rem.net/blog/2010/04/23/essential-silverlight-and-wpf-skills-the-ui-thread-dispatchers-background-workers-and-async-network-programming">http://10rem.net/blog/2010/04/23/essential-silverlight-and-wpf-skills-the-ui-thread-dispatchers-background-workers-and-async-network-programming</a> (also contains overview of the BackgroundWorker class) </li> <li><a href="http://www.silverlight.net/learn/videos/silverlight-videos/using-multiple-threads-with-the-backgroundworker/">http://www.silverlight.net/learn/videos/silverlight-videos/using-multiple-threads-with-the-backgroundworker/</a> (video) </li> </ul> </li> <li>Returning data to the UI thread by using the dispatcher object <br /> <em>The Dispatcher allows to pass code to execute on the UI Thread. Without this, we wouldn’t be able to change anything on the UI elements from a background thread. </em> <ul> <li><a href="http://www.silverlightshow.net/items/Tip-Asynchronous-Silverlight-Execute-on-the-UI-thread.aspx">http://www.silverlightshow.net/items/Tip-Asynchronous-Silverlight-Execute-on-the-UI-thread.aspx</a> </li> <li><a href="http://wildermuth.com/2008/05/06/Executing_Code_on_the_UI_Thread_in_Silverlight_2">http://wildermuth.com/2008/05/06/Executing_Code_on_the_UI_Thread_in_Silverlight_2</a> </li> <li><a href="http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher(v=vs.95).aspx">http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher(v=vs.95).aspx</a> </li> </ul> </li> <li>Implementing the DispatcherTimer <br /> <em>The DispatcherTimer is a Timer which is integrated in the Dispatcher queue. It should be your default when using any timer in a Silverlight application.</em> <ul> <li>DispatcherTimer class on MSDN: <a href="http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer(v=vs.95).aspx">http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer(v=vs.95).aspx</a> </li> <li><a href="http://blogs.silverlight.net/blogs/msnow/archive/2009/11/09/69731.aspx">http://blogs.silverlight.net/blogs/msnow/archive/2009/11/09/69731.aspx</a> </li> </ul> </li> </ul> <h5>Working with Dependency Properties</h5> <p>When I teach a Silverlight class, one of the hardest things to explain I think are dependency properties. Not because they’re that hard, certainly not. The thing is that dependency properties make something you know (the regular property system) to a new level. However, they do relieve us from writing a lot of code ourselves.</p> <p>Dependency properties are the enabler for data binding, styling and animations. Without them, we would have to write a lot more code to get these things working. Most properties on UI objects in Silverlight (the FontSize property on a TextBlock, the Width property of a Rectangle…) are dependency properties, so in most cases, you’ve used them without even knowing it! When you start writing your own controls, you’ll need to start creating them as well, if you want your control to be able to take part in data binding, styling… It’s certainly recommended to do so, since other users of your custom-built controls will expect your controls to behave just like the default controls of Silverlight. </p> <p>Let’s take a look at working with dependency controls:</p> <ul> <li>Creating dependency properties / Specifying dependency property metadata / Getting and setting dependency property values <br /> <em>Creating dependency properties is more complicated than writing regular properties. You have to declare the DP by registering it with the dependency property system (on the DependencyObject). Optionally, you have to write code in a PropertyChangedCallback that will trigger when the value changes. Finally, you have to write a public wrapper for your DP. You won’t be accessing the value of the DP directly: you’ll always use this wrapper which internally uses the GetValue/SetValue defined on the DependencyObject class. These methods will retrieve the exact value of the DP at the given time, taking into account all the current influences taking place on the value and their priorities.</em> <ul> <li>DependencyObject class on MSDN: <a href="http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject(VS.95).aspx">http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject(VS.95).aspx</a> </li> <li>DependencyProperty class on MSDN: <a href="http://msdn.microsoft.com/en-us/library/system.windows.dependencyproperty(VS.95).aspx">http://msdn.microsoft.com/en-us/library/system.windows.dependencyproperty(VS.95).aspx</a> </li> <li><a href="http://www.silverlightshow.net/news/Dependency-Property-Value-Resolution.aspx">http://www.silverlightshow.net/news/Dependency-Property-Value-Resolution.aspx</a> </li> <li><a href="http://www.silverlightshow.net/news/Demystifying-Silverlight-Dependency-Properties-.aspx">http://www.silverlightshow.net/news/Demystifying-Silverlight-Dependency-Properties-.aspx</a> </li> <li><a href="http://geekswithblogs.net/Silverlight2/archive/2008/12/24/understanding-dependency-properties-in-silverlight.aspx">http://geekswithblogs.net/Silverlight2/archive/2008/12/24/understanding-dependency-properties-in-silverlight.aspx</a> </li> <li><a href="http://www.silverlightshow.net/tips/Tip-How-to-declare-a-dependancy-property-in-Silverlight.aspx">http://www.silverlightshow.net/tips/Tip-How-to-declare-a-dependancy-property-in-Silverlight.aspx</a> </li> <li><a href="http://www.kirupa.com/blend_silverlight/dependency_properties_pg1.htm">http://www.kirupa.com/blend_silverlight/dependency_properties_pg1.htm</a> </li> <li><a href="http://jesseliberty.com/2007/09/19/dependency-properties-or-attached-properties/">http://jesseliberty.com/2007/09/19/dependency-properties-or-attached-properties/</a> </li> <li><a href="http://www.kirupa.com/blend_silverlight/dependency_properties_pg2.htm">http://www.kirupa.com/blend_silverlight/dependency_properties_pg2.htm</a> </li> </ul> </li> <li>The topic of dependency properties in Silverlight is inherited from WPF. There’s a lot of interesting material on DPs in WPF as well from the following links: <ul> <li><a href="http://msdn.microsoft.com/en-us/library/ms752914.aspx">http://msdn.microsoft.com/en-us/library/ms752914.aspx</a> </li> <li><a href="http://joshsmithonwpf.wordpress.com/2007/05/16/demystifying-dependency-properties/">http://joshsmithonwpf.wordpress.com/2007/05/16/demystifying-dependency-properties/</a> </li> <li><a href="http://www.wpftutorial.net/DependencyProperties.html">http://www.wpftutorial.net/DependencyProperties.html</a> </li> <li><a href="http://www.switchonthecode.com/tutorials/wpf-tutorial-introduction-to-dependency-properties">http://www.switchonthecode.com/tutorials/wpf-tutorial-introduction-to-dependency-properties</a> </li> <li><a href="http://www.codeguru.com/csharp/.net/net_general/netframeworkclasses/article.php/c13449">http://www.codeguru.com/csharp/.net/net_general/netframeworkclasses/article.php/c13449</a> </li> </ul> </li> </ul> <h5>Interacting with attached properties</h5> <p>Attached properties are properties defined on one control but used on a different control. Confused? Let me explain it with a simple example. Take the Row property on a Grid control. When we want to place a TextBlock in row #3 inside a Grid, we specify the Grid.Row property to have the value 3. However, the TextBlock does not have a “Grid.Row” property defined. Instead, the Grid has the Row property defined as an attached property. The attached property is defined as a global property, so that other control can use it. Most attached properties are defined on containers (Grid, Canvas…). This is because there needs to be some “communication” between the child control and the parent control. However, this is not required: your own control can too define attached properties if needed. </p> <p>To learn more about attached properties, take a look at the following articles:</p> <ul> <li>Setting attached properties in XAML <ul> <li><a href="http://www.silverlightshow.net/items/Attached-Properties-in-Silverlight.aspx">http://www.silverlightshow.net/items/Attached-Properties-in-Silverlight.aspx</a> </li> <li><a href="http://msdn.microsoft.com/en-us/library/cc265152(v=vs.95).aspx">http://msdn.microsoft.com/en-us/library/cc265152(v=vs.95).aspx</a> </li> </ul> </li> <li>Getting and setting attached properties programmatically <ul> <li><a href="http://msdn.microsoft.com/en-us/library/cc265152(v=vs.95).aspx#attached_properties_code">http://msdn.microsoft.com/en-us/library/cc265152(v=vs.95).aspx#attached_properties_code</a> </li> <li><a href="http://dotnet.dzone.com/news/custom-attached-properties">http://dotnet.dzone.com/news/custom-attached-properties</a> </li> <li><a href="http://www.silverlightshow.net/tips/Tip-How-to-declare-an-attached-property-in-Silverlight.aspx">http://www.silverlightshow.net/tips/Tip-How-to-declare-an-attached-property-in-Silverlight.aspx</a> </li> </ul> </li> </ul> <h5>Implementing ICommand</h5> <p>The MVVM pattern is something you’ve surely heard about already. The ViewModel (aka View-Model-ViewModel) pattern promotes separation of concerns. The ViewModel is an abstraction of the View: the View mostly XAML-only and it’s the place where the designer is focusing on. The ViewModel contains state and operations for the View. State can be seen as properties, operations are commands. The View falls back on the concepts of data binding and the DataContext to bind to an instance of the ViewModel.</p> <p>When executing an action in the UI, for example clicking a Button, we think of adding an event handler and writing some event handling code in the code-behind. MVVM promotes commanding, which comes down to writing a public command in the ViewModel and binding to this instance in the View. When the command fires, the related code in the ViewModel gets executed. Therefore, we don’t write an event handler, instead we create a command instance and the ViewModel and bind to it. </p> <p>Commanding is possible in Silverlight 4 because of the introduction of the ICommand interface. When creating a command implementation, we have implement the ICommand interface. Once we have our implementation, we can instantiate it, expose it as a public property on the ViewModel and bind to it in the View. In Silverlight 4, commanding is only supported on the ButtonBase class though. (Note: in many cases, we don’t implement the ICommand ourselves but we’ll use an existing implementation such as RelayCommand of MVVM Light or DelegateCommand from Prism). </p> <p>The following articles can helpful when exploring the ICommand interface:</p> <ul> <li>General implementation of ICommand: <ul> <li>ICommand interface on MSDN: <a href="http://msdn.microsoft.com/en-us/library/system.windows.input.icommand(v=vs.95).aspx" target="_blank">http://msdn.microsoft.com/en-us/library/system.windows.input.icommand(v=vs.95).aspx</a> </li> <li><a href="http://www.johnpapa.net/5-Simple-Steps-to-Commanding-in-Silverlight" target="_blank">http://www.johnpapa.net/5-Simple-Steps-to-Commanding-in-Silverlight</a></li> <li><a href="http://wildermuth.com/2010/01/21/New_SL4_Feature_Commanding" target="_blank">http://wildermuth.com/2010/01/21/New_SL4_Feature_Commanding</a> </li> <li><a href="http://www.silverlightshow.net/items/Silverlight-4-How-to-Command-Control.aspx">http://www.silverlightshow.net/items/Silverlight-4-How-to-Command-Control.aspx</a> </li> <li><a href="http://www.silverlightshow.net/news/Using-RelayCommands-in-Silverlight-and-WPF.aspx">http://www.silverlightshow.net/news/Using-RelayCommands-in-Silverlight-and-WPF.aspx</a> </li> <li><a href="http://www.snowball.be/2010/12/31/Working+With+The+RaiseCanExecuteChanged+In+MVVM+Light+Silverlight.aspx" target="_blank">http://www.snowball.be/2010/12/31/Working+With+The+RaiseCanExecuteChanged+In+MVVM+Light+Silverlight.aspx</a> </li> </ul> </li> <li>Implementing an ICommand <ul> <li><a href="http://www.orktane.com/Blog/post/2009/03/09/I-Command-Silverlight.aspx" target="_blank">http://www.orktane.com/Blog/post/2009/03/09/I-Command-Silverlight.aspx</a> </li> </ul> </li> <li>Binding to an ICommand: <ul> <li><a href="http://www.dotnetfunda.com/articles/article859-command-binding-in-silverlight-4-stepbystep-.aspx" target="_blank">http://www.dotnetfunda.com/articles/article859-command-binding-in-silverlight-4-stepbystep-.aspx</a> </li> </ul> </li> <li>Passing a parameter <ul> <li><a href="http://www.silverlightshow.net/news/ICommand-in-Silverlight-4-.aspx">http://www.silverlightshow.net/news/ICommand-in-Silverlight-4-.aspx</a> </li> <li><a href="http://geekswithblogs.net/HouseOfBilz/archive/2009/05/22/adventures-in-mvvm-ndash-commands-in-silverlight.aspx" target="_blank">http://geekswithblogs.net/HouseOfBilz/archive/2009/05/22/adventures-in-mvvm-ndash-commands-in-silverlight.aspx</a> </li> </ul> </li> </ul> <h4>Summary</h4> <p>In this part, we prepared ourselves for the code-side of Silverlight. Not everything is XAML so there are some really important things to understand that you need to know in this area. Aspects such as Dependency Properties, Attached Properties and the ICommand interface are tools you’ll surely want in your Silverlight toolbox!</p> <p>In part 4, data will be our focus, when we look at things like data binding and validation.</p> <h4>About Gill</h4> <p>Gill Cleeren is Microsoft Regional Director (<a href="http://www.theregion.com/">www.theregion.com</a>), Silverlight MVP (former ASP.NET MVP), INETA speaker bureau member and Silverlight Insider. He lives in Belgium where he works as .NET architect at Ordina. Passionate about .NET, he’s always playing with the newest bits. In his role as Regional Director, Gill has given many sessions, webcasts and trainings on new as well as existing technologies, such as Silverlight, ASP.NET and WPF at conferences including TechEd Berlin 2010, TechDays Belgium, DevDays NL, NDC Oslo Norway, SQL Server Saturday Switserland, Spring Conference UK, Silverlight Roadshow in Sweden… He’s also the author of many articles in various developer magazines and for SilverlightShow.net. He organizes the yearly Community Day event in Belgium.</p> <p>He also leads Visug (<a href="http://www.visug.be/">www.visug.be</a>), the largest .NET user group in Belgium. Gill recently published his first book: “<a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">Silverlight 4 Data and Services Cookbook</a>” (Packt Publishing). You can find his blog at <a href="http://www.snowball.be/">www.snowball.be</a>. </p> <p>Twitter: @gillcleeren</p> <div></div> http://www.silverlightshow.net/items/Getting-ready-for-Microsoft-Silverlight-Exam-70-506-Part-3.aspx editorial@silverlightshow.net (Gill Cleeren ) http://www.silverlightshow.net/items/Getting-ready-for-Microsoft-Silverlight-Exam-70-506-Part-3.aspx#comments http://www.silverlightshow.net/items/Getting-ready-for-Microsoft-Silverlight-Exam-70-506-Part-3.aspx Tue, 01 Feb 2011 03:39:00 GMT A classic memory game: Part 2 - The game logic, connecting the ViewModel and the View <p><em><strong>This article is compatible with the latest version of Silverlight.</strong></em></p> <div style="padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;border: #dddddd 1px solid;"> <h3>Don't miss...</h3> <ul style="list-style-type: circle; margin: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/XNA-for-Silverlight-developers-Part-1-Fundamentals.aspx">XNA for SL developers series</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/book/Pro-Game-Design-with-Silverlight-4.aspx">Pro Game Design with SL4 book: </a></li> </ul> <p style="padding-bottom: 5px;">         <a href="http://www.silverlightshow.net/book/Pro-Game-Design-with-Silverlight-4.aspx"><img alt="Beginning Windows Phone 7 Development" src="http://www.silverlightshow.net/Storage/GameDesign.jpg" /></a> </p> <p style="font-size: 12px;">             <a href="http://www.silverlightshow.net/Books.aspx">Show more books</a><img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>This article is Part 2 of “A classic memory game”.</p> <p>The series is about building the following classic memory game in Silverlight, and porting it to Windows Phone 7. In the first article we started a new MVVM Light project, created the controls and designed the game-states. Now it’s time to put some code behind the game, and finish it.</p> <p>Here’s the game itself and you can <a href="http://www.silverlightshow.net/Storage/Sources/memoria_2.zip">download the source code here</a>.</p> <p style="text-align: center;"><iframe width="570" height="570" src="http://www.silverlightshow.net/Storage/demos/Memoria/MemoriaPart1.html"></iframe></p> <h3>The Game Logic</h3> <h4>MVVM Light template</h4> <h4></h4> <p>The MVVM Light project template contains a ViewModelLocator and a MainViewModel in the ViewModel folder. The ViewModelLocator’s job is to hold a reference of the ViewModels and to create them when needed. In the App.xaml there’s an instance of the ViewModelLocator, so the Views can bind to the ViewModel via this instance. </p> <p>App.xaml:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 60.53%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; height: 99px; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"><</span><span style="color: #800000;">Application.Resources</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">ResourceDictionary</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">vm:MemoryViewModelLocator</span> <span style="color: #ff0000;">x:Key</span><span style="color: #0000ff;">="Locator"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">d:IsDataSource</span><span style="color: #0000ff;">="True"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"></</span><span style="color: #800000;">ResourceDictionary</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"></</span><span style="color: #800000;">Application.Resources</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>MainPage.xaml:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 60.68%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; height: 49px; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"><</span><span style="color: #800000;">UserControl.DataContext</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 59.72%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; height: 16px; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">Binding</span> <span style="color: #ff0000;">Path</span><span style="color: #0000ff;">="Main"</span> <span style="color: #ff0000;">Source</span><span style="color: #0000ff;">="{StaticResource Locator}"</span><span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 99.81%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; height: 16px; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"></</span><span style="color: #800000;">UserControl.DataContext</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <h4>Model</h4> <p>To represent the cards, we have a MemoryCard class with the following properties:</p> <ul> <li>the <strong>ID</strong> specifies which image is on the card </li> <li>the <strong>Upside</strong> property indicates if a card is showing it’s face or back </li> <li>the <strong>Solved</strong> property is set true once the card and its pair are found </li> </ul> <p>The MemoryCard class implements the <strong>INotifyPropertyChanged</strong> interface. Classes that implement this interface must have an event delegate PropertyChangedEventHandler. Raising this event enables the View (that’s the MainPage.xaml) to track changes. So we need to raise this event when setting the Upside and the Solved properties. The ID won’t change in a MemoryCard’s lifetime so we don’t need to do anything there.</p> <p>Here’s the Upside property and the raisePropertyChanged method.</p> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 90.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #008000;">/// The <see cref="Upside" /> property's name.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">string</span> UpsidePropertyName = <span style="color: #006080;">"Upside"</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">bool</span> _upside = <span style="color: #0000ff;">false</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #008000;">/// Gets the Upside property.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #008000;">/// Changes to that property's value raise the PropertyChanged event. </span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">bool</span> Upside</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> get</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> _upside;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> set</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (_upside == <span style="color: #0000ff;">value</span>)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> _upside = <span style="color: #0000ff;">value</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// Update bindings, no broadcast</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> raisePropertyChanged(UpsidePropertyName);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 92.1%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; height: 150px; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">event</span> PropertyChangedEventHandler PropertyChanged;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> raisePropertyChanged(<span style="color: #0000ff;">string</span> propertyName)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (PropertyChanged != <span style="color: #0000ff;">null</span>)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">this</span>.PropertyChanged(<span style="color: #0000ff;">this</span>, <span style="color: #0000ff;">new</span> PropertyChangedEventArgs(propertyName));</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <div> </div> <h4>The game logic</h4> <p>The logic is simple. In the MainViewModel’s constructor we’re setting up two timers (DispatcherTimers), one to turn back cards after a while and one for tracking the elapsed time. In the Start method we load the selected number of cards (based on the difficulty) and reset the score and start the elapsed timer.</p> <p>We have a few properties to store the state of the game. The most important one is the list of the cards (MemoryCardList). The MainViewModel derives from BaseViewModel that means we don’t have to explicitly implement the INotifyPropertyChanged interface because it’s already implemented in the base class as well as the RaisePropertyChanged method.</p> <p>Here’s the LoadCards method:</p> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 90.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> LoadCards()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">int</span> cardCount = 0;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">switch</span> (Difficulty)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">case</span> Difficulties.Easy:</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> cardCount = 8;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> CardSize = 100;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">break</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">case</span> Difficulties.Normal:</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> cardCount = 10;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> CardSize = 78;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">break</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">case</span> Difficulties.Hard:</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> cardCount = 15;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> CardSize = 62;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">break</span>; </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> } </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// clear</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> MemoryCardList.Clear();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// add cards</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < cardCount; i++)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> MemoryCardList.Add(<span style="color: #0000ff;">new</span> MemoryCard(i)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Upside = <span style="color: #0000ff;">false</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> });</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> MemoryCardList.Add(<span style="color: #0000ff;">new</span> MemoryCard(i)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> Upside = <span style="color: #0000ff;">false</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> });</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// shuffle them</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> var rand = <span style="color: #0000ff;">new</span> Random();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = MemoryCardList.Count - 1; i > 0; i--)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">int</span> n = rand.Next(i+1);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> var temp = MemoryCardList[i];</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> MemoryCardList[i] = MemoryCardList[n];</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> MemoryCardList[n] = temp;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> IsGameEnded = <span style="color: #0000ff;">false</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <p>Note that we are adding two cards with the same ID at a time in the loop so we can pair them. After adding the cards we shuffle them. One last thing to explain: the CardSize specifies the actual size (width and height) of the cards in the View as we have smaller cards when there more. Keeping the CardSize in the ViewModel is not very elegant, it should belong to the View, I’ll probably refactor it.</p> <p>The heart of the game is the <strong>OnSelectionChanged</strong> method. First we count the upside cards, if it’s two (which is actually one plus the newly flipped) we compare the IDs. If there’s a match they are solved. We have to check if there are any unsolved cards there to track the end of the game. If two cards are already upside showing their front, the newly selected would be the third card to show it’s front, so we have to flip back everything. Here’s the code:</p> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 90.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> OnSelectionChanged(MemoryCard lastCard)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">int</span> upsideNo = MemoryCardList.Count((m) => m.Upside); </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (upsideNo == 1)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// one is upside + lastCard is 2, check IDs</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> MoveCounter++;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> var upsideCard = MemoryCardList.First((m) => m.Upside);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (upsideCard.ID == lastCard.ID)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (MemoryCardList.Count((m) => !m.Solved) == 2)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> _elapsedTimer.Stop();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> EndGame();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> } </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> upsideCard.SetSolved();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> lastCard.SetSolved();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> PairCounter++; </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (!_timer.IsEnabled)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> _timer.Start();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> } </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (upsideNo == 2)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// two is already upside, hide them, lastCard will be the only upside</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> _timer.Stop();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> hideCards();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> } </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <h3> </h3> <h3>Connecting the ViewModel and the View</h3> <p>After building the project the MainViewModel properties should show up in Blend’s databinding windows. We bind the MemoryCardList to the ListBox’s ItemSource. Click on the little square next to the ItemSource, choose DataBinding and select the MemoryCardList in the DataContext tab.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/wildfox/binding0_thumb_2.png"><img width="804" height="124" title="binding0_thumb" style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;border: 0px solid;" alt="binding0_thumb" src="http://www.silverlightshow.net/Storage/Users/wildfox/binding0_thumb_thumb.png" /></a></p> <p>Now the ListBox will always display the cards in the ViewModel’s MemoryCardList property.</p> <h4>Converters</h4> <p>Blend’s databinding window shows only the compatible types by default. That means for example an IsVisible property type of bool won’t show up (by default) when you try to bind it to any element’s Visibility property, because the Visibility is type of a Visibility enum. Here enters the IValueConverter interface. When you build a class implementing this interface, you can pass it to the binding to have the data converted to compatible type.</p> <p>A classic example is the VisiblityConverter for the Solved property (so it’s working the opposite way), note that only one way is implemented, we won’t need the ConvertBack:</p> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 90.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> VisibilityConverter : IValueConverter</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #cc6633;">#region</span> IValueConverter Members</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">object</span> Convert(<span style="color: #0000ff;">object</span> <span style="color: #0000ff;">value</span>, Type targetType, <span style="color: #0000ff;">object</span> parameter, System.Globalization.CultureInfo culture)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">value</span> == <span style="color: #0000ff;">null</span>) <span style="color: #0000ff;">return</span> Visibility.Visible;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> ((<span style="color: #0000ff;">bool</span>)<span style="color: #0000ff;">value</span>) <span style="color: #0000ff;">return</span> Visibility.Collapsed;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">return</span> Visibility.Visible;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">object</span> ConvertBack(<span style="color: #0000ff;">object</span> <span style="color: #0000ff;">value</span>, Type targetType, <span style="color: #0000ff;">object</span> parameter, System.Globalization.CultureInfo culture)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> NotImplementedException();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #cc6633;">#endregion</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <p>After build, you can set it up in Blend for the MemoryCard’s Solved property. Edit the CardList’s ItemTemplate, select the ToggleButton and bind the Visibility property:</p> <p>Switch to all properties, select the Solved property, open the dropdown at the bottom of the window, and select the VisibilityConverter as Value converter.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/wildfox/binding2_thumb3_2.png"><img width="426" height="508" title="binding2_thumb3" style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;border: 0px solid;" alt="binding2_thumb3" src="http://www.silverlightshow.net/Storage/Users/wildfox/binding2_thumb3_thumb.png" /></a></p> <p>You can bind the Checked property to the Upside property without a converter, because both of them are a type of bool.</p> <p>Sometimes we need the ValueConverter in both ways, and sometimes we need additional parameters. To set the difficulty I needed both. There is a RadioButton for each difficulty, and we have one Difficulty property in the ViewModel type of an enum. So to make it work I needed to pass which RadioButton is the target. Here’s the code for the DifficultyConverter:</p> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 90.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">object</span> Convert(<span style="color: #0000ff;">object</span> <span style="color: #0000ff;">value</span>, Type targetType, <span style="color: #0000ff;">object</span> parameter, System.Globalization.CultureInfo culture)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (System.Convert.ToString(<span style="color: #0000ff;">value</span>).Equals(System.Convert.ToString(parameter)))</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">object</span> ConvertBack(<span style="color: #0000ff;">object</span> <span style="color: #0000ff;">value</span>, Type targetType, <span style="color: #0000ff;">object</span> parameter, System.Globalization.CultureInfo culture)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (System.Convert.ToBoolean(<span style="color: #0000ff;">value</span>))</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> Enum.Parse(<span style="color: #0000ff;">typeof</span>(Difficulties), System.Convert.ToString(parameter), <span style="color: #0000ff;">true</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <p>And here’s the Binding for the Easy difficulty to the button’s Checked property:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/wildfox/binding3_thumb2_2.png"><img width="413" height="493" title="binding3_thumb2" style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;border: 0px solid;" alt="binding3_thumb2" src="http://www.silverlightshow.net/Storage/Users/wildfox/binding3_thumb2_thumb.png" /></a></p> <p>Another converter was needed for displaying the images based on the ID. The <strong>ImageConverter</strong> takes the ID and converts it to an ImageSource by resolving a naming convention.</p> <h4>Formatting text</h4> <p>Converters are often used to format text, for example converting a number to string in a desired format. Silverlight 4 however introduced the StringFormat extension. Unfortunately I couldn’t find any Blend support here, so we have to dive into code to make it working. The following code formats the move counter to a 2-digit style:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/wildfox/formatting_thumb1_2.png"><img width="475" height="67" title="formatting_thumb1" style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;border: 0px solid;" alt="formatting_thumb1" src="http://www.silverlightshow.net/Storage/Users/wildfox/formatting_thumb1_thumb.png" /></a></p> <p>You can find a good summary about StringFormat on <a href="http://www.designersilverlight.com/2010/05/28/silverlight-4-binding-and-stringformat-in-xaml/">DesignerSilverlight</a>.</p> <h4>CallDatacontextMethodAction</h4> <p>We have to connect not just the data in the ViewModel to the View, but user-actions too. The standard way for the View to notify the ViewModel that something is happened is by commands. A simpler and more designer friendly approach is the CallDatacontextMethodAction behavior by <a href="http://dotneteers.net/blogs/vbandi/">András Velvárt</a>. You might have already read the article about it: <a href="http://www.silverlightshow.net/items/A-Designer-friendly-Approach-to-MVVM-Part-I.aspx">A Designer-friendly Approach to MVVM</a>.</p> <p>After adding it to the project and building it we can add it to our Start button to call the Start method on the ViewModel.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/wildfox/calldatacontextmethod0_thumb1_2.png"><img width="247" height="418" title="calldatacontextmethod0_thumb1" style="background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;border: 0px solid;" alt="calldatacontextmethod0_thumb1" src="http://www.silverlightshow.net/Storage/Users/wildfox/calldatacontextmethod0_thumb1_thumb.png" /></a>    <a href="http://www.silverlightshow.net/Storage/Users/wildfox/calldatacontextmethod1_thumb1_2.png"><img width="484" height="280" title="calldatacontextmethod1_thumb1" style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;border: 0px solid;" alt="calldatacontextmethod1_thumb1" src="http://www.silverlightshow.net/Storage/Users/wildfox/calldatacontextmethod1_thumb1_thumb.png" /></a></p> <h4></h4> <h4>Delaying an action</h4> <p>For the MemoryCard I had to delay the effect of setting the Solved property to true. What happened is by setting the card to solved it immediately disappeared, even before the control would arrive to the Checked state. This was clearly not okay, the player couldn’t see the card before it was marked as solved and disappeared.  That’s why I introduced the SetSolved method that starts a timer and only after 1.5 seconds sets the Solved property to true thus making the card disappear.</p> <h4>The Messenger class</h4> <p>The ViewModel sends a signal to the View once all of the cards are collected by using <a href="http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx">MVVM Light Messenger class</a>. The View then moves into the EndState:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">Messenger.Default.Register<<span style="color: #0000ff;">string</span>>(<span style="color: #0000ff;">this</span>, (msg) =></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (Constants.EndGameMessage == msg)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> { </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> VisualStateManager.GoToState(<span style="color: #0000ff;">this</span>, EndState.Name, <span style="color: #0000ff;">true</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">});</pre> <!--CRLF--></div> </div> <h3> </h3> <p>The Messenger is used in the MemoryCard class as well. When the card is flipped it notifies the MainViewModel and that is when the OnSelectionChanged method runs, which is the heart of the game.</p> <h3>Summary</h3> <p>In this article we inspected the development aspects of a game leveraging on MVVM using bindings, visual states, transitions and behaviors. Expression Blend turned out to be a really powerful tool as for the whole game we needed only little coding.</p> <p>In the final article of the series I will port this game to Windows Phone 7, exploring performance optimizations, phone-specific UI, and tombstoning. Don’t hesitate to drop a comment if you have questions or want to see something specific in the next article.</p> <h3>About the Author</h3> <p><img width="150" height="190" style="width: 100px; float: left; height: 134px; margin-right: 15px;" alt="Levente Mihaly" src="http://www.silverlightshow.net/Storage/levi.jpg" />My name is Levente Mihaly. I've entered the .NET world in 2006, and after graduating at Budapest University of Technology (Msc in Computer Science) I started working as a .NET software developer. After meeting technologies like WinForms and ASP.NET, Silverlight quickly became my favourite platform from the early Silverlight 2 beta stages. I was always interested in mobile development and now I'm very happy since with Windows Phone 7 I can easily expand my knowledge to the mobile world. Nowadays beside following Silverlight I'm focusing on WP7 in my free time. I'm also the runner-up of the 2010 Silverlight ecoContest. You can reach me on twitter (<a href="http://twitter.com/#!/leventemihaly" target="_blank">@leventemihaly</a>). <br />  </p> http://www.silverlightshow.net/items/A-classic-memory-game-Part-2-The-game-logic-connecting-the-ViewModel-and-the-View.aspx editorial@silverlightshow.net (Levente Mihály ) http://www.silverlightshow.net/items/A-classic-memory-game-Part-2-The-game-logic-connecting-the-ViewModel-and-the-View.aspx#comments http://www.silverlightshow.net/items/A-classic-memory-game-Part-2-The-game-logic-connecting-the-ViewModel-and-the-View.aspx Fri, 21 Jan 2011 09:54:00 GMT Caching of, in, and around your Silverlight application (part 3) <p><em><strong>This article is compatible with the latest version of Silverlight.</strong></em></p> <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>Don't miss...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Microsoft-Silverlight-4-Data-and-Services-Cookbook-Interview-with-Co-author-Kevin-Dockx.aspx">Read interview with Kevin Dockx</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/My-XAP-file-is-5-Mb-size-is-that-bad.aspx">My XAP file is 5 Mb size, is that bad?</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/caching.aspx">This series is now available as a fully offline resource: </a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/caching.aspx"><img style="border:0px solid;" alt="Caching of, in, and around your Silverlight application Ebook" src="http://www.silverlightshow.net/Storage/caching_ebook_thumbS.png" usemap="#rade_img_map_1291385581316" /></a><br /> <strong><span style="font-size: 13px;">($0.99)</span></strong></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>This is the third in a 3-part series of articles about caching & Silverlight.</p> <p>This is the third part in a 3-part series on Silverlight and Caching. The first part was about XAP & Assembly caching, which you can find <a href="http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application-part-1.aspx" target="_blank">here</a>. In the part, we learned how we can leverage the Isolated Storage for caching in the same and between different Silverlight applications. You can find that article <a href="http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application-part-2.aspx" target="_blank">here</a>. In this third and final part, we’ll look at the server side of things, and an extra piece of code to throw in the mix: a Silverlight caching provider.</p> <p><a href="http://www.silverlightshow.net/Storage/Sources/SilverlightShowCaching3.zip" target="_blank">The source code for this part can be found here.</a></p> <p> </p> <h3>Server side caching with a WCF Service</h3> <p>In the previous part, we’ve seen how we can make sure a certain server side method is only called once: when the data isn’t available on the client. But next to caching data on the client, it can also be cached on the server. But what’s the advantage of this? Sure, caching your data on the server might mean you only need to call your database once (assuming we’re fetching data from a database) – the next times, the data will come from the server side cache. But if we’re already caching the data on the client, aren’t we better off with that? With server side caching, you still need to call your service method every time, with client side caching, you only call it once, right?</p> <p>Well: image a multi-user environment – pretty typical for most applications. If we use the example from the previous article, our GetCities operation, including the actual fetching of the data (which, in the example, is just using some dummy data, but in real-life would probably come from some kind of database), would be called once for each user. If you cache the data server side after the first data fetch, the first user call to the operation would result in a hit on your database. All the following calls, from different users, would result in getting the data from the server side cache instead of the database.</p> <p>As you can see, this can offer tremendous advantages in multi-user environments. In a real-life environment, you should always combine client side caching with server side caching.</p> <p>In a WCF service, you leverage the HttpContext’s Cache for this. Let’s adjust our example method:</p> <pre class="csharpcode"><p>[OperationContract] <span class="kwrd">public</span> List<City> GetCitiesCachedServerSide() { <span class="kwrd">string</span> cacheKey = <span class="str">"CachedCities"</span>; <span class="rem">// create a new generic list to hold the cities. </span> List<City> cityList = <span class="kwrd">new</span> List<City>(); <span class="rem">// check if the list is in cache</span> <span class="kwrd">if</span> (HttpContext.Current.Cache.Get(cacheKey) == <span class="kwrd">null</span>) { cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"ANT"</span>, Description = <span class="str">"Antwerp"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"BRU"</span>, Description = <span class="str">"Brussels"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"GHE"</span>, Description = <span class="str">"Ghent"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"AMS"</span>, Description = <span class="str">"Amsterdam"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"PAR"</span>, Description = <span class="str">"Paris"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"LON"</span>, Description = <span class="str">"London"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"BAR"</span>, Description = <span class="str">"Barcelona"</span> }); <span class="rem">// add list to cache for 5 minutes</span> HttpContext.Current.Cache.Add(cacheKey, cityList, <span class="kwrd">null</span>, DateTime.Now.AddMinutes(5), <br />Cache.NoSlidingExpiration, CacheItemPriority.Default, <span class="kwrd">null</span>); } <span class="kwrd">else</span> { <span class="rem">// get list from cache</span> cityList = (List<City>)HttpContext.Current.Cache[cacheKey]; } <span class="kwrd">return</span> cityList; } </p></pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>As you can see, we check if the list of countries already exists in the cache. If it doesn’t, we add it, making sure each next call will fetch the data from the cache.</p> <pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> GetFromWCFCachedServerSide() { <span class="rem">// call WCF Service</span> CityServiceReference.CityServiceClient client = <span class="kwrd">new</span> CityServiceClient(); client.GetCitiesCachedServerSideCompleted += (send, args) => { <span class="kwrd">if</span> (args.Error == <span class="kwrd">null</span>) { Cities = args.Result; userIsolatedStorageSettings[<span class="str">"CachingCities"</span>] = <span class="kwrd">new</span> ObservableCollection<City>(args.Result); userIsolatedStorageSettings.Save(); } }; client.GetCitiesCachedServerSideAsync(); }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>You’ve got a few options when adding an item to cache:</p> <ul> <li><strong>absoluteExpiration</strong>: enables you to define when an item in cache should become invalid, and thus removed from the cache. If you’re using sliding expiration, this should be set to NoAbsoluteExpiration. </li> <li><strong>slidingExpiration</strong>: defines the interval between when an object was last accessed and when it must be removed from the cache. If you’re using absolute expiration, this should be set to NoSlidingExpiration. </li> <li><strong>cacheItemPriority</strong>: the relative cost of an item in your cache. Items with lower cost are removed first. </li> <li><strong>onRemoveCallback</strong>: a callback method which will be called when an item is removed from cache. </li> <li><strong>dependencies</strong>: CacheDependency for the item you’re adding in the cache. If a dependency is changed, the item in cache automatically expires. </li> </ul> <p> </p> <h3>Server side caching with WCF RIA Services</h3> <p>A lot of Silverlight applications are built with WCF RIA Service. Rightfully so, as it offers tremendous advantages and is quite extensible. With WCF RIA Services, you’ve got a client side DomainContext, in which you can load your entities – and it keeps your entities there by default. This already results in quite a lot less data fetching operations when used correctly: often, the client side DomainContext is kept in an application-wide accessible LocalStateContainer (a simple static class) as a static property. The ViewModels that need data can directly access it from the DomainContext instance, keeping the need to refetch data to a minimum, and at the same time offering you the advantage that your screens stay “in sync” (as they’re all referring to the same data – change that data in one screen, and it’s automatically updated in a different screen using the same entities).</p> <p>What’s less know is that you can also cache your WCF RIA Services result sets on the server – again, offering big advantages in a multi-user environment. The magic word here is the OutputCach attribute: decorate a query method with this method, and (depending on the options you provide), the resultset is cached for a certain amount of time. In the demo code, I’ve added a DomainService which returns a list of cities – this time, using WCF RIA Services instead of regular WCF. The resultset will be cached on the server:</p> <pre class="csharpcode">[OutputCache(OutputCacheLocation.Server, 180, UseSlidingExpiration = <span class="kwrd">true</span>)] <span class="kwrd">public</span> IQueryable<CityForRIA> GetCities() { <span class="rem">// create a new generic list to hold the cities</span> List<CityForRIA> cityList = <span class="kwrd">new</span> List<CityForRIA>(); cityList.Add(<span class="kwrd">new</span> CityForRIA() { ID = <span class="str">"ANT"</span>, Description = <span class="str">"Antwerp"</span> }); cityList.Add(<span class="kwrd">new</span> CityForRIA() { ID = <span class="str">"BRU"</span>, Description = <span class="str">"Brussels"</span> }); cityList.Add(<span class="kwrd">new</span> CityForRIA() { ID = <span class="str">"GHE"</span>, Description = <span class="str">"Ghent"</span> }); cityList.Add(<span class="kwrd">new</span> CityForRIA() { ID = <span class="str">"AMS"</span>, Description = <span class="str">"Amsterdam"</span> }); cityList.Add(<span class="kwrd">new</span> CityForRIA() { ID = <span class="str">"PAR"</span>, Description = <span class="str">"Paris"</span> }); cityList.Add(<span class="kwrd">new</span> CityForRIA() { ID = <span class="str">"LON"</span>, Description = <span class="str">"London"</span> }); cityList.Add(<span class="kwrd">new</span> CityForRIA() { ID = <span class="str">"BAR"</span>, Description = <span class="str">"Barcelona"</span> }); <span class="kwrd">return</span> cityList.AsQueryable<CityForRIA>(); }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>And this is how we call the EntityQuery:</p> <pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> GetFromRIAServCachedServerSide() { var loadOp = LocalStateContainer.CityDomainContext</pre> <pre class="csharpcode">.Load<CityForRIA>(LocalStateContainer.CityDomainContext.GetCitiesQuery()); loadOp.Completed += (send, args) => { <span class="kwrd">if</span> (loadOp.HasError == <span class="kwrd">false</span>) { CitiesFromRIAServices = LocalStateContainer.CityDomainContext.CityForRIAs; } }; }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>The OutputCache attribute can be provided with different options, of which these are the most important ones: </p> <ul> <li><strong>cacheLocation</strong>: defines where items can be cached: client, server, or both. </li> <li><strong>duration</strong>: the duration, in seconds, before an item will expire. </li> <li><strong>UseSlidingExpiration</strong>: if this is set to true, the duration will be reset each time an item from cache is accessed. If set to false, the item will expire after the duration – in absolute terms – has passed. </li> <li><strong>VaryByHeaders</strong>: if the message headers are different, a new item will be added to the cache instead of returning the already existing one. </li> </ul> <p> </p> <h3>Providing the missing parts: a Silverlight Cache Provider.</h3> <p>Throughout this article series, we’ve talked about various ways of caching. Those familiar with the ASP .NET Cache might have noticed something is missing in the Silverlight framework: yes, you can leverage the Isolated Storage for caching, but in a true caching scenario, you’d want to be able to make sure items in cache expire after a while. And are refetched automatically when needed, maybe? You might also want to make sure this is done with as little effort as possible throughout the development of your application. In ASP .NET, you’ve got the Cache store for this, but an equivalent doesn’t really exist in Silverlight: you have to write that yourself.</p> <p>In the next few paragraphs, we’re going to do just that: write a Silverlight enabled cache provider.</p> <p>What we want to end up with is: </p> <ul> <li>A way to add items to your cache </li> <li>A way to make sure these items expire after a while </li> <li>A way to make sure these items are automatically refetched when needed </li> <li>… and it should be easy to use </li> </ul> <p>We’ll start out by defining the contracts. These contracts can be pretty simple – most of the work should be done in the specific implementations, which can vary depending on how you want to fetch the data (WCF, WCF RIA Services, …) and how you want to save the data (in memory, in Isolated Storage, …).</p> <p>To start, we’ll need an ICache contract, which is our cache store.  In the contract, we define a CacheStoreKey, a Put method and a Get method.  Important to notice is this Get method should have a callback, as we’re working async if the item data isn’t loaded yet.  </p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">interface</span> ICache { <span class="kwrd">void</span> Put(ICacheItem cacheItem); <span class="kwrd">void</span> Get(<span class="kwrd">string</span> key, EventHandler<GenericEventArgs<ICacheItem>> callback); <span class="kwrd">string</span> CacheStoreKey { get;} }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>Next, we’ll need an ICacheItem contract, which should have a key, a function used to check if the data is available (and, eventually, fill the item with data) with a callback (used to pass through the Get method callback from the cache store), and a timespan which tells us how long the item is valid in cache. </p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">interface</span> ICacheItem { <span class="kwrd">void</span> CheckAndFillOrUpdate(EventHandler<GenericEventArgs<ICacheItem>> callback); <span class="kwrd">string</span> Key { get; } TimeSpan ExpiresAfter { get; } }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>The specific implementation of the ICache contract will provide the cache dictionary used to keep the items.  This results in the following code:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> InMemCache : ICache { Dictionary<<span class="kwrd">string</span>, ICacheItem> CacheDictionary = <span class="kwrd">new</span> Dictionary<<span class="kwrd">string</span>, ICacheItem>(); <span class="kwrd">public</span> InMemCache(<span class="kwrd">string</span> cacheStoreKey) { _cacheStoreKey = cacheStoreKey; CacheDictionary = <span class="kwrd">new</span> Dictionary<<span class="kwrd">string</span>, ICacheItem>(); } <span class="kwrd">public</span> <span class="kwrd">void</span> Put(ICacheItem cacheItem) { CacheDictionary.Add(cacheItem.Key, cacheItem); } <span class="kwrd">public</span> <span class="kwrd">void</span> Get(<span class="kwrd">string</span> key, EventHandler<GenericEventArgs<ICacheItem>> callback) { <span class="kwrd">if</span> (CacheDictionary.ContainsKey(key)) { var currentItem = CacheDictionary[key]; currentItem.CheckAndFillOrUpdate(callback); } } <span class="kwrd">private</span> <span class="kwrd">string</span> _cacheStoreKey; <span class="kwrd">public</span> <span class="kwrd">string</span> CacheStoreKey { get { <span class="kwrd">return</span> _cacheStoreKey; } } }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>The idea is that putting an item in cache will not fetch it immediately: putting an item in cache is equal to defining <em>how</em> it will be fetched.</p> <p>The ICacheItem implementation is a bit more complex.  For this example, we’ll assume we’re working with WCF RIA Services, as this is the framework of choice often used in Silverlight applications. This means our implementation should be able to accept a function to load our items (which accepts an EntityQuery returns a LoadOperation) and the EntityQuery itself.  You could probably simplify this somewhat with reflection, but as we’re writing a cache provider performance is important, and using reflection is typically quite resource intensive.  Although you could argue that, to simplify the use of this provider, using reflection can be justified – it’s up to you.</p> <p>This is how the implementation of ICacheItem looks:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> InMemCacheItem<T, S> : ICacheItem <span class="kwrd">where</span> S : Entity { <span class="kwrd">public</span> T Value; <span class="kwrd">public</span> DateTime? LastCheck; <span class="kwrd">public</span> Func<EntityQuery<S>, LoadOperation<S>> FillAndUpdateFunction { get; set; } <span class="kwrd">public</span> EntityQuery<S> EntityQuery { get; set; } <span class="kwrd">private</span> <span class="kwrd">string</span> _key; <span class="kwrd">public</span> <span class="kwrd">string</span> Key { get { <span class="kwrd">return</span> _key; } } <span class="kwrd">private</span> TimeSpan _expiresAfter; <span class="kwrd">public</span> TimeSpan ExpiresAfter { get { <span class="kwrd">return</span> _expiresAfter; } } <span class="kwrd">public</span> InMemCacheItem(<span class="kwrd">string</span> key, TimeSpan expiresAfter, Func<EntityQuery<S>, LoadOperation<S>> fillAndUpdateFunction, EntityQuery<S> entityQuery) { <span class="kwrd">this</span>._key = key; <span class="kwrd">this</span>._expiresAfter = expiresAfter; <span class="kwrd">this</span>.FillAndUpdateFunction = fillAndUpdateFunction; <span class="kwrd">this</span>.EntityQuery = entityQuery; } <span class="kwrd">public</span> <span class="kwrd">void</span> CheckAndFillOrUpdate(EventHandler<GenericEventArgs<ICacheItem>> callback) { <span class="kwrd">if</span> ((LastCheck == <span class="kwrd">null</span>) || (DateTime.Now.Subtract(ExpiresAfter) > LastCheck)) { <span class="rem">// refetch</span> var lo = FillAndUpdateFunction.Invoke(EntityQuery); EventHandler handler = <span class="kwrd">null</span>; handler += (send, args) => { lo.Completed -= handler; <span class="kwrd">this</span>.Value = (T)lo.Entities; LastCheck = DateTime.Now; <span class="rem">// exec callback</span> callback.Invoke(<span class="kwrd">this</span>, <span class="kwrd">new</span> GenericEventArgs<ICacheItem>(<span class="kwrd">this</span>)); }; lo.Completed += handler; } <span class="kwrd">else</span> { <span class="rem">// the data is in cache and isn't expired, just execute the callback</span> callback.Invoke(<span class="kwrd">this</span>, <span class="kwrd">new</span> GenericEventArgs<ICacheItem>(<span class="kwrd">this</span>)); } } }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>All the pieces are in place, we can start using this provider.  When you put an item in cache, you tell it how it should fetch its data:</p> <pre class="csharpcode">CacheProvider.Put( <span class="kwrd">new</span> InMemCacheItem<IEnumerable<CityForRIA>, CityForRIA>( <span class="str">"Cities"</span> , TimeSpan.FromSeconds(100) , (query) => { <span class="kwrd">return</span> (LoadOperation<CityForRIA>)LocalStateContainer.CityDomainContext.Load(query); } , LocalStateContainer.CityDomainContext.GetCitiesForClientCacheQuery() ));</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>As said, what we’ve done here is the initialization of a cache item: this is not the data fetch itself, it just defines how data should be fetched when needed.</p> <p>Fetching the data is done with the Get method on the cache store: </p> <pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> GetWithCacheProvider() { <span class="rem">// get from cache</span> CacheProvider.Get(<span class="str">"Cities"</span>, (send, args) => { <span class="rem">// the callback</span> CitiesFromRIAServices = <span class="kwrd">new</span> ObservableCollection<CityForRIA>( ((InMemCacheItem<IEnumerable<CityForRIA>, CityForRIA>)args.Value).Value); }); }</pre> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } </style> <p>What will happen is: if the data for an item in the dictionary is available and hasn’t expired it will come from that item’s value property: the callback will be executed immediately. If that isn’t the case, the data will be fetched using the method we’ve provided on initialization. After the data has been fetched, the Value property will be set, and the callback from the Get method we’ve provided will be executed.</p> <p>With these few classes, we’ve now got a basic Silverlight cache provider.  Due to the fact that we’re working on interfaces, not specific implementations of these interfaces, you can easily work from this example to create your own provider and extend it to your liking. Like that, you could serialize items to and from Isolated Storage next to using the Dictionary. You could enable multiple Cache stores at the same time. You could make sure your items are saved between different Silverlight sessions, or even shareable between different Silverlight sites by using the caching techniques from part 2 – it’s all up to you and depends on the requirements of your application.</p> <p> </p> <h3>Conclusion</h3> <p>In the last part of these article series, we’ve seen how we can cache server side, and we’ve brought all the previous techniques together by writing an extensible Silverlight cache provider.  You should now have a good understanding on what caching in Silverlight means, and how you can profit from it in your applications.</p> <p>I hope you’ve enjoyed the article series– I know I enjoyed writing it :-)</p> <p> </p> <h3>About the author</h3> <p>Kevin Dockx lives in Belgium and works at <a href="http://www.realdolmen.com/">RealDolmen</a>, one of Belgium's biggest ICT companies, where he is a technical specialist/project leader on .NET web applications, mainly Silverlight, and a solution manager for Rich Applications (Silverlight, Windows Phone 7 Series, WPF, Surface). His main focus lies on all things Silverlight, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a Silverlight enthusiast, he's a regular speaker on various national and international events, like Microsoft DevDays in The Netherlands, Microsoft Techdays in Portugal or on BESUG events (the Belgian Silverlight User Group). Next to that, he also authored a best-selling Silverlight book, <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">Packt Publishing's Silverlight 4 Data and Services Cookbook</a>, together with <a href="http://www.snowball.be/">Gill Cleeren</a>. His blog, which contains various tidbits on Silverlight, .NET, and the occasional rambling, can be found at <a href="http://blog.kevindockx.com/">http://blog.kevindockx.com/</a>.</p> http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application.aspx#comments http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application.aspx Wed, 01 Dec 2010 10:13:00 GMT Caching of, in, and around your Silverlight application (part 2) <p><em><strong>This article is compatible with the latest version of Silverlight.</strong></em></p> <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>Don't miss...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Microsoft-Silverlight-4-Data-and-Services-Cookbook-Interview-with-Co-author-Kevin-Dockx.aspx">Read interview with Kevin Dockx</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/My-XAP-file-is-5-Mb-size-is-that-bad.aspx">My XAP file is 5 Mb size, is that bad?</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/caching.aspx">This series is now available as a fully offline resource: </a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/caching.aspx"><img style="border:0px solid;" alt="Caching of, in, and around your Silverlight application Ebook" src="http://www.silverlightshow.net/Storage/caching_ebook_thumbS.png" usemap="#rade_img_map_1291385581316" /></a><br /> <strong><span style="font-size: 13px;">($0.99)</span></strong></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>This is the second in a 3-part series of articles about caching & Silverlight.</p> <p>The first part was about XAP & Assembly caching, which you can find here. In this part, we’ll see how we can leverage the Isolated Storage for caching.</p> <p><a href="http://www.silverlightshow.net/Storage/Sources/SilverlightShowCaching.zip" target="_blank">You can download the source code here.</a> </p> <h3>Reusing data throughout your Silverlight application</h3> <p>But first, I’d like to tackle another issue I tend to get a lot of questions about: sharing data across different parts of your code, e.g.: across different ViewModels. Most of the people who ask me this type of question come from an ASP .NET / Web Application background, where you’ve got different pages in the same application, and you’d typically use something like Application State, Session State or even query strings to share data across different pages, and to avoid refetching it on each page (e.g.: you’re caching the data). If that’s what you’re used to working with, it’s very understandable you’re wondering what the Silverlight equivalent is.</p> <p>The keyword here is: state. As you know, (X)HTML is stateless: once you post your page to the server to request a new/changed version, the state of your page (actually: the state of your complete application) is lost. ASP .NET works around this by providing you with various means to get some kind of state: ViewState (page level), Session state (user-specific) or Application state (app-wide, across different sessions). In essence, these techniques try to solve the fact that HTML is stateless by providing you with means to achieve some kind of state in your web application. Data you need across different sessions, for example: a list of countries for a combobox, would typically be saved in the Application State. Data that’s user-specific could be saved in the Session state, et cetera.</p> <p>Fast forward to Silverlight. One of the big transitions one has to make when coming from a web background to Silverlight programming is getting used to the fact that Silverlight is stateful, not stateless: there’s no need for ViewState, Session state or Application state. If you look at it this way, programming a Silverlight application has much more in common with programming a desktop application than a web application, odd as it may seem. I’ve actually noticed that people coming from programming Windows Forms can often transition faster to correctly programming Silverlight applications, exactly because of this.</p> <p>So: to share data across different ViewModels, what you need is a part of your application which is accessible by all your ViewModels. A typical way to solve this is to provide your application with a LocalStateContainer class. This is a static class which contains static properties. These properties hold your application-wide data – once you need them in a ViewModel, add a property to your ViewModel which gets its data from the LocalStateContainer.</p> <p>Let’s assume our application needs to get a list of cities from a service. This list of cities should be available to all ViewModels in your application. We’ll start out by creating a WCF Service to get the list of cities. Add a City class to your Web application, and add a new Silverlight-enabled WCF Service which implements one operation: GetCities:</p> <pre class="csharpcode">[ServiceContract(Namespace = <span class="str">""</span>)] [AspNetCompatibilityRequirements(RequirementsMode = <br />    AspNetCompatibilityRequirementsMode.Allowed)] <span class="kwrd">public</span> <span class="kwrd">class</span> CityService { [OperationContract] <span class="kwrd">public</span> List<City> GetCities() { <span class="rem">// create a new generic list to hold the cities. </span> List<City> cityList = <span class="kwrd">new</span> List<City>(); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"ANT"</span>, Description = <span class="str">"Antwerp"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"BRU"</span>, Description = <span class="str">"Brussels"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"GHE"</span>, Description = <span class="str">"Ghent"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"AMS"</span>, Description = <span class="str">"Amsterdam"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"PAR"</span>, Description = <span class="str">"Paris"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"LON"</span>, Description = <span class="str">"London"</span> }); cityList.Add(<span class="kwrd">new</span> City() { ID = <span class="str">"BAR"</span>, Description = <span class="str">"Barcelona"</span> }); <span class="kwrd">return</span> cityList; } }</pre> <style type="text/css"> .csharpcode { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { MARGIN: 0em } .csharpcode .rem { COLOR: #008000 } .csharpcode .kwrd { COLOR: #0000ff } .csharpcode .str { COLOR: #006080 } .csharpcode .op { COLOR: #0000c0 } .csharpcode .preproc { COLOR: #cc6633 } .csharpcode .asp { BACKGROUND-COLOR: #ffff00 } .csharpcode .html { COLOR: #800000 } .csharpcode .attr { COLOR: #ff0000 } .csharpcode .alt { BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100% } .csharpcode .lnum { COLOR: #606060 } </style> <p>Next, add a Service Reference to this service from your Silverlight application.</p> <p>The LocalStateContainer class should now contain a static Observable Collection of cities. In the MainViewModel, we’ll fetch the data from the service, but we’ll only fetch the data when the city list is still empty. Once the cities have been fetched, we’ll put them in the LocalStateContainers’ City property.</p> <pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> GetCitiesFromServiceOrIsolatedStorage() { <span class="rem">// is there any country data in the Isolated Storage?</span> <span class="kwrd">if</span> (userIsolatedStorageSettings.Contains(<span class="str">"CachingCities"</span>)) { Cities = (ObservableCollection<City>)userIsolatedStorageSettings[<span class="str">"CachingCities"</span>]; } <span class="kwrd">else</span> { <span class="rem">// call WCF Service</span> CityServiceReference.CityServiceClient client = <span class="kwrd">new</span> CityServiceClient(); client.GetCitiesCompleted += (send, args) => { <span class="kwrd">if</span> (args.Error == <span class="kwrd">null</span>) { Cities = args.Result; userIsolatedStorageSettings[<span class="str">"CachingCities"</span>] = <br />                    <span class="kwrd">new</span> ObservableCollection<City>(args.Result); userIsolatedStorageSettings.Save(); } }; client.GetCitiesAsync(); } }</pre> <style type="text/css"> .csharpcode { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { MARGIN: 0em } .csharpcode .rem { COLOR: #008000 } .csharpcode .kwrd { COLOR: #0000ff } .csharpcode .str { COLOR: #006080 } .csharpcode .op { COLOR: #0000c0 } .csharpcode .preproc { COLOR: #cc6633 } .csharpcode .asp { BACKGROUND-COLOR: #ffff00 } .csharpcode .html { COLOR: #800000 } .csharpcode .attr { COLOR: #ff0000 } .csharpcode .alt { BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100% } .csharpcode .lnum { COLOR: #606060 } </style> <p>From now on, your city list is available application-wide. If you need access to this list, just add a property to a ViewModel which gets the cities from that LocalStateContainers’ Cities property.</p> <p>For demo purposes, I’m fetching the list of cities in my MainViewModel. Depending on the type of application you’re designing, you could change this. One way would be to fetch the application-wide data right after your application has been started. Another way would be to fetch each list the first time it’s needed through a method in your LocalStateContainer class. There is no “right way” which works for each and every application: the “right way” always depends on the type of application you’re designing.</p> <h3>Reusing data across different Silverlight sessions.</h3> <p>In the example above, we’ve made sure we only need to fetch the application-wide data once. However: your data isn’t persisted across different Silverlight sessions, meaning that every time a client restarts his application, the data will have to be fetched again. It would be nice to able to save data across different sessions – and this is where the Isolated Storage comes into play.</p> <p>From a Silverlight application, you can access the Isolated Storage on the client machine. The best way to look at this is as a virtual file system, which stores data in a hidden folder on the client machine. Each Silverlight application is allocated a part of Isolated Storage (by default: 1MB per application).</p> <p>Through System.IO.IsolatedStorage.IsolatedStorageSettings, you can access the ApplicationSettings. Now you’ve got a Dictionary<TKey, TValue> in which you can store data and/or from which you can fetch data. First, we’ll check if the dictionary already contains an item with key “CachingCities” (a unique key). If it does, we’ll fetch the data from Isolated Storage by filling the Cities property on our MainViewModel with the value from the CachingCities dictionary entry. If there’s no item with that key present, we fetch the data from our service, and save the data in Isolated Storage.</p> <pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> GetCitiesFromServiceOrIsolatedStorage() { <span class="rem">// is there any country data in the Isolated Storage?</span> <span class="kwrd">if</span> (userIsolatedStorageSettings.Contains(<span class="str">"CachingCities"</span>)) { Cities = (ObservableCollection<City>)userIsolatedStorageSettings[<span class="str">"CachingCities"</span>]; } <span class="kwrd">else</span> { <span class="rem">// call WCF Service</span> CityServiceReference.CityServiceClient client = <span class="kwrd">new</span> CityServiceClient(); client.GetCitiesCompleted += (send, args) => { <span class="kwrd">if</span> (args.Error == <span class="kwrd">null</span>) { Cities = args.Result; userIsolatedStorageSettings[<span class="str">"CachingCities"</span>] = <br />                    <span class="kwrd">new</span> ObservableCollection<City>(args.Result); userIsolatedStorageSettings.Save(); } }; client.GetCitiesAsync(); } }</pre> <style type="text/css"> .csharpcode { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { MARGIN: 0em } .csharpcode .rem { COLOR: #008000 } .csharpcode .kwrd { COLOR: #0000ff } .csharpcode .str { COLOR: #006080 } .csharpcode .op { COLOR: #0000c0 } .csharpcode .preproc { COLOR: #cc6633 } .csharpcode .asp { BACKGROUND-COLOR: #ffff00 } .csharpcode .html { COLOR: #800000 } .csharpcode .attr { COLOR: #ff0000 } .csharpcode .alt { BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100% } .csharpcode .lnum { COLOR: #606060 } </style> <p>Once the list is in Isolated Storage, the service call won’t have to be executed, even between different Silverlight sessions.  Our application will display the list of cities:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/image_4.png"><img width="686" height="314" title="image" style="border:0px; background-image: none; padding-left: 0px; width: 665px; padding-right: 0px; display: block; float: none; height: 297px; margin-left: auto; margin-right: auto; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/image_thumb_1.png" /></a></p> <p>One note of caution: although the Isolated Storage is hidden on the client machine, a user can still access the folder, so data stored isn’t completely secure. You can however use the Cryptography classes to encrypt the data you’re storing.</p> <p> </p> <h3>Clearing the Isolated Storage and asking for higher quota.</h3> <p>The Isolated Storage can be cleared as well, with the following statement:</p> <pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> ClearIsolatedStorage() { userIsolatedStorageSettings.Clear(); }</pre> <style type="text/css"> .csharpcode { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { MARGIN: 0em } .csharpcode .rem { COLOR: #008000 } .csharpcode .kwrd { COLOR: #0000ff } .csharpcode .str { COLOR: #006080 } .csharpcode .op { COLOR: #0000c0 } .csharpcode .preproc { COLOR: #cc6633 } .csharpcode .asp { BACKGROUND-COLOR: #ffff00 } .csharpcode .html { COLOR: #800000 } .csharpcode .attr { COLOR: #ff0000 } .csharpcode .alt { BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100% } .csharpcode .lnum { COLOR: #606060 } </style> <p>If you’re only saving small amounts of data, the default 1MB storage space will probably be sufficient. However, if you’re saving large sets of data, you might require more. This requires user interaction: you need to ask the client if he wants to increase the amount of Isolated Storage space available to your application by executing the IncreaseQuotaTo command on the current User Store.</p> <pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> IncreaseQuota() { <span class="kwrd">using</span> (var isf = IsolatedStorageFile.GetUserStoreForApplication()) { <span class="rem">// ask for 5MB </span> isf.IncreaseQuotaTo(5242880); } }</pre> <style type="text/css"> .csharpcode { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { MARGIN: 0em } .csharpcode .rem { COLOR: #008000 } .csharpcode .kwrd { COLOR: #0000ff } .csharpcode .str { COLOR: #006080 } .csharpcode .op { COLOR: #0000c0 } .csharpcode .preproc { COLOR: #cc6633 } .csharpcode .asp { BACKGROUND-COLOR: #ffff00 } .csharpcode .html { COLOR: #800000 } .csharpcode .attr { COLOR: #ff0000 } .csharpcode .alt { BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100% } .csharpcode .lnum { COLOR: #606060 } </style> <p>This will result in the user getting a popup like this:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/image_2.png"><img width="511" height="238" title="image" style="border:0px; background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/image_thumb.png" /></a></p> <p>To check the amount of space available to your application, right-click your Silverlight application, select “Silverlight” and navigate to the Application Storage tab. You’ll get an overview of the current usage & quote for all Silverlight applications using Isolated Storage on the current machine.</p> <p> </p> <h3>What about sharing the Isolated Storage between different applications?</h3> <p>Image the following scenario: you’re working for a company which uses a number of different Silverlight applications. All these applications use some shared data, for example: a list of employees, a list of company locations, … This is data which is pretty static, so you’d like to cache this data. However, if you’re using the Isolated Storage for this as we did in the previous paragraphs, each Silverlight application will have to fetch the list of employees, locations, … even though they are the same for each application.</p> <p>There’s a solution to this problem: sharing data from your Isolated Storage across applications. In the previous paragraphs, we’ve used IsolatedStorageSettings.ApplicationsSettings. There’s another user store available: the user store for the current site. This store is shared across all Silverlight applications hosted on the same site.</p> <p>You can access it through IsolatedStorageSettings.SiteSettings. However, in this case I prefer using the storage file directly (as you might know, IsolatedStorageSettings.ApplicationSettings and SiteSettings are just easy ways to access the underlying file, doing the serialization from/to objects in Isolated Storage for you, instead of having you write them yourself). I do this because IsolatedStorageSettings will save the data in its finalizer, which can actually result in different applications overwriting each others’ site settings with their own, resulting in empty data. By using the lower level API’s, you can make sure you won’t have this problem.</p> <p>Let’s change the code from the previous example a bit, so we’re storing the data in the Site store for the current user:</p> <pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> SaveCitiesToSiteStorage() { <span class="rem">// get the city list and save it to the site store, so other applications on</span> <span class="rem">// the same site can access it.</span> <span class="rem">// call WCF Service</span> CityServiceReference.CityServiceClient client = <span class="kwrd">new</span> CityServiceClient(); client.GetCitiesCompleted += (send, args) => { <span class="kwrd">if</span> (args.Error == <span class="kwrd">null</span>) { <span class="kwrd">using</span> (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForSite()) { IsolatedStorageFileStream fileStream = <span class="kwrd">null</span>; fileStream = isf.OpenFile(<br />                    <span class="str">"mySiteStore"</span>,<br />                    System.IO.FileMode.Create,<br />                    System.IO.FileAccess.ReadWrite); XmlSerializer xmlSerializer = <span class="kwrd">new</span> XmlSerializer(<br />                    <span class="kwrd">typeof</span>(ObservableCollection<City>),<br />                    <span class="str">"Cities"</span>); xmlSerializer.Serialize(fileStream, args.Result); fileStream.Flush(); fileStream.Close(); fileStream.Dispose(); } } }; client.GetCitiesAsync(); }</pre> <style type="text/css"> .csharpcode { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { MARGIN: 0em } .csharpcode .rem { COLOR: #008000 } .csharpcode .kwrd { COLOR: #0000ff } .csharpcode .str { COLOR: #006080 } .csharpcode .op { COLOR: #0000c0 } .csharpcode .preproc { COLOR: #cc6633 } .csharpcode .asp { BACKGROUND-COLOR: #ffff00 } .csharpcode .html { COLOR: #800000 } .csharpcode .attr { COLOR: #ff0000 } .csharpcode .alt { BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100% } .csharpcode .lnum { COLOR: #606060 } </style> <p>If we now add another Silverlight application to our solution, hosted on the same site, we can access the data saved to Isolated Storage from the first application:</p> <pre class="csharpcode"><span class="kwrd">public</span> MainViewModel() { <span class="rem">// get city list from site settings</span> <span class="kwrd">using</span> (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForSite()) { <span class="kwrd">if</span> (isf.FileExists(<span class="str">"mySiteStore"</span>)) { <span class="rem">// fetch the data </span> IsolatedStorageFileStream fileStream = isf.OpenFile(<br /><span class="str">                "mySiteStore"</span>,<br />                System.IO.FileMode.OpenOrCreate, <br />                System.IO.FileAccess.ReadWrite); XmlSerializer xmlSerializer = <span class="kwrd">new</span> XmlSerializer(<br />                <span class="kwrd">typeof</span>(ObservableCollection<City>),<br />                <span class="str">"Cities"</span>); Cities = (ObservableCollection<City>)xmlSerializer.Deserialize(fileStream); fileStream.Close(); fileStream.Dispose(); } } }</pre> <style type="text/css"> .csharpcode { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small } .csharpcode PRE { MARGIN: 0em } .csharpcode .rem { COLOR: #008000 } .csharpcode .kwrd { COLOR: #0000ff } .csharpcode .str { COLOR: #006080 } .csharpcode .op { COLOR: #0000c0 } .csharpcode .preproc { COLOR: #cc6633 } .csharpcode .asp { BACKGROUND-COLOR: #ffff00 } .csharpcode .html { COLOR: #800000 } .csharpcode .attr { COLOR: #ff0000 } .csharpcode .alt { BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100% } .csharpcode .lnum { COLOR: #606060 } </style> <p>So it’s pretty easy to share data across different Silverlight applications, but: they must be hosted on the same site.</p> <p> </p> <h3>Conclusion</h3> <p>This concludes the second part of this article, in which we’ve looked into various ways of leveraging the Isolated Storage to cache your data between sessions and/or between different applications.  Stay tuned for the next (and last) part, which will tackle server-side caching.</p> <p> </p> <h3>About the author</h3> <p>Kevin Dockx lives in Belgium and works at <a href="http://www.realdolmen.com/" target="_blank">RealDolmen</a>, one of Belgium's biggest ICT companies, where he is a technical specialist/project leader on .NET web applications, mainly Silverlight, and a solution manager for Rich Applications (Silverlight, Windows Phone 7 Series, WPF, Surface). His main focus lies on all things Silverlight, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a Silverlight enthusiast, he's a regular speaker on various national and international events, like Microsoft DevDays in The Netherlands, Microsoft Techdays in Portugal or on BESUG events (the Belgian Silverlight User Group). Next to that, he also authored a best-selling Silverlight book, <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">Packt Publishing's Silverlight 4 Data and Services Cookbook</a>, together with <a href="http://www.snowball.be/">Gill Cleeren</a>. His blog, which contains various tidbits on Silverlight, .NET, and the occasional rambling, can be found at <a href="http://blog.kevindockx.com/">http://blog.kevindockx.com/</a>.</p> http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application-part-2.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application-part-2.aspx#comments http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application-part-2.aspx Thu, 25 Nov 2010 07:40:00 GMT WCF RIA Services Part 9 - Structuring Your Application <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; padding-top: 5px;"><strong><img alt="" width="128" height="97" style="width: 112px; float: right; height: 80px; margin-left: 10px;" src="http://www.silverlightshow.net/Storage/old_skool_cassette.png" />Watch recordings of Brian's WCF RIA Services webinars:</strong>   <ul> <li><a href="http://www.silverlightshow.net/shows/WCF-RIA-Services-Webinar-1.aspx">Querying & Updating Data From Silverlight Clients with WCF RIA Services</a> (Feb 03, 2011)</li> <li><a href="http://www.silverlightshow.net/shows/WCF-RIA-Services-Webinar-2.aspx">WCF RIA Services Validation</a> (Mar 17, 2011)</li> <li><a href="http://www.silverlightshow.net/shows/WCF-RIA-Services-Webinar-3.aspx">Secure and Personalize Your Silverlight App with WCF RIA Services</a> (May 26, 2011)</li> <li><a href="http://www.silverlightshow.net/shows/WCF-RIA-Services-Webinar-4.aspx">WCF RIA POCO Domain Services</a> (Sep 29, 2011)</li> </ul> </div> <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>Don't miss...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Deep-dive-into-WCF-part-1-TDD.aspx">Deep Dive Into WCF series</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Search.aspx?q=WCF&adv=true&tg=true&ro=0&t=1,2,3,5&r=10&o=1">See more articles on WCF</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/shows/Paging-WCF-Ria-Services-entities-in-MVVM-applications.aspx">WCF RIA Services Show</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_services.aspx">The WCF series is now available as a fully offline resource: </a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_services.aspx"><img style="border:0px solid;" alt="WCF RIA Services Ebook" src="http://www.silverlightshow.net/Storage/wcf_ria_ebook_thumb0.png" usemap="#rade_img_map_1291385581316" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>This article is Part 9 of the series WCF RIA Services.</p> <h3>Introduction</h3> <p>In all the articles up to this point, I have been dumping all the domain service stuff into the single web project that also hosts the Silverlight application. Additionally, I've been putting a lot of functionality into the single Silverlight Application project on the client side. Granted it is only a couple of views so far. But if this app grew to a couple dozen views, I really would not want to be putting all those into a single project. In a real world app, too much code in one place, whether in a single method, a single class, or a single project is a maintenance liability. Additionally, on the server side you might want to start partitioning the code into logical layers, such as breaking out a separate data access layer project from the domain service code, and you might want separate projects for different sets of domain services.</p> <p>In this article, I'm going to focus on how to break your solution up into multiple projects on both the server and client sides. I'll show how you can break things up into vertical slices that support different use cases in your application or different functional areas. You'll quickly learn how to use WCF RIA Services Class Library projects, as well as how to break things up into multiple XAP files on the client side. Using the Managed Extensibility Framework or <a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=3453ab2b-2067-41e4-b087-312d8385cf1b&displaylang=en" target="_blank">Prism 4</a>, you can break up your client application into multiple modules that get developed and built as separate XAP files, and then get downloaded asynchronously when needed by the client application. When you go down this path, unfortunately Visual Studio gets in your way a little bit for setting up your WCF RIA services link with the server project. I'll show you how to easily get past that limitation as well.</p> <p>You can <a href="http://www.silverlightshow.net/Storage/Sources/TaskManagerPart9.zip" target="_blank">download the sample code for this article here</a>.</p> <h3>Client-Server Project Relationships</h3> <br /> <p>One thing to understand up front is that there are some architectural constraints implied by the use of WCF RIA Services. Because of the way the RIA Services code generation process works, if you want to consume a WCF RIA DomainService from a client project, that client project has to have a link to the server project that contains the domain services you want to consume. That means that a single client project can only point to a single server project. You can have multiple client projects that point to the same server project, and the code generation will happen in each client project. But then if those projects are all used in the same scope, you will have duplicate types defined in the same scope, and will run into problems there. So to keep things clean, you will want to maintain a one-to-one correspondence between a single server project where a set of domain services is defined and a single client project where the client code for those services gets generated. However, the client project can just be a class library that can be reused across multiple modules or client applications. So your architecture will tend to look like this as you start to partition things:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/Architecture_2.png"><img width="627" height="447" title="Architecture" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="Architecture" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/Architecture_thumb.png" /></a></p> <h3>Adding a WCF RIA Services Class Library Project</h3> <p>The way to get started breaking things up is to add a new WCF RIA Services Class Library project to your solution. In this case, say I wanted to add some separable functionality to my application, such as the ability to add notes. I would select Add > New Project from Solution Explorer with the solution node selected, and pick the WCF RIA Services Class Library project type.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/AddRIALibrary_2.png"><img width="716" height="417" title="AddRIALibrary" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="AddRIALibrary" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/AddRIALibrary_thumb.png" /></a></p> <p>Once you add this project, you really are adding two projects, the client Silverlight Class Library and a server normal Class Library project. The RIA Services link will already be set between the projects, and it adds them to the solution under a new solution folder.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/ClassLibrariesInSolution_2.png"><img width="328" height="315" title="ClassLibrariesInSolution" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="ClassLibrariesInSolution" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/ClassLibrariesInSolution_thumb.png" /></a></p> <p>You do not really have to use this project type to get this architecture though. You could just add a new Silverlight Class Library to the solution, then add a normal Class Library as well. Then you would just go to the project properties of the Silverlight Class Library and set the WCF RIA Services link drop down to point to the new server class library project. Then you would just have to add the WCF RIA Services references to the client and server projects. This just gets you all that done in one fell swoop. And since the client and server projects are linked, having them in a solution folder is a decent way to group them. </p> <p>You would then add a new domain service to the TaskManager.Notes.Web project to get started defining your new service functionality and its associated entities. Its code generated client code will end up in the TaskManager.Notes client library. Then you would add a reference from the main client TaskManager Silverlight application to the TaskManager.Notes class library to start using those domain services in the main app. You could add new views and client functionality to that same class library as well. If you wanted to separate out your data access logic into its own class library, you would just add a new class library project and add your Entity Data Model into that project. Then add a reference to that class library from the class library that is going to contain your domain service. Remember to build before adding the new domain service so that it will see your entity framework model and let you pick from its entity types. </p> <p>The resulting solution tree after adding some views and the data access library is shown below.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/SolutionTreeWithDomainService_2.png"><img width="311" height="514" title="SolutionTreeWithDomainService" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="SolutionTreeWithDomainService" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/SolutionTreeWithDomainService_thumb.png" /></a></p> <h3>Using Entities Across Domain Services</h3> <p>In WCF RIA Services version 1, there is a limitation that you cannot have two domain services being used by the same client application that expose the same entity type. This is just a limitation of the way the client side code generation is done, because it will try to generate the same entity type once for each service and you will have duplicate definitions. This is fixed in WCF RIA Services SP1, <a href="http://www.silverlight.net/getstarted/riaservices/" target="_blank">which is available in beta form at the time of writing this here</a>. But if you stick to the current release version, you will have to factor your vertical slices so that a given entity type is only used in one of the domain service vertical slices.</p> <h3>Breaking Your Client Application into Multiple Modules</h3> <p>As mentioned earlier, using MEF or Prism you can break your client architecture into modules – or separate chunks of functionality that can be downloaded asynchronously at runtime. For this article, I’ll just use MEF directly. I’ll be doing some articles on Prism 4 in the near future as well.</p> <p>To do this, you need to put your functionality in a project that compiles to a separate XAP file from the main application. That requires you to pick the Silverlight Application template when creating the project, as opposed to a Silverlight Class Library or a WCF RIA Services Class Library project.</p> <p>If I were going to do something similar to what I showed earlier in the article but wanted that new notes functionality to be downloaded separately as a module the first time it is used, the first step would be to create a new Silverlight Application project in my solution named TaskManager.NotesModule.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/AddModuleProject_2.png"><img width="676" height="407" title="AddModuleProject" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="AddModuleProject" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/AddModuleProject_thumb.png" /></a></p> <p>In the pop up that prompts for creating a server project, uncheck the box for hosting the application.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/NoServerProject_2.png"><img width="593" height="421" title="NoServerProject" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="NoServerProject" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/NoServerProject_thumb.png" /></a></p> <p>After the project is created, delete App.xaml and MainPage.xaml from the new project.</p> <p>Next you will add the server class library where the domain service will live. Add a new Windows Class Library project and call it TaskManager.NotesModule.Services. You can delete Class1.cs from the new class library project as well. You could then add a domain service to that project, possibly using an entity data model defined in a separate class library as discussed earlier. </p> <p>If you open the TaskManager.NotesModule Silverlight project settings at this point, the first thing you will need to do is set the startup object to (not set). That is because this project is not intended to be a standalone Silverlight application, but we are just using the Silverlight Application project type because its build output is to produce a XAP file with the contents of the project.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/ModuleProjectSettings_2.png"><img width="666" height="655" title="ModuleProjectSettings" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="ModuleProjectSettings" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/ModuleProjectSettings_thumb.png" /></a></p> <p>The trick comes when you go to set up the RIA Services link.  If you drop down the WCF RIA Services link setting, you will not see the class library that contains your domain service listed as an option. This is really just a bug in the tooling. That drop down really just sets a relative path to the server project in the client project’s csproj file (or vbproj). Since the tool won’t let you set it correctly, you have to open the csproj file and edit it directly.</p> <p>To do so, right click on the project and select Edit Project File.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/EditProjectFile_2.png"><img width="804" height="540" title="EditProjectFile" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="EditProjectFile" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/EditProjectFile_thumb.png" /></a></p> <p>If that option is not available for you, you can also just open the .csproj in any text editor. The setting you are looking for.is called LinkedServerProject. You need to fill it in with the relative path to the .csproj file of the server project. For example, in my case, the path is:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"></pre> <!--CRLF--></div> </div> <p>After adding this and saving the file and closing it, you can then right click on the project in Solution Explorer and select Reload Project. If you then go look at the project settings again, you will see it is now showing the right server project. If you build, you will get the client generated code in your module project from the linked server project.</p> <h3>Using MEF To Dynamically Load the Module</h3> <p>Now all that is left is to load the module dynamically with MEF. I don’t have room for a full lesson on MEF, but what I am going to use here is MEF’s ability to download a separate XAP file asynchronously and then plug in the parts it finds in that XAP to the application dynamically. For a great overview of this capability, I recommend you check out <a href="http://johnpapa.net/silverlight/silverlight-tv-11-dynamically-loading-xaps-with-mef/" target="_blank">this Silverlight TV Episode with Glenn Block</a>.</p> <p>The first step is to add the MEF System.ComponentModel.Composition reference to the TaskManager.NotesModule project. You can then mark the parts you want to plug in with appropriate <strong>Export</strong> attributes. In this case, I am going to plug in a single <strong>ChildWindow</strong> derived view called <strong>NotesView</strong>. So I add the following <strong>Export</strong> to the code behind of that view:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span class="lnum" id="lnum1"> </span>[Export(<span class="kwrd">typeof</span>(ChildWindow))]</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> </span><span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> NotesView : ChildWindow</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> </span>{</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> </span>}</pre> <!--CRLF--></div> </div> <p>Next, I need to add a little code the main app to download the separate XAP file asynchronously when appropriate. First step is to add references to the TaskManager project to System.ComponentModel.Composition.Initialization and System.ComponentModel.Composition. Then I add the following code to the code behind of the main page:</p> <div id="codeSnippetWrapper"> <div class="csharpcode" id="codeSnippet"> <pre class="alt"><span class="lnum" id="lnum1"> </span>[Import]</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum2"> </span><span class="kwrd">public</span> ChildWindow PlugInPopup { get; set; }</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum3"> </span><span class="kwrd">bool</span> plugInsInitialized = <span class="kwrd">false</span>;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum4"> </span> </pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum5"> </span><span class="kwrd">private</span> <span class="kwrd">void</span> button1_Click(<span class="kwrd">object</span> sender, RoutedEventArgs e)</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum6"> </span>{</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum7"> </span> <span class="kwrd">if</span> (!plugInsInitialized)</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum8"> </span> {</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum9"> </span> plugInsInitialized = <span class="kwrd">true</span>;</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum10"> </span> var deployment = <span class="kwrd">new</span> DeploymentCatalog(<span class="str">"TaskManager.NotesModule.xap"</span>);</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum11"> </span> deployment.DownloadCompleted += (s, e2) =></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum12"> </span> {</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum13"> </span> CompositionInitializer.SatisfyImports(<span class="kwrd">this</span>);</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum14"> </span> ShowPopup();</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum15"> </span> };</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum16"> </span> CompositionHost.Initialize(<span class="kwrd">new</span> DeploymentCatalog(), deployment);</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum17"> </span> deployment.DownloadAsync();</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum18"> </span> }</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum19"> </span> <span class="kwrd">else</span></pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum20"> </span> ShowPopup();</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum21"> </span>}</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum22"> </span> </pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum23"> </span><span class="kwrd">private</span> <span class="kwrd">void</span> ShowPopup()</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum24"> </span>{</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum25"> </span> <span class="kwrd">if</span> (PlugInPopup != <span class="kwrd">null</span>)</pre> <!--CRLF--> <pre class="alteven"><span class="lnum" id="lnum26"> </span> PlugInPopup.Show();</pre> <!--CRLF--> <pre class="alt"><span class="lnum" id="lnum27"> </span>}</pre> <!--CRLF--></div> </div> <p>The <strong>PlugInPopup</strong> property will be populated by MEF after the extra XAP is downloaded. Constructing a <strong>DeploymentCatalog</strong> with a relative path to the XAP file in the host site of this application allows it to download that XAP file asynchronously when told to do so with the <strong>DownloadAsync</strong> call. You can see that the code subscribes to the completed event for that download, and then calls <strong>SatisfyImports</strong> to get the container to do dependency injection on this already existing view. At that point the <strong>PlugInPopup</strong> property gets populated, and is then shown.</p> <p>The last part to making this work is to add the TaskManager.NotesModule project to the host Web site (it does not need a test page) so that it is in the ClientBin directory and can be downloaded.</p> <p>The key point here is the need to manually edit the project file to point to the right server project where your domain services live. Just because Visual Studio doesn’t always let you point to any project in your solution (or outside of the solution for that matter), the only requirement is that the LinkedServerProject have a relative path to a compiled project that contains domain services. So a simple edit of the project file gets you want you want to organize your projects how ever you want, as long as you maintain that one-to-one relationship between client and server projects.</p> <h3>Summary</h3> <p>When it comes to organizing and structuring your solution, you can see that you have good flexibility to start breaking up chunks of functionality on the client and server sides into separate libraries and modules however it makes the most sense for your project. You should think in terms of breaking out vertical slices of functionality, composed of a server library project that contains a domain service or several that are related and all their supporting functionality and definitions on the server side. You will link that to a single client project, typically a Silverlight Class Library project or Silverlight Application project if you are trying to be more modular and download modules separately as separate XAPs. Even though you can have a single server project linked from multiple client projects, it will generally cause problems to do so within the same application because of duplicate definitions. So using client side class libraries that just contain the code generated RIA Services code and then referencing that class library from wherever that functionality is needed within the client application gives you flexibility to compose the client side however you want. Also remember that in WCF RIA Services SP1, the constraint on having one domain service “own” a single entity type is lifted.</p> <p>You can <a href="http://www.silverlightshow.net/Storage/Sources/TaskManagerPart9.zip" target="_blank">download the sample code for this article here</a>.</p> <p><span style="font-size: 18px;">About the Author</span></p> <p>Brian Noyes is Chief Architect of <a href="http://www.idesign.net/">IDesign</a>, a Microsoft Regional Director, and Connected System MVP. He is a frequent top rated speaker at conferences worldwide including Microsoft TechEd, DevConnections, DevTeach, and others. He is the author of <a href="http://www.amazon.com/Developing-Applications-Workflow-Foundation-Training/dp/0321503139/ref=sr_1_1?ie=UTF8&s=books&qid=1289774458&sr=1-1">Developing Applications with Windows Workflow Foundation</a>, <a href="http://www.amazon.com/Smart-Client-Deployment-ClickOnce-Applications/dp/0321197690">Smart Client Deployment with ClickOnce</a>, and <a href="http://www.amazon.com/Data-Binding-Windows-Forms-2-0/dp/032126892X">Data Binding in Windows Forms 2.0</a>. Brian got started programming as a hobby while flying <a href="http://en.wikipedia.org/wiki/Grumman_F-14_Tomcat">F-14 Tomcats</a> in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at <a href="http://briannoyes.net/">http://briannoyes.net/</a> or on twitter @briannoyes.</p> http://www.silverlightshow.net/items/WCF-RIA-Services-Part-9-Structuring-Your-Application.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/WCF-RIA-Services-Part-9-Structuring-Your-Application.aspx#comments http://www.silverlightshow.net/items/WCF-RIA-Services-Part-9-Structuring-Your-Application.aspx Wed, 24 Nov 2010 06:08:00 GMT Caching of, in, and around your Silverlight application (part 1) <p><em><strong>This article is compatible with the latest version of Silverlight.</strong></em></p> <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>Don't miss...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Microsoft-Silverlight-4-Data-and-Services-Cookbook-Interview-with-Co-author-Kevin-Dockx.aspx">Read interview with Kevin Dockx</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/My-XAP-file-is-5-Mb-size-is-that-bad.aspx">My XAP file is 5 Mb size, is that bad?</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/caching.aspx">This series is now available as a fully offline resource: </a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/caching.aspx"><img style="border:0px solid;" alt="Caching of, in, and around your Silverlight application Ebook" src="http://www.silverlightshow.net/Storage/caching_ebook_thumbS.png" usemap="#rade_img_map_1291385581316" /></a><br /> <strong><span style="font-size: 13px;">($0.99)</span></strong></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>This is the first in a 3-part series of articles about caching & Silverlight.</p> <p><a href="http://www.silverlightshow.net/Storage/Sources/SilverlightShowCaching1.zip">You can download the source code here.</a></p> <p>A lot can be written about this subject, and because of that, quite a few misunderstandings about Silverlight and caching exist.</p> <p>Let’s start with a general definition of caching: this is what Wikipedia has to say about this technique: </p> <blockquote> <p>In computer science, a cache is a component that improves performance by transparently storing data such that future requests for that data can be served faster. ... (<a href="http://www.google.com/url?q=http://en.wikipedia.org/wiki/Caching&sa=X&ei=ohXYTIKWEYXtObjDrK8J&ved=0CBQQpAMoAA&usg=AFQjCNE3lYG7YTSX1_7A3mChGeTHEA0YGw">en.wikipedia.org/wiki/Caching</a>)</p> </blockquote> <p>Well, that sure opens up a lot of possible places to cache, in and outside of your Silverlight application. Can you cache the complete Silverlight application? What’s this assembly caching you keep on reading about? How do you go about keeping your data on the client when navigating to different parts of you application, instead of refetching it all the time? Can you leverage the Isolated Storage for caching, and is it possible to persist data in between different application sessions? Is it possible to share cached items between different Silverlight applications? And what about the server-side: can I minimize database hits when launching queries from my Silverlight application?</p> <p>If you’ve ever asked yourself one (or more) of these questions, this article series is for you. As you might notice when seeing them in the same paragraph, these questions are about different ways of caching, and they all apply to different scenarios.</p> <p>In the first part of this series, I’d like to talk about the caching of your Silverlight application itself and Assembly Caching – almost no code is required for this. </p> <h3>XAP Caching</h3> <p>Every Silverlight application consists of one or more XAP files. Smaller applications typically consist of one XAP, but larger applications might benefit from dividing your application into different application modules, compiling into different XAP-files which are loaded on demand. When a user first navigates to a page hosting a Silverlight application, the full XAP has to be downloaded to the client. As an XAP typically contains a bunch of referenced assemblies, your XAML files, compiled code and everything else you’ve included as embedded resources in your Silverlight project, these files have a tendency to get quite big. Therefore, being able to cache these files will reduce the time a user has to wait to access your application.</p> <p>Luckily, this is done by default with the help of your browser cache. Once a Silverlight application has been downloaded to the client, it will automatically be cached in the browsers’ temporary files. The next time a user accesses your Silverlight application, the XAP will be loaded from the browser cache (well, as long as it hasn’t been cleared of course – browser caching is controlled by the client and/or browser, we cannot assume anything in this case) instead of from the server.</p> <p>However, as a developer, this might pose some problems. Imagine the following scenario: a user has opened your Silverlight application, so it’s in the browser cache. In the meantime, you find a bug in your application, solve it, and roll out a new version of your app. Next time that user accesses the hosting web page, you of course want him to get the new version of your application. However, as the previous version is in his browser cache, he will get that version instead of the new one… Luckily, you can control when an XAP should expire (as you can with every file) through IIS.</p> <p>Open up Internet Information Services Manager, and navigate (in Content View) to the website you’re hosting your Silverlight application on. Select the XAP, open up the Features view, select HTTP Response Headers, and click on Set Common Headers in the Actions pane. Choose “Immediately” in the Expire Web Content popup, and close the popup again.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/screen1.png"><img width="773" height="501" title="screen1" style="border:0px; background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px;" alt="screen1" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/screen1_thumb.png" /></a></p> <p>After you’ve done this, a new version of the XAP will be downloaded to the client when he accesses the hosting web page, even if he already has a version of your application in his browser cache.</p> <p>As you can see, you also have the option to let the file expire at regular intervals. This might come in handy in a development/test environment: if you’re running a server which receives a new nightly build of your application so the test team can work on the new version the day after, it might be a good idea to use one of these options to ensure the testers will always test on the latest version. </p> <h3>XAP Caching in an Out of Browser scenario?</h3> <p>If you’re designing an Out of Browser application, you might notice your XAP doesn’t get updated automatically – even if you’ve made sure it’s expired, and a new version should be downloaded. This is because in an Out of Browser scenario, you need to download the new version yourself. This is typically done in the application startup method:</p> <p>private void Application_Startup(object sender, StartupEventArgs e) <br /> { <br />     // OOB new version check <br />     this.CheckAndDownloadUpdateCompleted += (send, args) => <br />         { <br />             if (args.UpdateAvailable) <br />             { <br />                 MessageBox.Show("A new version of the application is downloaded, please restart the application to launch the new version."); <br />             } <br />         }; <br />     this.CheckAndDownloadUpdateAsync();</p> <p>    this.RootVisual = new MainPage(); <br /> }</p> <p>This code will ensure your Out of Browser application is updated as well.</p> <h3>Assembly Caching</h3> <p>In Silverlight 3, a new feature was introduced: assembly caching. A lot of people don’t seem to know what this feature actually does, and therefore hesitate to use it. Assembly caching makes sure external assemblies are not packaged in the XAP file, making the XAP itself significantly smaller. Whenever a user accesses your application, the external assemblies will be downloaded from their respective locations: this can be the Microsoft site, a vendor-specific location (if you’re using a 3<sup>rd</sup> party control library, for example), or even your own central assembly repository. In a default scenario, the assemblies themselves are copied to the ClientBin directory, so they’re always available. </p> <p>You might wonder: what’s there to gain from this? In the end, the assemblies must be downloaded anyway, so the total download size / time is about the same, right? This is where your browser cache comes into play: as with the XAP file itself, the external assemblies are cached by your browser. This means that if the assembly is already in your browser cache, it does not have to be downloaded again. If you combine this knowledge with content expiration, you can now image a scenario where you roll out a new version of your Silverlight application, expire the XAP immediately (so a new version is delivered to the client), but leave the unchanged external assemblies alone, so they don’t expire. Now, when a client navigates to your application, the new version of the XAP will be downloaded, but the external (unchanged) assemblies will come from the browser cache.</p> <p>To enable assembly caching, navigate to the project properties of your Silverlight application, and check Reduce XAP size by using application library caching:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/screen2.png"><img width="558" height="205" title="screen2" style="border:0px; background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px;" alt="screen2" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/screen2_thumb.png" /></a></p> <p>If you rebuild your application, you will notice your ClientBin directory now contains zip-files (one for each external assembly you referenced). For example purposes, I’ve added a reference to System.Windows.Controls.Toolkit to my Silverlight application, resulting in 2 zip files: System.Windows.Controls.Toolkit.zip and System.Windows.Controls.zip (which is used by the Toolkit assembly): </p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/screen3.png"><img width="397" height="487" title="screen3" style="border:0px; background-image: none; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px;" alt="screen3" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/screen3_thumb.png" /></a></p> <p>Needless to say, as far as strategies to reduce your XAP size (and thus: decrease download time) are concerned, this feature should not be overlooked. </p> <p>One final word of notice: this feature cannot be combined with an Out of Browser Silverlight application. </p> <h3>Conclusion</h3> <p>This concludes the first part of this 3-part series on caching, in which we’ve learned about how to leverage and control the browser cache, and how to enable Assembly Caching in your Silverlight application. In the next part, we’ll have a look at using the Isolated Storage to enable various caching scenarios.</p> <p> </p> <h3>About the author</h3> <p>Kevin Dockx lives in Belgium and works at RealDolmen, one of Belgium's biggest ICT companies, where he is a technical specialist/project leader on .NET web applications, mainly Silverlight, and a solution manager for Rich Applications (Silverlight, Windows Phone 7 Series, WPF, Surface). His main focus lies on all things Silverlight, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a Silverlight enthusiast, he's a regular speaker on various national and international events, like Microsoft DevDays in The Netherlands, Microsoft Techdays in Portugal or on BESUG events (the Belgian Silverlight User Group). Next to that, he also authored a best-selling Silverlight book, <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book" target="_blank">Packt Publishing's Silverlight 4 Data and Services Cookbook</a>, together with <a href="http://www.snowball.be/" target="_blank">Gill Cleeren</a>. His blog, which contains various tidbits on Silverlight, .NET, and the occasional rambling, can be found at <a href="http://blog.kevindockx.com/">http://blog.kevindockx.com/</a>.</p> http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application-part-1.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application-part-1.aspx#comments http://www.silverlightshow.net/items/Caching-of-in-and-around-your-Silverlight-application-part-1.aspx Thu, 18 Nov 2010 07:21:00 GMT Paging WCF Ria Services entities in Model-View-ViewModel applications <em><strong>This article is compatible with the latest version of Silverlight.</strong></em> <p style="text-align: justify;">Download <a href="http://www.silverlightshow.net/Storage/Sources/SilverlightPlayground.zip" target="_blank" rel="enclosure">sources</a> & <a href="http://www.silverlightshow.net/shows/Paging-WCF-Ria-Services-entities-in-MVVM-applications.aspx" target="_blank" rel="enclosure">video</a></p> <div style="padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;border: #dddddd 1px solid;"> <h3>More on this topic..</h3> <ul style="list-style-type: circle; margin: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Search.aspx?q=WCF&adv=true&tg=true&ro=0&t=1,2,3,5&r=10&o=1">See more articles on WCF</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Search.aspx?q=MVVM&adv=true&tg=true&ro=0&t=1,2,3&r=10&o=1">See more articles on MVVM</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Search.aspx?q=Andrea+Boschin&adv=true&tg=true&ro=1&t=1,3&r=10&o=1">All articles by Andrea Boschin</a> </li> </ul> </div> <p style="text-align: justify;">There is no doubt that "WCF Ria Services" are a great tool for implementing applications that need to present data from any source. There it is a lot of work spared in creating services and proxies and interacting with the service itself. Personally the thing I love so much is the Validation tools that are very powerful and complete and the capability of sharing code between server and client that make the separation between them something of undistinguishable.</p> <p style="text-align: justify;">Toghether with WCF Ria Services there are a set of components that are not so useful to consume services. Particularly I usually prefer not to use components like DomainDataSource because it brings my queries directly into the Views and it is a very bad thing. Microsoft has spent long time to create similar components - I remember SqlDataSource and LinqDataSource in ASP.NET - but they are targeted for very simple applications that have a short lifecycle. Someone found ways to use the DomainDataSource in MVVM scenarios but my feel is again bad because of its intrinsec slowness and because many thing I have to do are not strongly typed and this opens the way to runtime errors I wouldn't want to deal with.</p> <p style="text-align: justify;">In this article I would want to investigate a possible solution, made with a custom PagedDataSource component specifically created for MVVM applications, and the way it might be useful to page queries.</p> <h3 style="text-align: justify;">Discovering the inside of DataSource controls</h3> <p style="text-align: justify;">If you investigate about the intimate functioning of the DomainDataSource and of some other similar components (e.g. the CollectionViewSource) you will soon meet an interface ICollectionView that is the very inner core of the component. This interface it the source of many of the functions you expect from the DataSource components while it support current record, filtering and sorting. Watching in more detail you will find also another interesting set of interfaces including IEditableCollectionView and IPagedCollectionView. The one I would like to delineate here is the IPagedCollectionView that grants the capability of paging resultsets. Here is the definition of this interface:</p> <div style="text-align: justify;"> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">interface</span> IPagedCollectionView</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span> <span style="color: #008000;">// Events</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span> <span style="color: #0000ff;">event</span> EventHandler<EventArgs> PageChanged;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span> <span style="color: #0000ff;">event</span> EventHandler<PageChangingEventArgs> PageChanging;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum6" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum7" style="color: #606060;"> </span> <span style="color: #008000;">// Methods</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum8" style="color: #606060;"> </span> <span style="color: #0000ff;">bool</span> MoveToFirstPage();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum9" style="color: #606060;"> </span> <span style="color: #0000ff;">bool</span> MoveToLastPage();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum10" style="color: #606060;"> </span> <span style="color: #0000ff;">bool</span> MoveToNextPage();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum11" style="color: #606060;"> </span> <span style="color: #0000ff;">bool</span> MoveToPage(<span style="color: #0000ff;">int</span> pageIndex);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum12" style="color: #606060;"> </span> <span style="color: #0000ff;">bool</span> MoveToPreviousPage();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum13" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum14" style="color: #606060;"> </span> <span style="color: #008000;">// Properties</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum15" style="color: #606060;"> </span> <span style="color: #0000ff;">bool</span> CanChangePage { get; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum16" style="color: #606060;"> </span> <span style="color: #0000ff;">bool</span> IsPageChanging { get; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum17" style="color: #606060;"> </span> <span style="color: #0000ff;">int</span> ItemCount { get; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum18" style="color: #606060;"> </span> <span style="color: #0000ff;">int</span> PageIndex { get; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum19" style="color: #606060;"> </span> <span style="color: #0000ff;">int</span> PageSize { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum20" style="color: #606060;"> </span> <span style="color: #0000ff;">int</span> TotalItemCount { get; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum21" style="color: #606060;"> </span>}</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum22" style="color: #606060;"> </span>  </pre> <!--CRLF--></div> </div> </div> <p style="text-align: justify;">The interface contains a big number of members, but we can shorten them to a bunch of groups; There are a set of methods to perform navigation in the result set, moving the cursor up and down to the pages. We have a property (PageSize) to configure the component and other properties to read the current state, including the current page index, and the number of items in the view. Finally we have a couple of events that notify about the start and end of the page changes.</p> <p style="text-align: justify;">The beautiful of this interface is that controls like DataGrid and DataPager directly understands and interacts with it to perform data pagination. So implementing the inteface is the first step to have a MVVM-targeted PagedDataSource. Then we will can pass the component directly to Data controls and having them work seamless like a normal DataSource control.</p> <h3 style="text-align: justify;">Implementing the PagedDataSource</h3> <p style="text-align: justify;">Before starting to develop the new DataSource it is important to understand what is the expected behavior. First of all, starting from what we do not want, the component will not be used in the XAML. This mean it is not required it implement a base class like Control or ContentControl. As we will see in the following of the article the component will be very lightweight and it will suffice to implement only a little set of interfaces. </p> <p style="text-align: justify;">The preferred usage of our new PagedDataSource is that it is exposed by a property in the ViewModel, and this property binded to the controls that have to show the data. To achieve this result it is important that the DataSource implements IEnumerable and INotifyCollectionChanged. This way we can directly connect the consumer to the data source and having it populated and also having the consumer react to the changes we will make to the data. </p> <p style="text-align: justify;">Finally, due the fact that some properties exposed by the component have to be monitored by the consumer, we have to implement also the INotifyPropertyChanged interface. So, here is how it appear the declaration of the PagedDataSource class:</p> <div style="text-align: justify;"> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> PagedDataSource<T> : IPagedCollectionView, IEnumerable, INotifyCollectionChanged, INotifyPropertyChanged</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span> <span style="color: #0000ff;">where</span> T : Entity</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span> <span style="color: #008000;">// implement class here</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span>}</pre> <!--CRLF--></div> </div> </div> <p style="text-align: justify;">Watching at these few lines there is another thing to say: The component is declared as a Generic type, with a constraint that impose T to be derived from the class Entity. You can understand this constraint if you remember that every WCF Ria Services method returns a IQueryable<T>, where T will be an Entity of the underlying datamodel. What we will expect is to pass a query to the PagedDataSource and having the query "automagically" paged. So, T will be an element we will use often during the implementation to shorten the code required to use the PagedDataSource.</p> <p style="text-align: justify;">The following step is to connect the PagedDataSource to the DomainContext. It is not required a specific type of domain context but simply handle every class deriving from DomainContext so we will can handle every type of data source and not only the Entity Framework. In the constructor we take a reference to the EntitySet<T> that has to be contained in the DomainContext, for future references.</p> <div style="text-align: justify;"> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;">public</span> PagedDataSource(DomainContext context)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.PagedEntitySet = context.EntityContainer.GetEntitySet<T>();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.Context = context;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span>}</pre> <!--CRLF--></div> </div> </div> <p style="text-align: justify;">Once we have initialized it the PagedDataSource it start to follow a precise lifecycle. First of all it loads the first page, according with the specified PageSize and PageIndex, then it notifies the consumer of the data available raising a CollectionChanged event. The consumer now reads the entity instances from the PagedDataSource using the implemetation of IEnumerable<T>. When the ViewModel or a DataPager calls one of the Move methods, the component loads the new page and again notifies the consumer. The lifecycle is really simple but it have its core in the Refresh method that is responsible to load the required page of entities, without loading all the data in the table. Here is the source of the method:</p> <div style="text-align: justify;"> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> Refresh()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.IsPageChanging = <span style="color: #0000ff;">true</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span> <span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">this</span>.OnPageChanging(<span style="color: #0000ff;">this</span>.PageIndex))</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum6" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum7" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.IsPageChanging = <span style="color: #0000ff;">false</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum8" style="color: #606060;"> </span> <span style="color: #0000ff;">return</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum9" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum10" style="color: #606060;"> </span>  </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum11" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.PagedEntitySet.Clear();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum12" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum13" style="color: #606060;"> </span> QueringEventArgs<T> query = <span style="color: #0000ff;">new</span> QueringEventArgs<T>();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum14" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.OnQuering(query);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum15" style="color: #606060;"> </span>  </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum16" style="color: #606060;"> </span> query.Query.IncludeTotalCount = <span style="color: #0000ff;">true</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum17" style="color: #606060;"> </span>  </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum18" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.Context.Load<T>(</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum19" style="color: #606060;"> </span> query.Query</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum20" style="color: #606060;"> </span> .Skip(<span style="color: #0000ff;">this</span>.PageIndex * <span style="color: #0000ff;">this</span>.PageSize)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum21" style="color: #606060;"> </span> .Take(<span style="color: #0000ff;">this</span>.PageSize),</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum22" style="color: #606060;"> </span> LoadBehavior.RefreshCurrent,</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum23" style="color: #606060;"> </span> lo =></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum24" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum25" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.IsPageChanging = <span style="color: #0000ff;">false</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum26" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.ItemCount = <span style="color: #0000ff;">this</span>.TotalItemCount = lo.TotalEntityCount;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum27" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.OnPageChanged();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum28" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.OnCollectionChanged(<span style="color: #0000ff;">new</span> NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum29" style="color: #606060;"> </span> }, <span style="color: #0000ff;">null</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum30" style="color: #606060;"> </span>}</pre> <!--CRLF--></div> </div> </div> <p style="text-align: justify;">Probably it is the most complex method in the component so let me explain it row-by-row; In the first part the method sets the IsPageChanging property (it is part of the IPagedCollectionView interface) to indicate that the change of the page is in progress. Then it raises the PageChanging event giving to the ViewModel the last chance of cancel the change since its EventArgs is cancelable. </p> <p style="text-align: justify;">If the code authorizes the component to perform the page change, the EntitySet into the DomainContext is cleared then the component asks the query to perform with a Quering event. Here it expects that the returned arguments contain an EntityQuery<T> that are the data to which we must apply paging rules. There is a specific reason to ask for the query every time we have to refresh the page. This way it lets the developer to change the parameters to the query. It is useful if we need to filter data on the server and have some parameters acquired by the user interface. We will see an use of this in the following parts of the article.</p> <p style="text-align: justify;">Finally the method append to the query a call to Skip and Take. This is the part that does the trick. Thanks to the capability of serializing queries the call to these methods is passed to the server that apply them to the data just before to send it to the client. If you use Entity Framework the serialized query is applied directly to the generated SQL statement created by EF to extract data. It is really wonderful and astounding. </p> <p style="text-align: justify;">Under this trick there is WCF Data Services that is the REST implementation build over WCF. When you call the Load method the framework translates it to a querystring that describes the query. Here is a catch from the browser:</p> <p style="text-align: justify;"><img width="815" height="96" title="Capture" style="width: 760px; display: block; float: none; height: 82px; margin-left: auto; margin-right: auto;border: 0px solid;" alt="Capture" src="http://www.silverlightshow.net/Storage/Users/AndreaBoschin/__Capture_1.png" /> </p> <p style="text-align: justify;">When the call to the service returns there is a bunch of tasks to accomplish: after setting the IsPageChanging to false we need to read the TotalItemCount and copy it to two properties of IPagedCollectionView and finally raise the PageChanged event and the CollectionChanged event to ask the consumer to update itself. The TotalItemCount is the total number of records we expect without the paging applied. This information is required to calculate the exact number of pages available.</p> <h3 style="text-align: justify;">Model-View-ViewModel aspects</h3> <p style="text-align: justify;">If you know the MVVM pattern you already understand how this class might be useful. We have to expose from the ViewModel a property to which connect the consumer ItemsControl and the DataPager. In my sample I did a step forward and I thought about the fact often you need to have a lot of pages made in the same way just because your application needs to perform CRUD operations to each one. So I created a ListViewModel<T, K> class that include all the logic needed to create a DataGrid + DataPager page:</p> <div style="text-align: justify;"> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">abstract</span> <span style="color: #0000ff;">class</span> ListViewModel<T, K></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span> <span style="color: #0000ff;">where</span> T : Entity</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span> <span style="color: #0000ff;">where</span> K : DomainContext, <span style="color: #0000ff;">new</span>()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum6" style="color: #606060;"> </span> <span style="color: #008000;">/// Gets or sets the context.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum7" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum8" style="color: #606060;"> </span> <span style="color: #008000;">/// <value>The context.</value></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum9" style="color: #606060;"> </span> <span style="color: #0000ff;">protected</span> K Context { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum10" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum11" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum12" style="color: #606060;"> </span> <span style="color: #008000;">/// Gets or sets the items.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum13" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum14" style="color: #606060;"> </span> <span style="color: #008000;">/// <value>The items.</value></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum15" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> PagedDataSource<T> Items { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum16" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum17" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum18" style="color: #606060;"> </span> <span style="color: #008000;">/// Initializes a new instance of the <see cref="ListViewModel&lt;T, K&gt;"/> class.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum19" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum20" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> ListViewModel()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum21" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum22" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.Context = <span style="color: #0000ff;">new</span> K();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum23" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.Items = <span style="color: #0000ff;">new</span> PagedDataSource<T>(<span style="color: #0000ff;">this</span>.Context);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum24" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.Items.Quering += <span style="color: #0000ff;">new</span> EventHandler<QueringEventArgs<T>>(Items_Quering);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum25" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.Items.ItemCreating += <span style="color: #0000ff;">new</span> EventHandler<ItemCreatingEventArgs>(Items_ItemCreating);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum26" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.Items.MoveToFirstPage();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum27" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum28" style="color: #606060;"> </span>  </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum29" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum30" style="color: #606060;"> </span> <span style="color: #008000;">/// Wraps the item.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum31" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum32" style="color: #606060;"> </span> <span style="color: #008000;">/// <param name="item">The item.</param></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum33" style="color: #606060;"> </span> <span style="color: #008000;">/// <returns></returns></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum34" style="color: #606060;"> </span> <span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">abstract</span> <span style="color: #0000ff;">object</span> WrapItem(<span style="color: #0000ff;">object</span> item);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum35" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum36" style="color: #606060;"> </span> <span style="color: #008000;">/// Gets the query.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum37" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum38" style="color: #606060;"> </span> <span style="color: #008000;">/// <returns></returns></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum39" style="color: #606060;"> </span> <span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">abstract</span> EntityQuery<T> GetQuery();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum40" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum41" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum42" style="color: #606060;"> </span> <span style="color: #008000;">/// Handles the ItemCreating event of the Items control.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum43" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum44" style="color: #606060;"> </span> <span style="color: #008000;">/// <param name="sender">The source of the event.</param></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum45" style="color: #606060;"> </span> <span style="color: #008000;">/// <param name="e">The <see cref="SilverlightPlayground.PagingQueries.Data.ItemCreatingEventArgs"/> instance containing the event data.</param></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum46" style="color: #606060;"> </span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> Items_ItemCreating(<span style="color: #0000ff;">object</span> sender, ItemCreatingEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum47" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum48" style="color: #606060;"> </span> e.Item = <span style="color: #0000ff;">this</span>.WrapItem(e.Item);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum49" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum50" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum51" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum52" style="color: #606060;"> </span> <span style="color: #008000;">/// Handles the Quering event of the Items control.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum53" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum54" style="color: #606060;"> </span> <span style="color: #008000;">/// <param name="sender">The source of the event.</param></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum55" style="color: #606060;"> </span> <span style="color: #008000;">/// <param name="e">The <see cref="SilverlightPlayground.PagingQueries.Data.QueringEventArgs&lt;T&gt;"/> instance containing the event data.</param></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum56" style="color: #606060;"> </span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> Items_Quering(<span style="color: #0000ff;">object</span> sender, QueringEventArgs<T> e)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum57" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum58" style="color: #606060;"> </span> e.Query = <span style="color: #0000ff;">this</span>.GetQuery();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum59" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum60" style="color: #606060;"> </span>}</pre> <!--CRLF--></div> </div> </div> <p style="text-align: justify;">The ListViewModel require two type arguments: T is the entity to page and K is the DomainContext to use. Inside this ViewModel I have a property of type PagedDataSource<T> initialized with the type arguments. The instance of the DomainContext is created by this class and saved in the Context property. The class handles the Quering event and pass it to an abstract method. The reason is that the query to execute is the only thing a concrete ViewModel must provide to the PagedDataSource. </p> <p style="text-align: justify;">Curiously there is another event, MVVM related, that we have not already met. It is the ItemCreated evnt that is raised every time an item is prepared by the IEnumerable implementation of the PagedDataSource. This event is useful when you have to bind to a DataGrid and collect from each row some commands (e.g. open, delete, etc...). If you bind to the DataGrid the pure entity there is not any way to handle these events but you need to have a row ViewModel that wraps the entity and exposes the commands. The ItemCreated let you to intercept the item just before it is provided to the DataGrid and let you create the required RowViewModel<T> instance. </p> <p style="text-align: justify;">Here is the final code from the concrete ViewModel of the datagrid page:</p> <div style="text-align: justify;"> <div id="codeSnippetWrapper" style="text-align: left; padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px;border: silver 1px solid;"> <div id="codeSnippet" style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> MainPageViewModel : ListViewModel<Item, TestDomainContext></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span> <span style="color: #008000;">/// Gets or sets the max value.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum6" style="color: #606060;"> </span> <span style="color: #008000;">/// <value>The max value.</value></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum7" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> MaxValue { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum8" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum9" style="color: #606060;"> </span> <span style="color: #008000;">/// Gets or sets the show command.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum10" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum11" style="color: #606060;"> </span> <span style="color: #008000;">/// <value>The show command.</value></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum12" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> DelegateCommand<Item> ShowCommand { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum13" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum14" style="color: #606060;"> </span> <span style="color: #008000;">/// Initializes a new instance of the <see cref="MainPageViewModel"/> class.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum15" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum16" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> MainPageViewModel()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum17" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum18" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.ShowCommand = <span style="color: #0000ff;">new</span> DelegateCommand<Item>(o => <span style="color: #0000ff;">this</span>.Show(o));</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum19" style="color: #606060;"> </span> <span style="color: #0000ff;">this</span>.MaxValue = 10000;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum20" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum21" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum22" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum23" style="color: #606060;"> </span> <span style="color: #008000;">/// Gets the query.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum24" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum25" style="color: #606060;"> </span> <span style="color: #008000;">/// <returns></returns></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum26" style="color: #606060;"> </span> <span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">override</span> EntityQuery<Item> GetQuery()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum27" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum28" style="color: #606060;"> </span> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">this</span>.Context.GetNumbersQuery(1, <span style="color: #0000ff;">this</span>.MaxValue);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum29" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum30" style="color: #606060;"> </span>  </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum31" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum32" style="color: #606060;"> </span> <span style="color: #008000;">/// Wraps the item.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum33" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum34" style="color: #606060;"> </span> <span style="color: #008000;">/// <param name="item">The item.</param></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum35" style="color: #606060;"> </span> <span style="color: #008000;">/// <returns></returns></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum36" style="color: #606060;"> </span> <span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">object</span> WrapItem(<span style="color: #0000ff;">object</span> item)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum37" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum38" style="color: #606060;"> </span> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span> NumberRowViewModel((Item)item, <span style="color: #0000ff;">this</span>.ShowCommand);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum39" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum40" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum41" style="color: #606060;"> </span> <span style="color: #008000;">/// <summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum42" style="color: #606060;"> </span> <span style="color: #008000;">/// Shows the specified item.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum43" style="color: #606060;"> </span> <span style="color: #008000;">/// </summary></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum44" style="color: #606060;"> </span> <span style="color: #008000;">/// <param name="item">The item.</param></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum45" style="color: #606060;"> </span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> Show(Item item)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum46" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum47" style="color: #606060;"> </span> <span style="color: #008000;">// do what you want with the selected item</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum48" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum49" style="color: #606060;"> </span>}</pre> <!--CRLF--></div> </div> </div> <p style="text-align: justify;">The code from the attached sample has been cut to the minimal required to apply paging. </p> <h3 style="text-align: justify;">Future improvements</h3> <p style="text-align: justify;">As you have seen the PagedDataSource is a key component to simplify the development in MVVM scenarios. It grants the capability to easily apply paging and customize the queries. Obviously there are many improvements you can imagine. Since it does not require a Filter event like the CollectionViewSource does, because you apply restrictions directly to the query, it is understandable someone needs to add sorting to the PagedDataSource. I figure out you can do this task in multiple ways, but please remember the better is add another part of the query into the Refresh method and having the sorting execute on the server side on all the records in the repository and not only on the few rows returned. </p> http://www.silverlightshow.net/items/Paging-WCF-Ria-Services-entities-in-Model-View-ViewModel-applications.aspx editorial@silverlightshow.net (Andrea Boschin ) http://www.silverlightshow.net/items/Paging-WCF-Ria-Services-entities-in-Model-View-ViewModel-applications.aspx#comments http://www.silverlightshow.net/items/Paging-WCF-Ria-Services-entities-in-Model-View-ViewModel-applications.aspx Wed, 20 Oct 2010 11:16:00 GMT How to distribute a Silverlight OOB Application? <em><strong>This article is compatible with the latest version of Silverlight.</strong></em> <div><em><strong></strong></em><br /> <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>More on this topic..</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/shows/SilverlightShow-Webinar-Running-Silverlight-Outside-the-Browser-and-with-Elevated-Trust-by-Chris-Anderson.aspx">SilverlightShow OOB Webinar</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Silverlight-4-elevated-permissions.aspx">SL4 elevated permissions article</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Silverlight-3-as-a-Desktop-Application-Out-of-Browser-Applications.aspx">An article on OOB applications</a> </li> </ul> </div> <h3>Table of Contents</h3> <ul> <li>Introduction </li> <li>Background </li> <li>Step1 : Creating a Silverlight OOB Application <ul> <li>Creating a Project </li> <li>Configuring OOB Settings </li> <li>Publishing Application as .XAP </li> </ul> </li> <li>Step2 : Configuring CD-ROM Installation <ul> <li>Basic to Silverlight OOB Installation </li> <li>Basic to Silverlight OOB Silent Installation </li> <li>Basic to HTA File </li> <li>Creating the Folder Structure </li> <li>Configuring Silverlight Runtime Detection </li> <li>Configuring OOB Application Installation </li> <li>Configuring CD-ROM Installation Launch </li> </ul> </li> <li>Step3 : Demo </li> <li>Summary </li> </ul> <h3> </h3> <h3>Introduction</h3> <p>One of the new features introduced in Silverlight 4 is the silent installation of Silverlight Out-of-Browser application. This means, without user intervention, you can directly install them to their machines. You don’t have to open the browser window to install the OOB app. This is perfect for CD-ROM distribution. You can even automate the process from the CD/DVD media; if the user already has permission to auto run external media.</p> <p>Here in this article, I will first create a simple OOB Silverlight application and then show you the steps to install it as OOB application silently.</p> <p> </p> <h3>Step1 : Creating a Silverlight OOB Application</h3> <p>In this first step, we will first create a Silverlight Application and design the UI. As our goal in this article is to deploying the application as OOB, hence we will not focus deeply into the UI. Later we will configure the application for OOB and after the successful build; we will publish the .XAP file to a local folder. If you already know about these steps can skip to the next Step.</p> <h4>Creating a Project</h4> <ol> <li>Open your Visual Studio 2010 IDE </li> <li>Go to File –> New –> Project or just press Ctrl + Shift + N to open the New Project dialog <br /> <img width="500" height="346" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_3.png" /> </li> <li>In the “New Project” dialog Window, expand “Visual C#” and click on the “Silverlight” from the left panel </li> <li>Now in the right panel, only the Silverlight Templates will be visible </li> <li>Select “Silverlight Application” from the right panel </li> <li>Give a proper name for the Project (e.g. SilverlightDistributionDemo) </li> <li>Choose proper location for the Solution by clicking the “Browse” button </li> <li>Click “Ok” to continue. This will open the “New Silverlight Application” dialog where you can choose the Silverlight version and Silverlight Hosting Project settings <br /> <img width="427" height="346" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_125bb809-a0a3-4f5c-8c21-a247b8b9ed8a.png" /> </li> <li>Be sure to select the “Silverlight 4” from the options pane and hit Ok” to continue </li> </ol> <p>This will create the basic Silverlight project for you. Now design your application as per your requirement. For this sample application, I will create a basic UI. Here is the XAML code for that:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"><</span><span style="color: #800000;">UserControl</span> <span style="color: #ff0000;">x:Class</span><span style="color: #0000ff;">="SilverlightDistributionDemo.MainPage"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">xmlns</span><span style="color: #0000ff;">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">xmlns:x</span><span style="color: #0000ff;">="http://schemas.microsoft.com/winfx/2006/xaml"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">xmlns:mc</span><span style="color: #0000ff;">="http://schemas.openxmlformats.org/markup-compatibility/2006"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">Height</span><span style="color: #0000ff;">="300"</span> <span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="400"</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">Grid</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="LayoutRoot"</span> <span style="color: #ff0000;">Background</span><span style="color: #0000ff;">="White"</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">Border</span> <span style="color: #ff0000;">Background</span><span style="color: #0000ff;">="#FFFFA0"</span> <span style="color: #ff0000;">Margin</span><span style="color: #0000ff;">="20"</span> <span style="color: #ff0000;">CornerRadius</span><span style="color: #0000ff;">="15"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">BorderThickness</span><span style="color: #0000ff;">="1"</span> <span style="color: #ff0000;">BorderBrush</span><span style="color: #0000ff;">="Red"</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">="Silverlight OOB Application Installer Demo"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">HorizontalAlignment</span><span style="color: #0000ff;">="Center"</span> <span style="color: #ff0000;">VerticalAlignment</span><span style="color: #0000ff;">="Center"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="30"</span> <span style="color: #ff0000;">FontWeight</span><span style="color: #0000ff;">="Bold"</span> <span style="color: #ff0000;">Foreground</span><span style="color: #0000ff;">="Red"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">TextWrapping</span><span style="color: #0000ff;">="Wrap"</span> <span style="color: #ff0000;">TextAlignment</span><span style="color: #0000ff;">="Center"</span><span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"></</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"></</span><span style="color: #800000;">Grid</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"></</span><span style="color: #800000;">UserControl</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>Here is the output of the Silverlight UI, if you run it in your Browser Window:</p> <p><img width="357" height="346" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_21e79fa7-1807-4c72-b60b-6eeb17e397d8.png" /></p> <h4>Configuring OOB Settings</h4> <p>So, our application UI is ready. Now, we need to configure the application to launch in outside browser window. Hence start with the configuration settings. Follow the simple steps mentioned below and you will be done:</p> <ol> <li>From your solution explorer, right click on the Silverlight project and go to Properties. This will open the following properties pane in your screen: <br /> <br /> <img width="640" height="351" title="image" style="border:0px solid; background-image: none; padding-left: 0px; width: 601px; padding-right: 0px; display: inline; height: 308px; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_dda4cadb-4e3f-4d2b-b3b3-dd9e0ff8c4d7.png" /> </li> <li>Select “Silverlight” from the left panel </li> <li>In the right panel, select the “Enable running application out of the browser” as shown in the above screenshot. This will enable the application to run outside the browser window </li> <li>Now click on the “Out-of-Browser Settings …” button. This will open up another dialog window on your screen <br /> <br /> <img width="374" height="480" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_53197d8d-f817-4725-a68a-4eadc4488c2b.png" /> </li> <li>Give the application Height & Width in this screen. You can also configure running the application in full trusted mode. Also you can configure the Window style here. For this demo, it is not require and hence I am leaving it as it is by default </li> <li>Click “Ok” to save the “Out-of-Browser Settings” </li> <li>Save the properties by clicking File –> Save or just by pressing the Ctrl + S key combination </li> </ol> <p>Now your application is ready for running outside the browser. To check this, press F5 to run the application. This will first build the project and run it inside the browser window and you will see the UI as you created. Right click on the application UI and you will see a context menu popped up in the screen. It has two menu items called “Silverlight” and “Install <Application_Name> onto this computer…”. The second option will only visible if your application supports running as OOB.</p> <p><img width="357" height="345" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_3554af54-1ae6-4f11-9eb5-26cef0c4edeb.png" /></p> <p>Clicking on the Install menu will start the installation wizard. Wait, our mission is not to install like this. We have to install the application silently from the deployment directory silently, without opening the browser window. We will discuss it step-by-step at latter part of the article.</p> <h3>Publishing Application as .XAP</h3> <p>Build the solution. Once you successfully built your solution, go to the “ClientBin” directory present in the Web application project. Here you will see the published XAP file. Copy this file to a specific folder location for later use.</p> <p><img width="302" height="329" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_713047f2-cfbe-4b09-99fd-c0411a678472.png" /></p> <p>Here in this example, we don’t have any other dependent services. Hence, just copying the .xap file is perfect for us. But in case, you have some other dependency files you need to publish the project. To do this, right click on the web application project and click “Publish…” menu to launch the publish web wizard.</p> <p><img width="357" height="303" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_b3fc289e-e745-4341-b1e5-bd1356521c5a.png" /></p> <p>Select the “File System” as the Publish Method and follow the instructions to publish the Silverlight application. Copy the required files from the published folder to a specific location for later use.</p> <p> </p> <h3>Step2 : Configuring CD-ROM Installation</h3> <p>Now it’s time to configure our application deployment from CD-ROM. Everything should be done silently, means it should check whether the required Silverlight version is installed in the installation PC and based on that it should run either the Silverlight installation or directly start deploying the application as out-of-browser. Let’s do it step-by-step.</p> <h4>Basic to Silverlight OOB Installation</h4> <p>Before jumping into the deployment steps, let us discuss how OOB installation works. Silverlight 4 now has support for installing out-of-browser application silently. When you install Silverlight plug-in, it also installs a .exe file named "sllauncher.exe" which you can find in your "Program Files\Microsoft Silverlight\" directory. This EXE file now has the capability to install your Silverlight OOB application silently without opening the browser window. If you have already installed your OOB application, it will create a shortcut to launch the application from desktop or start menu. Right click on the shortcut & go to its properties. You will notice that the target location is set to "Microsoft Silverlight" and the target is set to something similar to the following line:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #006080;">"C:\Program Files\Microsoft Silverlight\sllauncher.exe"</span> 744317312.localhost</pre> <!--CRLF--></div> </div> <p><img width="285" height="402" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_df43470b-1a3e-4aa8-b72d-c8dfdd3951c0.png" /></p> <p>That is responsible for launching the XAP file as your Out-of-Browser application.</p> <h4>Basic to Silverlight OOB Silent Installation</h4> <p>Let's come to write some scripts to install your XAP silently as out of browser Silverlight application. Hope, you already published our sample application (.xap) after configuring it as out of browser to your local drive in a specific folder (say, C:\MySilverlightApps\XAP). For our case, the complete path of the XAP is: "C:\MySilverlightApps\XAP\SilverlightDistributionDemo.xap".</p> <p>Now open your Notepad and write the following code in a single line:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #006080;">"C:\Program Files\Microsoft Silverlight\sllauncher.exe"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> /install:<span style="color: #006080;">"C:\MySilverlightApps\XAP\SilverlightDistributionDemo.xap"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> /origin:http://www.kunal-chowdhury.com/private/apps/XAP/SilverlightDistributionDemo.xap</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> /shortcut:desktop+startmenu</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> /overwrite </pre> <!--CRLF--></div> </div> <p><img width="677" height="138" title="image" style="border:0px solid; background-image: none; padding-left: 0px; width: 627px; padding-right: 0px; display: inline; height: 124px; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_9a2cc222-6c82-4bc0-aae2-fb2fb11c60ff.png" /></p> <p>Here, you have to pass the location of your XAP file as a parameter value to the "/install" flag.</p> <p>You can specify the URL for future update location of the application by setting the "/origin" flag. When you call the CheckAndDownloadUpdateAsync() method from code, it will try to get the update from the specified location.</p> <p>You can specify the shortcut location of the application by setting the value to the "/shortcut" flag. If you just set desktop or start menu as the value to the flag, it will create the shortcut in desktop or start menu depending on the parameter you set. If you use "desktop+startmenu" as the value to the parameter, it will install it both in the desktop and start menu of your operating system.</p> <h4>Basic to HTA File</h4> <p>HTML Applications (HTAs) are full-fledged applications. These applications are fully trusted and display only the menus, icons, toolbars, and title information that the Web developer sets. In short, HTAs pack all the power of Windows Internet Explorer - its object model, performance, rendering power, protocol support and user interface of the browser. HTAs can be created using the normal HTML and Dynamic HTML (DHTML) tags. You need to save the file as “.hta” to execute the Html Application.</p> <p>The HTA:APPLICATION tag in the following example specifies application features not available in DHTML. As prescribed by the attributes, this application has neither border (border), nor title bar (caption), nor standard program icon (sysMenu). The application title appears in the Windows task list but not in the taskbar (showInTaskBar), and only one instance of the application is permitted to run at a time (singleInstance).</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"><</span><span style="color: #800000;">HTML</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"><</span><span style="color: #800000;">HEAD</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">TITLE</span><span style="color: #0000ff;">></span>My Monster Application<span style="color: #0000ff;"></</span><span style="color: #800000;">TITLE</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">HTA:APPLICATION</span> <span style="color: #ff0000;">ID</span><span style="color: #0000ff;">="oMyApp"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">APPLICATIONNAME</span><span style="color: #0000ff;">="monster"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">BORDER</span><span style="color: #0000ff;">="none"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">CAPTION</span><span style="color: #0000ff;">="no"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">ICON</span><span style="color: #0000ff;">="/graphics/creature.ico"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">SHOWINTASKBAR</span><span style="color: #0000ff;">="no"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">SINGLEINSTANCE</span><span style="color: #0000ff;">="yes"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">SYSMENU</span><span style="color: #0000ff;">="no"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">WINDOWSTATE</span><span style="color: #0000ff;">="maximize"</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"></</span><span style="color: #800000;">HEAD</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"></</span><span style="color: #800000;">HTML</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>To launch an HTA, double-click its program icon, run it from the Start menu, open it through a URL, or start it from the command line. After starting, the HTA renders everything within the body tag and displays the value set in the title tag as the window title.</p> <p>Want to read more about HTA file? Read it from MSDN:</p> <ul> <li><a href="http://msdn.microsoft.com/en-us/library/ms536471(v=VS.85).aspx" target="_blank">HTML Applications (HTA)</a> </li> <li><a href="http://msdn.microsoft.com/en-us/library/ms536496(VS.85).aspx" target="_blank">Introduction to HTML Applications</a> </li> </ul> <h4>Creating the Folder Structure</h4> <p>Before going into the depth, we need to finalize our folder structure. Create a root folder and name it properly. Create two folders inside it & name them as “Silverlight” and “XAP” respectively. Download the latest Silverlight runtime installer from Microsoft Site and save it inside the “Silverlight” directory. Put the application XAP that we published earlier into the “XAP” folder.</p> <p><img width="679" height="145" title="image" style="border:0px solid; background-image: none; padding-left: 0px; width: 656px; padding-right: 0px; display: inline; height: 135px; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_bbe6e3c8-8e44-467f-b38a-4fc90d75d245.png" /></p> <p>The other three files shown in the above screen represents one autorun.inf, one batchInstall.cmd and install.hta. We will create those files later in this article and discuss accordingly.</p> <h4>Configuring Silverlight Runtime Detection</h4> <p>Now we have to detect whether the Silverlight version is installed in client PC. It can be done using the JavaScript. You can use the Silverlight.js file which comes with every Silverlight application project. In our case, the whole file is not require and hence I took a little portion from it and modified as per our requirement.</p> <p>First of all, we will create a function and inside it, we will create an ActiveXObject named “AgControl.AgControl”. From this instance of agcontrol, we will be able to know about the installed version of Silverlight. If it throws exception, means that, Silverlight is not installed in local PC. In other case, it will return the current installed version of Silverlight. Be sure to check the version in descending order.</p> <p>Here is the whole code snippet:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">function</span> GetSilverlightVersion() {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// initialize the silverlightVersion to -1.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">var</span> silverlightVersion = -1;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> getSilverlightVersion = <span style="color: #0000ff;">function</span> () {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">try</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// create the ActiveX Object of AgControl.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// This is the core of Silverlight runtime.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">var</span> control = <span style="color: #0000ff;">new</span> ActiveXObject(<span style="color: #006080;">'AgControl.AgControl'</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// will execute if your latest Silverlight version is 4.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (control.IsVersionSupported(<span style="color: #006080;">"4.0"</span>)) {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> silverlightVersion = 4;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// will execute if your latest Silverlight version is 3.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (control.IsVersionSupported(<span style="color: #006080;">"3.0"</span>)) {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> silverlightVersion = 3;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// will execute if your latest Silverlight version is 2.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (control.IsVersionSupported(<span style="color: #006080;">"2.0"</span>)) {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> silverlightVersion = 2;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// if Silverlight version is not supported by your app,</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// set it as 0 (zero).</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">else</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> silverlightVersion = 0;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> control = <span style="color: #0000ff;">null</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">catch</span> (e) {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// if any exception while creating the ActiveX Object,</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// will set the silverlightVersion as -1.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> silverlightVersion = -1;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> alert(<span style="color: #006080;">"Unable to create the ActiveX Object from Browser window."</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// call to the inner function to detect the Silverlight.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> getSilverlightVersion();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// return the version of the Silverlight.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> silverlightVersion;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--></div> </div> <p>Now depending upon your Silverlight version, you can install the require Silverlight version. This thing also you can do using JavaScript. Wait, you can do this using JavaScript, but if you run from browser window, it will not work. To do this, we are using the HTML Application (.hta). For this, create another JavaScript method and create a WScript.Shell instance object from the ActiveXObject and call the Run() method by passing the required parameters. Here is the code for that:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">function</span> InstallSilverlight() {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WshShell = <span style="color: #0000ff;">new</span> ActiveXObject(<span style="color: #006080;">"WScript.Shell"</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WshShell.Run(<span style="color: #006080;">"Silverlight\\Silverlight.exe /q"</span>, 0, <span style="color: #0000ff;">true</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--></div> </div> <p>You can see that, in the Run() method I passed the location of the Silverlight runtime installer as the first parameter. You can see that, I used “/q” as the argument for Silverlight installer. This silently installs the Silverlight in the local PC. As a second parameter I used “0” (zero). This ensures that, the executed application window will remain hidden. So, the end user will not see the installation window. The third parameter ensures whether the call will wait for the application to exit. If you pass “true”, it will wait until the executed application exits in memory. Once that application closes, it will continue running the next line of the script.</p> <p>As per our requirement, we need to wait until the Silverlight runtime installs in the user’s machine and hence we used “true” as the third parameter.</p> <h4>Configuring OOB Application Installation</h4> <p>Now, we will create a batch file to execute the XAP installation silently. Open your notepad and write the following code inside it:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;">@ECHO OFF</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;">@<span style="color: #006080;">"%ProgramFiles%\Microsoft Silverlight\sllauncher.exe"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> /install:<span style="color: #006080;">"XAP\SilverlightDistributionDemo.xap"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> /shortcut:desktop+startmenu </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> /origin:http://www.kunal-chowdhury.com/Private/XAP/SilverlightDistributionDemo.xap </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> /overwrite</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;">@EXIT</pre> <!--CRLF--></div> </div> <p>The first line <a href="mailto:%E2%80%9C@ECHO">“@ECHO</a> OFF” will hide the prompt of the console while executing. The second line in the above code is a bunch of 5 lines. You must need to write them in a single line. Due to proper formatting of the code snippet and help you to understand it properly, I splitted them in 5 lines. While writing in the notepad, be sure to write those 5 lines in a single line entry. In the second line, you need to call the sllauncher.exe, which comes with the Silverlight runtime. sllauncher.exe is responsible to install/execute a silverlight OOB application. See the parameters that I used there. The first parameter “/install” tells the application to install the .XAP file from the specified location. The second parameter tells the application to install the shortcut of the OOB application in either desktop, startmenu or both places. The third parameter tells to check for updated version in the sepecified link. The forth parameter instructs to overwrite the existing .xap (if any, already installed). In the third line <a href="mailto:%E2%80%9C@EXIT">“@EXIT</a>” calls the exit method of the batch file to shutdown the batch processing.</p> <p>Once you write the above code in notepad, save it as a .cmd file. Give a proper name while saving (in our case, it is “batchInstall.cmd". Save in proper location, as mentioned in the folder structure.</p> <p>Now, you need to call this batch file from the HTML application file. Write another JavaScript function and call the Run() method of the WScript.Shell object with the proper parameters. In this case, we will use “false” as the third parameter as we don’t need to wait for the installer to install the OOB application.</p> <p>Here is the full JavaScript code for you:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">function</span> InstallSilverlight() {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WshShell = <span style="color: #0000ff;">new</span> ActiveXObject(<span style="color: #006080;">"WScript.Shell"</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WshShell.Run(<span style="color: #006080;">"Silverlight\\Silverlight.exe"</span>, 0, <span style="color: #0000ff;">true</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">function</span> InstallOOBApplication() {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WshShell = <span style="color: #0000ff;">new</span> ActiveXObject(<span style="color: #006080;">"WScript.Shell"</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WshShell.Run(<span style="color: #006080;">"batchInstall.cmd"</span>, 0, <span style="color: #0000ff;">false</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">function</span> Install() {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">var</span> silverlightVersion = GetSilverlightVersion();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span>(silverlightVersion == 4) {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> InstallOOBApplication();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">else</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> InstallSilverlight();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> InstallOOBApplication();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> self.opener = <span style="color: #0000ff;">this</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> self.close();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--></div> </div> <p>In the above code, we created another JavaScript method named “Install()”, which actually checks the current installed version of Silverlight. If the required version is available in user’s PC, it will start installing the OOB Application. If the Silverlight or required version is not present, it will start installing the Silverlight first. As we instruct the Run() method to wait for the installation, the OOB Application installation will start once the Silverlight installation completes. Finally terminate the HTA application from the memory.</p> <p>Now last part in this is to call the Install() method on page load. Use the following code for that:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"><</span><span style="color: #800000;">body</span> <span style="color: #ff0000;">onload</span><span style="color: #0000ff;">="Install();"</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"></</span><span style="color: #800000;">body</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>Now save all this JavaScript code in a .hta file. Here is the full code inside your .HTA file:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><html></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><head></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <title>Application Executer</title></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <HTA:APPLICATION ID=<span style="color: #006080;">"oMyApp"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> APPLICATIONNAME=<span style="color: #006080;">"Application Executer"</span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> BORDER=<span style="color: #006080;">"No"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> CAPTION=<span style="color: #006080;">"No"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> SHOWINTASKBAR=<span style="color: #006080;">"No"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> SINGLEINSTANCE=<span style="color: #006080;">"Yes"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> SYSMENU=<span style="color: #006080;">"No"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> SCROLL=<span style="color: #006080;">"No"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> Width=<span style="color: #006080;">"0"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> Height=<span style="color: #006080;">"0"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> maximizeButton=<span style="color: #006080;">"false"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WINDOWSTATE=<span style="color: #006080;">"minimize"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <script type=<span style="color: #006080;">"text/javascript"</span> language=<span style="color: #006080;">"javascript"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #cc6633;">function</span> GetSilverlightVersion() {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// initialize the silverlightVersion to -1.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> var silverlightVersion = -1;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> getSilverlightVersion = <span style="color: #cc6633;">function</span> () {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">try</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// create the ActiveX Object of AgControl.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// This is the core of Silverlight runtime.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> var control = <span style="color: #0000ff;">new</span> ActiveXObject(<span style="color: #006080;">'AgControl.AgControl'</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// will execute if your latest Silverlight version is 4.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> (control.IsVersionSupported(<span style="color: #006080;">"4.0"</span>)) {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> silverlightVersion = 4;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// will execute if your latest Silverlight version is 3.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (control.IsVersionSupported(<span style="color: #006080;">"3.0"</span>)) {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> silverlightVersion = 3;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// will execute if your latest Silverlight version is 2.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (control.IsVersionSupported(<span style="color: #006080;">"2.0"</span>)) {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> silverlightVersion = 2;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// if Silverlight version is not supported by your app,</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// set it as 0 (zero).</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">else</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> silverlightVersion = 0;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> control = null;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">catch</span> (e) {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// if any exception while creating the ActiveX Object,</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// will set the silverlightVersion as -1.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> silverlightVersion = -1;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> alert(<span style="color: #006080;">"Unable to create the ActiveX Object from Browser window."</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// call to the inner function to detect the Silverlight.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> getSilverlightVersion();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #008000;">// return the version of the Silverlight.</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> silverlightVersion;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #cc6633;">function</span> InstallSilverlight() {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WshShell = <span style="color: #0000ff;">new</span> ActiveXObject(<span style="color: #006080;">"WScript.Shell"</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WshShell.Run(<span style="color: #006080;">"Silverlight\\Silverlight.exe /q"</span>, 0, true);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #cc6633;">function</span> InstallOOBApplication() {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WshShell = <span style="color: #0000ff;">new</span> ActiveXObject(<span style="color: #006080;">"WScript.Shell"</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> WshShell.Run(<span style="color: #006080;">"batchInstall.cmd"</span>, 0, false);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #cc6633;">function</span> Install() {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> var silverlightVersion = GetSilverlightVersion();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span>(silverlightVersion == 4) {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> InstallOOBApplication();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">else</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> InstallSilverlight();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> InstallOOBApplication();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> self.opener = <span style="color: #0000ff;">this</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> self.close();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </script></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"></head></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><body onload=<span style="color: #006080;">"Install();"</span>></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"></body></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"></html></pre> <!--CRLF--></div> </div> <p>Save the file in your root directory where batchInstall.cmd is present. Make sure that your file structure is proper.</p> <h4>Configuring CD-ROM Installation Launch</h4> <p>It’s time for us to run the installer automatically once you insert the CD/DVD installation drive or double click the drive to open. To do this, you have to add a “autorun.inf” file in the root directory where the .hta & .cmd batch files are present (see the folder structure above). Be sure that, the installer will automatically launch, if the end user has enabled the autorun functionality. By default it is enabled.</p> <p>Write the following code in your “autorun.inf” file:</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;">[autorun]</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;">open = install.hta</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;">shell\install = &Install</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;">shell\install\command = install.hta</pre> <!--CRLF--></div> </div> <p>The first line will tell the OS to autorun the file. The second line instructs the OS to autorun the mentioned file from the mentioned location. The third line will add a “Install” menu item in the context menu of the drive when you insert the CD media. It will have the installer file location, which is mentioned in the fourth line.</p> <p>Read more about Autorun.inf file and it’s options from here: <a href="http://autorun.moonvalley.com/autoruninf.htm" target="_blank">Autorun.inf, What is it?</a></p> <p> </p> <h3>Step3 : Demo</h3> <p>It is very difficult to demo it here. To test it, uninstall your Silverlight plug-in from your PC. Then run the install.hta file from the folder as shown in the below diagram:</p> <p><img width="643" height="149" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_726ed3d6-e02f-4bea-a39b-81d9cf87fa03.png" /></p> <p>This will call the “Install()” method of the JavaScript and check for the installed Silverlight version. As it didn’t find the Silverlight installed there, will start installing the Silverlight runtime silently. Once installed successfully, it will start installing the OOB Application silently. No UI will be visible for the user to interact with (this was our requirement). Once the installer installs the OOB application, you will see the OOB icon immediately in your desktop & start menu.</p> <p><img width="195" height="161" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_32068d80-f6a9-4447-b3ca-b6668bfea05c.png" />  <img width="357" height="188" title="image" style="border:0px solid; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_ab7678d1-20fb-46fb-bf1c-54a0bd559451.png" /></p> <p>Double click it to run the application from desktop or click to execute from start menu.</p> <p>Now, again run the “install.hta” file. It will call the JavaScript method “Install()”. The function will check whether the required Silverlight version installed in user PC & as the required version matches the original installed version, it will skip to the OOB application installation part. It will overwrite the existing XAP if it is already present.</p> <p> </p> <h3>Summary</h3> <p>I hope, you got the basic idea of the installation process from it. I used HTA file to demonstrate it in better way. It will be easy for you to read the JavaScript code and understand it properly. The next step for you is to create an original installer file by using the concept mentioned here.</p> <p>If you like this article, please vote for it. Appreciate you for your feedbacks/comments/suggestions. Thank you for reading the article.</p> <p> </p> <h3>Download</h3> <p>- <a href="http://www.silverlightshow.net/Storage/Sources/SL_OOB_App.zip" target="_blank">Silverlight OOB Application Installer (Source Code)</a></p> <p> </p> <h3>About the Author</h3> <table width="646" style="width: 646px; height: 198px;" border="0" cellspacing="2" cellpadding="2"> <tbody> <tr> <td valign="top" style="width: 85px;"><img width="100" height="118" title="image" style="border:0px; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" alt="image" src="http://www.silverlightshow.net/Storage/Users/kunal2383/image_428530bc-e2e2-40a9-9874-3fc57f78c0e1.png" /></td> <td valign="top" style="width: 731px;">Kunal Chowdhury is a Microsoft MVP in Silverlight,. He has a very good skill over Silverlight, XAML & C#. He worked in various Silverlight & WPF projects including Windows 7 Multitouch applications and delivered a quality output every time. He received various awards related to Software Development. <br /> <br /> During his pass time, he always busy to answer in online forums, writing articles and blog postings to share his knowledge across the world. <br /> <br /> You can reach him in his Blog - <a href="http://www.kunal-chowdhury.com/" target="_blank">http://www.kunal-chowdhury.com/</a> <br /> He also Tweets. Follow him in Twitter - <a href="http://twitter.com/kunal2383" target="_blank">@kunal2383</a></td> </tr> </tbody> </table> </div> http://www.silverlightshow.net/items/How-to-distribute-a-Silverlight-OOB-Application.aspx editorial@silverlightshow.net (Kunal Chowdhury ) http://www.silverlightshow.net/items/How-to-distribute-a-Silverlight-OOB-Application.aspx#comments http://www.silverlightshow.net/items/How-to-distribute-a-Silverlight-OOB-Application.aspx Tue, 12 Oct 2010 00:00:00 GMT WCF RIA Services Part 4 - Integrating with the Model-View-ViewModel Pattern <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; padding-top: 5px;"><strong><img alt="" width="128" height="97" style="width: 112px; float: right; height: 80px; margin-left: 10px;" src="http://www.silverlightshow.net/Storage/old_skool_cassette.png" />Watch recordings of Brian's WCF RIA Services webinars:</strong>   <ul> <li><a href="http://www.silverlightshow.net/shows/WCF-RIA-Services-Webinar-1.aspx">Querying & Updating Data From Silverlight Clients with WCF RIA Services</a> (Feb 03, 2011)</li> <li><a href="http://www.silverlightshow.net/shows/WCF-RIA-Services-Webinar-2.aspx">WCF RIA Services Validation</a> (Mar 17, 2011)</li> <li><a href="http://www.silverlightshow.net/shows/WCF-RIA-Services-Webinar-3.aspx">Secure and Personalize Your Silverlight App with WCF RIA Services</a> (May 26, 2011)</li> <li><a href="http://www.silverlightshow.net/shows/WCF-RIA-Services-Webinar-4.aspx">WCF RIA POCO Domain Services</a> (Sep 29, 2011)</li> </ul> </div> <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>Don't miss...</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Deep-dive-into-WCF-part-1-TDD.aspx">Deep Dive Into WCF series</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Search.aspx?q=WCF&adv=true&tg=true&ro=0&t=1,2,3,5&r=10&o=1">See more articles on WCF</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/shows/Paging-WCF-Ria-Services-entities-in-MVVM-applications.aspx">WCF RIA Services Show</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_services.aspx">The WCF series is now available as a fully offline resource: </a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_services.aspx"><img style="border:0px solid;" alt="WCF RIA Services Ebook" src="http://www.silverlightshow.net/Storage/wcf_ria_ebook_thumb0.png" usemap="#rade_img_map_1291385581316" /></a></p> <p style="font-size: 12px;">     <a href="http://www.silverlightshow.net/ebooks.aspx">All SilverlightShow Ebooks</a> <img alt="" src="http://www.silverlightshow.net/Storage/arrow-content.jpg" /></p> </div> <p>This article is Part 4 of the series WCF RIA Services.</p> <h3>Introduction</h3> <p>The Model-View-ViewModel pattern (MVVM) is a very popular approach for building more loosely coupled Silverlight and WPF applications. I won’t attempt to full define and explain the pattern here, but will give a quick explanation of what it is about and why you would want to use it. At a high level, MVVM is an alternative or evolution of MVC and MVP patterns, but taking full advantage of the rich data binding, commands, and behaviors that we have available to us in Silverlight and WPF. The view model’s primary responsibility is to offer up state to the view in the way the view wants to see it. It exposes properties that the view can easily bind to that let the view display the data it needs and to also hook up commands and behaviors that point back to the view model to invoke interaction logic that the view model encapsulates. The view model is all about containing and manipulating the data that the view needs and providing the interaction logic to support the view. The view model acts as a translator from the complex world of the overall application model to the specific set of data that a single view needs, structured in the way the view needs to display it. Structurally, you typically set the view’s DataContext equal to an instance of the view model so that the view can easily bind to the exposed properties of the view model. There are many ways to get this hook up done.</p> <p>The motivations for using it include the fact that it allows you to work on the view and the view model mostly in isolation, facilitating developer/designer workflow. Additionally, by separating your interaction logic into the view model, you can more easily unit test that logic because it is not tightly woven with the UI itself. And finally, the pattern just provides a clean separation of responsibility so the view can just be about the structure and visual behavior of what you see on the screen, and the view model can just be about the data and logic surrounding the data that the view needs to support it. For more in depth coverage, I recommend you read Josh Smith’s excellent <a href="http://msdn.microsoft.com/en-us/magazine/dd419663.aspx" target="_blank">article on MVVM</a>, as well as the guidance being developed by the Microsoft patterns & practices Prism team in Prism 4 at <a href="http://prism.codeplex.com/">http://prism.codeplex.com/</a>. Prism 4 is due out in the September/October timeframe but there are already public drops in the downloads section on CodePlex.</p> <p>So now let’s see how MVVM fits with WCF RIA Services. The starting point code for this article will be the sample code from Part 3 of the series, which <a href="http://www.silverlightshow.net/Storage/Sources/TaskManagerPart3.zip" target="_blank">you can download here</a>. You can download the <a href="http://www.silverlightshow.net/Storage/Sources/TaskManagerPart4.zip" target="_blank">finished code for this article here</a>.</p> <h3>Step 1: Factor out a view model</h3> <p>In the <a href="http://www.silverlightshow.net/items/WCF-RIA-Services-Part-3-Updating-Data.aspx" target="_blank">last article</a>’s version of the TaskManager application, I was already starting to have a fair amount of code building up in the code behind of the view (the <strong>MainPage</strong> user control), even with such a simple application. The first step is to factor that code out into a view model. Create a new class named <strong>TasksViewModel</strong> in the project. Often a good way to get started defining your view model is to analyze the view and determine what properties would be needed to support it. The image below shows the form as it is currently defined. To clean things up a bit, I’ve replaced the two <strong>TextBoxes</strong> for date input at the top with <strong>DatePickers</strong>, removed the unused properties on the Task from the <strong>DataGrid</strong>, and reordered the columns to look a little better.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/brian.noyes/figure1_2.png"><img width="763" height="153" title="figure1" style="border:0px solid; display: inline;" alt="figure1" src="http://www.silverlightshow.net/Storage/Users/brian.noyes/figure1_thumb.png" /></a> </p> <p>By looking at the UI design, you can identify 6 properties the view model should expose to support this view: two <strong>DateTime</strong> properties for lower and upper dates for a search; three commands to support searching by date, adding a task, and saving changes; and one Tasks collection. In its simplest form, that would look like this:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> TasksViewModel</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> DateTime LowerSearchDate { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> DateTime UpperSearchDate { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> ICommand SearchByDateCommand { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum6" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> ICommand AddTaskCommand { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum7" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> ICommand SaveChangesCommand { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum8" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> IEnumerable<Task> Tasks { get; set; }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum9" style="color: #606060;"> </span>}</pre> <!--CRLF--></div> </div> <p>However, you generally need to implement <strong>INotifyPropertyChanged</strong> on your view model which requires the expanded syntax for each property so that the UI can stay fresh through its data bindings if the bound property on the view model changes, so each property definition should look more like this in its full form, except possibly the private set properties that the view model sets once and does not change.</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> TasksViewModel : INotifyPropertyChanged</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">event</span> PropertyChangedEventHandler PropertyChanged = <span style="color: #0000ff;">delegate</span> { };</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span> DateTime _LowerSearchDate;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> DateTime LowerSearchDate</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum6" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum7" style="color: #606060;"> </span> get</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum8" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum9" style="color: #606060;"> </span> <span style="color: #0000ff;">return</span> _LowerSearchDate;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum10" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum11" style="color: #606060;"> </span> set</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum12" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum13" style="color: #606060;"> </span> <span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">value</span> != _LowerSearchDate)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum14" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum15" style="color: #606060;"> </span> _LowerSearchDate = <span style="color: #0000ff;">value</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum16" style="color: #606060;"> </span> PropertyChanged(<span style="color: #0000ff;">this</span>, <span style="color: #0000ff;">new</span> PropertyChangedEventArgs(<span style="color: #006080;">"LowerSearchDate"</span>));</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum17" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum18" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum19" style="color: #606060;"> </span> }</pre> <!--CRLF--></div> </div> <p>To support the <strong>ICommand</strong> properties, you will need a decent command implementation. I’ve included a simple <strong>RelayCommand</strong> implementation, but normally in real projects I use the <strong>DelegateCommand</strong> from Prism. </p> <p>A view model is all about managing the data needed by a view, and a <strong>DomainContext</strong> in RIA Services is all about providing and tracking changes to the data, so a simple approach to using RIA Services with MVVM is to simply use a <strong>DomainContext</strong> within your view model.</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span>TasksDomainContext _Context = <span style="color: #0000ff;">new</span> TasksDomainContext();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span><span style="color: #0000ff;">public</span> TasksViewModel()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span> SearchByDateCommand = <span style="color: #0000ff;">new</span> RelayCommand<<span style="color: #0000ff;">object</span>>(OnSearchByDate);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum6" style="color: #606060;"> </span> AddTaskCommand = <span style="color: #0000ff;">new</span> RelayCommand<<span style="color: #0000ff;">object</span>>(OnAddTask);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum7" style="color: #606060;"> </span> SaveChangesCommand = <span style="color: #0000ff;">new</span> RelayCommand<<span style="color: #0000ff;">object</span>>(OnSaveChanges);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum8" style="color: #606060;"> </span> Tasks = _Context.Tasks;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum9" style="color: #606060;"> </span> <span style="color: #0000ff;">if</span> (!DesignerProperties.IsInDesignTool)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum10" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum11" style="color: #606060;"> </span> _Context.Load(_Context.GetTasksQuery());</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum12" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum13" style="color: #606060;"> </span>}</pre> <!--CRLF--></div> </div> <p>Here I have made the <strong>TasksDomainContext</strong> a member of the view model, and initialized the commands in the constructor to point to methods within the view model. The Tasks property exposed by the view model just holds a reference to the Tasks entity collection exposed by the domain context, which will raise <strong>INotifyCollectionChanged</strong> events to keep the view fresh when the collection changes, which will happen on the initial load, when you add Tasks, and when <strong>SubmitChanges</strong> completes and has updated entities from the back end. Notice the use of the <strong>DesignerProperties.IsInDesignTool</strong> property to prevent calling Load in the designer, which would break it.</p> <p>Next is to move the methods that were in the code behind of <strong>MainPage</strong> into the view model. I’ve cleaned them up a bit in the process too. Note that the search method now leverages the deferred execution I talked about in Part 3, making the <strong>GetTasksByStartDate</strong> domain service method unnecessary since the client can specify that search expression itself. I’ve also moved the creation of a new Task into a simple popup <strong>ChildWindow</strong> so you can actually edit the values. Note the commend in the code below – showing a dialog from a view model is really a no-no, just doing it here because the focus is on RIA Services, not on full MVVM patterns. </p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> OnSearchByDate(<span style="color: #0000ff;">object</span> param)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span> _Context.Tasks.Clear();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span> EntityQuery<Task> query = _Context.GetTasksQuery();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span> LoadOperation<Task> loadOp = _Context.Load(query.Where(t => t.StartDate >= LowerSearchDate && t.StartDate <= UpperSearchDate));</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum6" style="color: #606060;"> </span>}</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum7" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum8" style="color: #606060;"> </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> OnAddTask(<span style="color: #0000ff;">object</span> param)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum9" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum10" style="color: #606060;"> </span> <span style="color: #008000;">// Generally don't want to do this for testability reasons</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum11" style="color: #606060;"> </span> <span style="color: #008000;">// Simplification because MVVM structuring is not the focus here</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum12" style="color: #606060;"> </span> <span style="color: #008000;">// See Prism 4 MVVM RI for a cleaner way to do this</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum13" style="color: #606060;"> </span> AddTaskView popup = <span style="color: #0000ff;">new</span> AddTaskView();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum14" style="color: #606060;"> </span> popup.DataContext = <span style="color: #0000ff;">new</span> Task();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum15" style="color: #606060;"> </span> popup.Closed += <span style="color: #0000ff;">delegate</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum16" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum17" style="color: #606060;"> </span> <span style="color: #0000ff;">if</span> (popup.DialogResult == <span style="color: #0000ff;">true</span>)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum18" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum19" style="color: #606060;"> </span> Task newTask = popup.DataContext <span style="color: #0000ff;">as</span> Task;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum20" style="color: #606060;"> </span> <span style="color: #0000ff;">if</span> (newTask != <span style="color: #0000ff;">null</span>) _Context.Tasks.Add(newTask);</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum21" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum22" style="color: #606060;"> </span> };</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum23" style="color: #606060;"> </span> popup.Show();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum24" style="color: #606060;"> </span>}</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum25" style="color: #606060;"> </span> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum26" style="color: #606060;"> </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> OnSaveChanges(<span style="color: #0000ff;">object</span> param)</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum27" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum28" style="color: #606060;"> </span> _Context.SubmitChanges();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum29" style="color: #606060;"> </span>}</pre> <!--CRLF--></div> </div> <p>At this point you have you have a functioning view model, now I’ll clean up the view to work with the view model.</p> <h3>Step 2: Hook up the view to the view model</h3> <p>From Part 1, the view was using the <strong>DomainDataSource</strong> that was generated from the drag and drop. If you want a clean MVVM design, you will unfortunately have to pass on using <strong>DomainDataSource</strong>. That object is effectively putting state management and query logic into the XAML itself, which violates the clean separation of responsibilities followed in MVVM.</p> <p>So basically I took the existing view, deleted out the <strong>DomainDataSource</strong>, and added appropriate bindings to each of the controls to bind to the exposed view model properties as shown below. For a top level view like this, constructing the view model in the XAML to set it as the data context is a simple way to get the view’s data context set to an instance of the view.</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;"><</span><span style="color: #800000;">UserControl</span> <span style="color: #ff0000;">x:Class</span><span style="color: #0000ff;">="TaskManager.MainPage"</span> ...<span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span> <span style="color: #0000ff;"><</span><span style="color: #800000;">UserControl.DataContext</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span> <span style="color: #0000ff;"><</span><span style="color: #800000;">local:TasksViewModel</span><span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span> <span style="color: #0000ff;"></</span><span style="color: #800000;">UserControl.DataContext</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Grid</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="LayoutRoot"</span> <span style="color: #ff0000;">Background</span><span style="color: #0000ff;">="White"</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum6" style="color: #606060;"> </span> <span style="color: #0000ff;"><</span><span style="color: #800000;">sdk:DataGrid</span> <span style="color: #ff0000;">ItemsSource</span><span style="color: #0000ff;">="{Binding Tasks}"</span> ...<span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum7" style="color: #606060;"> </span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Button</span> <span style="color: #ff0000;">Command</span><span style="color: #0000ff;">="{Binding SearchByDateCommand}"</span> ...<span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum8" style="color: #606060;"> </span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Button</span> <span style="color: #ff0000;">Command</span><span style="color: #0000ff;">="{Binding AddTaskCommand}"</span> ... <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum9" style="color: #606060;"> </span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Button</span> <span style="color: #ff0000;">Command</span><span style="color: #0000ff;">="{Binding SaveChangesCommand}"</span> ... <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum10" style="color: #606060;"> </span> <span style="color: #0000ff;"><</span><span style="color: #800000;">sdk:DatePicker</span> <span style="color: #ff0000;">SelectedDate</span><span style="color: #0000ff;">="{Binding LowerSearchDate}"</span> ... <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum11" style="color: #606060;"> </span> <span style="color: #0000ff;"><</span><span style="color: #800000;">sdk:DatePicker</span> <span style="color: #ff0000;">SelectedDate</span><span style="color: #0000ff;">="{Binding UpperSearchDate}"</span> ... <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum12" style="color: #606060;"> </span> <span style="color: #0000ff;"></</span><span style="color: #800000;">Grid</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum13" style="color: #606060;"> </span><span style="color: #0000ff;"></</span><span style="color: #800000;">UserControl</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>Lastly, remove all the code from the code behind of the view, since it is no longer being used (all the button click handlers were removed in the process of hooking of the commands with bindings to the view model properties).</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum1" style="color: #606060;"> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">partial</span> <span style="color: #0000ff;">class</span> MainPage : UserControl</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum2" style="color: #606060;"> </span>{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum3" style="color: #606060;"> </span> <span style="color: #0000ff;">public</span> MainPage()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum4" style="color: #606060;"> </span> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum5" style="color: #606060;"> </span> InitializeComponent();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum6" style="color: #606060;"> </span> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span id="lnum7" style="color: #606060;"> </span>}</pre> <!--CRLF--></div> </div> <h3>Summary</h3> <p>The simplest way to use WCF RIA Services with the MVVM pattern is to stop using the <strong>DomainDataSource</strong> in your views and to use a domain context as the repository of data for your view models. You can still leverage the drag and drop Data Sources window features, you just have to do a little clean up to delete off the <strong>DomainDataSource</strong> after the drop and touch up the bindings a little. </p> <p>There are two downsides to the approach as I have shown it here: testability and separation of concerns. One of the benefits of the MVVM pattern is supposed to be unit testability. But with a concrete type dependency on the domain context type in your view model, you are out of luck for mocking out that dependency. There are two approaches possible to address this:</p> <ol> <li>Use dependency injection to provide the domain context to the view model, and create a mock <strong>DomainClient</strong> and pass it to the <strong>DomainContext</strong>. This allows your view model to keep using the full functionality of the <strong>DomainContext</strong>, but you are able to mock out the calls to the service underneath the <strong>DomainContext</strong>. This approach is outlined <a href="http://www.nikhilk.net/NET-RIA-Services-ViewModel-Pattern-2.aspx" target="_blank">in this post</a>. I’ll be providing an example in Part 8 of this series, which is focused on testability. </li> <li>Factor out the <strong>DomainContext</strong> to a repository service that defines an interface similar to the <strong>DomainContext</strong> API and consume that from the view model. This would allow you to mock your repository service that contains the domain context. It would also address the separation of concerns problem, because then you would be separating the implementation choice of using RIA Services from the view model, which should really be separated. However, you would give up a lot of flexibility in the view model and it would not be an easy repository implementation. </li> </ol> <p>Neither of these approaches is particularly easy. I’ll cover them in more detail later in part 8, and may blog some more on this topic as well. That’s all for now. You can download the finished code <a href="http://www.silverlightshow.net/Storage/Sources/TaskManagerPart4.zip" target="_blank">for this article here</a>. See you next time.</p> <p><span style="font-size: 18px;">About the Author</span></p> <p>Brian Noyes is Chief Architect of IDesign, a Microsoft Regional Director, and Connected System MVP. He is a frequent top rated speaker at conferences worldwide including Microsoft TechEd, DevConnections, DevTeach, and others. He is the author of Developing Applications with Windows Workflow Foundation, Smart Client Deployment with ClickOnce, and Data Binding in Windows Forms 2.0. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at http://briannoyes.net.</p> http://www.silverlightshow.net/items/WCF-RIA-Services-Part-4-Integrating-with-the-Model-View-ViewModel-Pattern.aspx editorial@silverlightshow.net (Brian Noyes ) http://www.silverlightshow.net/items/WCF-RIA-Services-Part-4-Integrating-with-the-Model-View-ViewModel-Pattern.aspx#comments http://www.silverlightshow.net/items/WCF-RIA-Services-Part-4-Integrating-with-the-Model-View-ViewModel-Pattern.aspx Tue, 03 Aug 2010 02:51:00 GMT Navigating between Pages in Different Xaps (by using MEF) <p><em><strong>This article is compatible with the latest version of Silverlight.</strong></em></p> <div style="border:1px solid #dddddd;padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; width: 200px; float: right; margin-left: 10px; padding-top: 5px;"> <h3>More on this topic..</h3> <ul style="list-style-type: circle; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 20px; font-size: 12px;"> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/Search.aspx?q=MEF&adv=true&tg=true&ro=1&t=1&r=10&o=1">See more articles on MEF</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/shows/MEF-Webinar.aspx">Watch MEF Webinar by Gill Cleeren</a> </li> </ul> </div> <h3><strong>1. The Problem</strong></h3> <p>In this article I’ll show you a simple solution for navigation between pages in different Xaps, by using Managed Extensibility Framework (MEF). Recently I hit the following issue, while playing with MEF. Suppose that you have a Silverlight Navigation Application. Your application is partitioned in different modules (plugins, extensions, add-ons or whatever). Let's imagine that your application has three plugins – Orders plugin, Products plugin and Suppliers plugin, as shown on the snapshot below.</p> <p style="text-align: center;"><img alt="" src="http://www.silverlightshow.net/Storage/Users/ppopadiyn/MefNavigationFramework/Image010.png" /> </p> <p>Each one of your plugins contains an entry page (this is the so called <strong>Entry Point</strong> for the plugin). I’ll show you some technical details about the implementation later in the article. For now let’s stick to the main problem. Your main project (the host project) has static references to two of the plugins, for example OrdersPlugin and ProductsPlugin.</p> <p style="text-align: center;"><img alt="" src="http://www.silverlightshow.net/Storage/Users/ppopadiyn/MefNavigationFramework/Image020.png" /> </p> <p>Since both of the plugins are referenced by the main project, during compile time, they are included in the .Xap file! And once you start the application they are automatically loaded without any problems. However, the third plugin – the SuppliersPlugin is not included in the main .XAP file. It is downloaded runtime, by using the mighty DeploymentPackageCatalog (the DeploymentPackageCatalog is not part of MEF, but its implementation is widely spread in Google).</p> <p style="text-align: center;"><img alt="" src="http://www.silverlightshow.net/Storage/Users/ppopadiyn/MefNavigationFramework/Image030.png" /> </p> <p>If you try to navigate to the Orders page or Products page, then you won’t have any problems (it’s just like creating a regular Silverlight navigation application). However, when you try to navigate to the Suppliers page, you will see the following exception.</p> <p style="text-align: center;"><img alt="" src="http://www.silverlightshow.net/Storage/Users/ppopadiyn/MefNavigationFramework/Image040.png" /> </p> <p>What a shame, isn’t it? :). So where is the problem? By default the <strong>Frame</strong> class from the <strong>Navigation</strong> <strong>Framework</strong> uses the <strong>PageResourceContentLoader</strong> class to load the pages. The <strong>PageResourceContentLoader</strong> class has the following limitation: it is designed to load pages from the <strong>application package</strong> (<strong>the .xap file</strong>) that correspond to a given URI. However, our Suppliers page is not in the main application package, it is part of another package, downloaded runtime. That’s why the <strong>PageResourceContentLoader</strong> won’t know about the Suppliers page, and respectively won’t be able to load it.</p> <h3><strong>2. The Solution</strong></h3> <p>Fortunately the <strong>System.Windows.Controls.Navigation</strong> assembly provides us with the <strong>INavigationContentLoader</strong> interface. So, as you can guess, we need a custom implementation of the <strong>INavigationContentLoader</strong>.</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow-x: auto; overflow-y: auto; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> MefContentLoader : INavigationContentLoader</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">private</span> PageResourceContentLoader pageResourceContentLoader = <span style="color: #0000ff;">new</span> PageResourceContentLoader();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">private</span> Uri targetUri;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> IAsyncResult BeginLoad( Uri targetUri, Uri currentUri, AsyncCallback userCallback, <span style="color: #0000ff;">object</span> asyncState )</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> NotImplementedException();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">bool</span> CanLoad( Uri targetUri, Uri currentUri )</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> NotImplementedException();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> CancelLoad( IAsyncResult asyncResult )</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> NotImplementedException();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> LoadResult EndLoad( IAsyncResult asyncResult )</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> NotImplementedException();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow-x: visible; overflow-y: visible; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <p>The trick here is that our custom content loader should know about the entry points of each plugin.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> MefContentLoader : INavigationContentLoader</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> [ImportMany( AllowRecomposition = <span style="color: #0000ff;">true</span> )]</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> UIProviderBase[] Plugins</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> get;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> set;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #008000;">//....Rest of the code</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> <!--CRLF--></div> </div> <p>For our purposes we need to implement only the BeginLoad, CanLoad and EndLoad methods, like demonstrated on the code snippet below:</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> MefContentLoader : INavigationContentLoader</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">private</span> PageResourceContentLoader pageResourceContentLoader = <span style="color: #0000ff;">new</span> PageResourceContentLoader();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">private</span> Uri targetUri;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> MefContentLoader()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> CompositionInitializer.SatisfyImports( <span style="color: #0000ff;">this</span> );</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> [ImportMany( AllowRecomposition = <span style="color: #0000ff;">true</span> )]</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> UIProviderBase[] Plugins</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> get;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> set;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> IAsyncResult BeginLoad( Uri targetUri, Uri currentUri, AsyncCallback userCallback, <span style="color: #0000ff;">object</span> asyncState )</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">this</span>.targetUri = targetUri;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> pageResourceContentLoader.BeginLoad( targetUri, currentUri, userCallback, asyncState );</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">bool</span> CanLoad( Uri targetUri, Uri currentUri )</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> CancelLoad( IAsyncResult asyncResult )</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> NotImplementedException();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> LoadResult EndLoad( IAsyncResult asyncResult )</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">if</span> ( <span style="color: #0000ff;">this</span>.Plugins.Length == 0 ||</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">this</span>.Plugins.Count( p => p.EntryPage != <span style="color: #0000ff;">null</span> && p.EntryPage.Metadata.NavigateUri == targetUri.ToString() ) == 0 )</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> pageResourceContentLoader.EndLoad( asyncResult );</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> IView page = <span style="color: #0000ff;">this</span>.Plugins.First( p => p.EntryPage != <span style="color: #0000ff;">null</span> && p.EntryPage.Metadata.NavigateUri == <span style="color: #0000ff;">this</span>.targetUri.ToString() ).EntryPage.CreateExport().Value;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span> LoadResult( page );</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> </div> </div> <p>The tricky part comes into the <strong>EndLoad</strong> method. Once we know the entry points for each plugin, and we know the target uri, we can extract the requested page and pass it to the <strong>LoadResult</strong>.</p> <p>Finally, you need to set the <strong>Frame</strong>’s <strong>ContentLoader</strong> property in XAML.</p> <div id="codeSnippetWrapper" style="border:1px solid silver;padding-bottom: 4px; line-height: 12pt; overflow-x: auto; overflow-y: auto; background-color: #f4f4f4; margin-top: 20px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; cursor: text; padding-top: 4px; text-align: left;"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"><</span><span style="color: #800000;">navigation:Frame</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="ContentFrame"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">Style</span><span style="color: #0000ff;">="{StaticResource ContentFrameStyle}"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">Source</span><span style="color: #0000ff;">="/HomeView"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">NavigationFailed</span><span style="color: #0000ff;">="ContentFrame_NavigationFailed"</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">navigation:Frame.ContentLoader</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">local:MefContentLoader</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"></</span><span style="color: #800000;">navigation:Frame.ContentLoader</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">navigation:Frame.UriMapper</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">uriMapper:UriMapper</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">uriMapper:UriMapping</span> <span style="color: #ff0000;">Uri</span><span style="color: #0000ff;">=""</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">MappedUri</span><span style="color: #0000ff;">="/Views/HomeView.xaml"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">uriMapper:UriMapping</span> <span style="color: #ff0000;">Uri</span><span style="color: #0000ff;">="/{assemblyName};component/{path}"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">MappedUri</span><span style="color: #0000ff;">="/{assemblyName};component/{path}"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"><</span><span style="color: #800000;">uriMapper:UriMapping</span> <span style="color: #ff0000;">Uri</span><span style="color: #0000ff;">="/{pageName}"</span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #ff0000;">MappedUri</span><span style="color: #0000ff;">="/Views/{pageName}.xaml"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"></</span><span style="color: #800000;">uriMapper:UriMapper</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;"></</span><span style="color: #800000;">navigation:Frame.UriMapper</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;"></</span><span style="color: #800000;">navigation:Frame</span><span style="color: #0000ff;">></span></pre> </div> </div> <p>Check out the link at the end of the article, in case you want to download the full source code.</p> <h3><strong>3. Designing Plugin Applications</strong></h3> <p>Since there isn’t a lot of information in the web, I would like to say a few words about how to design (create) plugin applications. The strong definition about the plugin is a set of software components that adds specific capabilities to a large software application. We are surrounded with such kind of applications – the most famous are Office Word, Excel, Outlook, Visual Studio. Basically, each plugin has an entry point (plugin interface). The host application deals only with the plugin interfaces (not directly with the plugin). The host application operates independently of the plugins, making it possible for the end-users to add and update plugins dynamically without the need to make changes to the host application.</p> <p>Prior to .NET Framework 4, we didn't have any concrete technology for creating plugin applications. Fortunately, in .NET Framework 4, Microsoft provides us with the Managed Extensibility Framework (MEF) which is available for Silverlight, too.</p> <p>So let’s come back to our demo. I am using an abstract class named <strong>UIProviderBase </strong>and this is the “plugin interface” (the entry point) for the demo. The class provides a Title (the name of the plugin), an Image (associated with the plugin) and an EntryPage – this is the initial view (the main view) of the plugin. This class serves something like a contract, saying: “Hey, if you want to plug in your module in my application, you have to implement me”.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">abstract</span> <span style="color: #0000ff;">class</span> UIProviderBase</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">abstract</span> <span style="color: #0000ff;">string</span> Title</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> get;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">abstract</span> <span style="color: #0000ff;">string</span> ImageUri</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> get;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">abstract</span> ExportFactory<IView, IPageMetadata> EntryPage</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> get;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> set;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> </div> </div> <p>Each plugin should provide a UIProviderBase implementation. Additionally, that implementation should be marked with the <strong>[ExportAttribute]</strong>. Below you can see the entry point for the Suppliers plugin.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">[Export( <span style="color: #0000ff;">typeof</span>( UIProviderBase ) )]</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> SuppliersUIProvider : UIProviderBase</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">string</span> Title</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> get</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> <span style="color: #006080;">"Suppliers"</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">string</span> ImageUri</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> get</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">return</span> <span style="color: #006080;">"/SuppliersPlugin;component/Images/SuppliersImage.png"</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> [Import( ViewNames.SuppliersViewName )]</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">override</span> ExportFactory<IView, IPageMetadata> EntryPage</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> get;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> set;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> </div> </div> <p>On the other side, the host application is expecting an array of <strong>UIProviderBase</strong> implementations. Note the <strong>[ImportManyAttribute]</strong>.</p> <div id="codeSnippetWrapper"> <div id="codeSnippet" style="padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px; text-align: left;border-style: none;"> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">[Export( ViewModelNames.HomeViewModelName, <span style="color: #0000ff;">typeof</span>( <span style="color: #0000ff;">object</span> ) )]</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> HomeViewModel : MyViewModelBase, IPartImportsSatisfiedNotification</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">{</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> [ImportMany( AllowRecomposition = <span style="color: #0000ff;">true</span> )]</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> UIProviderBase[] Plugins</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> get;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> set;</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> </pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> OnImportsSatisfied()</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> {</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">this</span>.Plugins = <span style="color: #0000ff;">this</span>.Plugins.OrderBy( p => p.Title ).ToArray();</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> <span style="color: #0000ff;">this</span>.RaisePropertyChanged( <span style="color: #006080;">"Plugins"</span> );</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;"> }</pre> <!--CRLF--> <pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; overflow-x: visible; overflow-y: visible; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; margin-left: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; padding-top: 0px;border-style: none;">}</pre> </div> </div> <p>The other goodies:</p> <ul> <li>If you download the source code (the link is at the end of the article), you will find an implementation of the DeploymentServiceCatalog, which is downloading a XAP file by a given relative uri. </li> <li>Note the <strong>EntryPage</strong> property in the <strong>UIProviderBase</strong> class. An instance of the page is created on demand. What I am using here is a Metadata. For more information, you could read <a href="http://mef.codeplex.com/wikipage?title=Exports%20and%20Metadata&referringTitle=Guide">here</a>. </li> <li>In the HomeView.xaml I am using a PathListBox to arrange the UI. </li> <li>One last question I should answer is how the different plugins communicate with each other. Well, in this case you need to use the so called “global events (messages)". For example, I prefer the Messanger class from the MVVM Light Toolkit, but you can use the EventAggregator with the same success. </li> </ul> <div style="text-align: center;"><img alt="" style="margin-left: 0px;" src="http://www.silverlightshow.net/Storage/Users/ppopadiyn/MefNavigationFramework/Zip.png" /><br /> </div> <div style="text-align: center;"><a href="http://www.silverlightshow.net/Storage/Sources/MefNavigationFramework.zip">Download Source Code</a><br /> </div> http://www.silverlightshow.net/items/Navigating-between-Pages-in-Different-Xaps-by-using-MEF.aspx editorial@silverlightshow.net (Pencho Popadiyn ) http://www.silverlightshow.net/items/Navigating-between-Pages-in-Different-Xaps-by-using-MEF.aspx#comments http://www.silverlightshow.net/items/Navigating-between-Pages-in-Different-Xaps-by-using-MEF.aspx Mon, 02 Aug 2010 00:00:00 GMT