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 Part 8: Developing for a multitude of clients: strategies for code reuse and keeping costs in check. <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Part-8-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.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/Part-8-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" data-count="horizontal" data-text="Developing for a multitude of clients Part 8: Strategies for code reuse and keeping costs in check" data-url="http://slshow.net/WIlUaO">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Part-8-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p>We've already learned quite a bit about code reuse and strategies to keep costs in check in the <a href="http://www.silverlightshow.net/Profile/KevinDockx/Articles.aspx" target="_blank">previous articles in this series</a>: we've created a Silverlight web & OOB client, we <strong>split up our code in modules</strong> to enable them to be<strong> loaded on demand & reused</strong> by other clients, and we've created a Windows Phone client, in which we focussed on<strong> reuse of skill rather than reuse of XAML & code</strong> - but we could still share some common code through the use of a <strong>Portable Class Library</strong>, and of course: our service layer through its<strong> REST endpoints</strong>.</p> <p>As you might have noticed, an important distinction we try to make in this article series is the difference between<em> what can be reused</em> and <em>what should be reused</em>. That will become even more obvious in this article: we're going to add yet another type of client: a Windows 8 Store Application. </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/news/Free-SilverlightShow-Webinar-on-Oct-16-MVVM-in-Windows-8.aspx" target="_self">The webinar: 'MVVM in Windows 8'' with Gill Cleeren</a></li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Windows-8-Metro-Apps-The-8-Must-Know-Tricks-Day-1.aspx">The article series: Windows 8 Apps: The 8 Must-Know Tricks!</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_collections.aspx" target="_self">Ebook by Kevin Dockx: Working with Collections in WCF RIA Services</a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_collections.aspx" target="_self"><img style="width: 70px; height: 99px;" alt="Ebook by Kevin Dockx: Working with Collections in WCF RIA Services" src="http://www.silverlightshow.net/Storage/Ebooks/wcfriacoll_ebook_cover.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> <h3>Why would we want a Windows 8 Store Application?</h3> <p>Windows Store Applications are vastly different from what we've built up until now. There's a new set of design guidelines to confirm to, there's a new CLR these apps are built against, there's quite a few new coding principles to adhere to, … All in all: a lot of work if you're new to this. So why would we consider a Windows Store Application?</p> <p>One way to answer this question is by looking at the added value of these apps and the market opportunity we get as developers - a good blog post that sums up these <a href="http://blogs.msdn.com/b/jennifer/archive/2012/06/18/developing-a-windows-8-metro-app-part-1-why-would-you-want-to-develop-a-metro-application-for-windows-8.aspx" target="_blank">can be found at MSDN</a>. </p> <h3>What should we offer in this client?</h3> <p>This is one of the first questions we should ask ourselves, as quite a bit of the development cost will depend on the features we want to offer, or rather: on what we can use to build these features with. </p> <p>Let's have a look back at our full-blown Silverlight client: we use this one for quite a bit of data input - and validation on that data, client-side (next to server-side, of course). Thing is, at this point in time, Silverlight is a mature framework, which includes building blocks to make it easier for us to achieve solutions to some common concerns.  WinRT, or what’s offered by WinRT, isn’t yet. </p> <p>For example, thanks to WCF RIA Services, we've got a framework that tackles a very important concern for data input apps: validation. Write validation rules on the server, and they're generated on the client. Next to that, the Silverlight controls have built-in functionality to listen & react to this type of validation, through the INotifyDataErrorInfo interface. This combination results in almost out-of-the-box validation.</p> <p>For Windows 8 Store Applications, this isn't the case: at the moment, there isn't anything resembling WCF RIA Services available for these types of apps (and we don't know yet if something like that will be available in the foreseeable future). Furthermore: the INotifyDataErrorInfo interface is completely absent for Store Applications - in fact: any kind of validator is absent.</p> <p>And there's more: a lot of other components we could use - like third-party components for graphs - aren't available either, or are in an initial state. Of course, this is quite normal: after all, at the time of writing, Windows 8 isn't available to the general public yet. All this will get better, but it will take some time.</p> <p>We should keep in mind that the framework for building Windows 8 Store Applications is very much a "v1.0"-framework - a bit like what Silverlight was when Silverlight 2 was made available. Out of that follows that if we would want to support features that aren't built-in, or for which there aren't any mature helper frameworks available, it will take a lot of time, and thus cost a lot of money.</p> <p>If we want to keep costs in check, the above should be one of the first things to take into account. When developing software, it's not using the framework as it was intended to build the app that heightens the cost, it's often (mis-)using the framework or trying to add features that it isn't ready for that causes that. </p> <h3>Should we reuse the UI? After all, it's built in XAML, right?</h3> <p>Windows 8 Store Applications come with their own set of UI guidelines, which result in a UI that's quite different from what we've done in our initial Silverlight application. When you're building a Windows 8 application, you're building an application that should easily be controllable using touch - typically, you'd have larger buttons, more whitespace, less reliance on tooltips, … But that's not all. Navigation should typically be achieved hierarchically, or through a navigation bar - different from what we're used to. A lot of commands (the non-essential ones) should be moved to the command bar instead of being on-canvas (as they are now). And then there's charms: to ensure a consistent experience across applications, a few common features of apps should be implemented through the charms bar instead of in the application itself. Searching through the data of our application should be done via the Search charm. If we want to share data to other apps, we should use the Share charm. And our application settings should be accessible through the Settings charm.</p> <p>Another thing to keep into account is the fact that we're now looking at an application which can be snapped to the left or the right of the screen, which means we have to provide a snapped view for the pages in our application. Optionally, we could also provide a portrait mode next to the default landscape mode. </p> <p>These are just a few traits that make for a good Windows 8 Store Application, and if you think about this, that's quite a lot of change from what we're used to. But it makes sense: ensuring your app confirms to these guidelines ensures a consistent experience for the end-user, no matter which app (s)he is using.</p> <p>If you're new to this, you might want to <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh465424.aspx" target="_blank">check out the guidelines</a> on this, or have a look at <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh770549.aspx" target="_blank">a few case studies</a> at MSDN.</p> <p>Obviously, it's clear that we shouldn't reuse our current UI. But can we?</p> <p>Unless you've been building a very simple application: no. The XAML used for Windows 8 Store Applications contains quite a few differences from the XAML used in Silverlight, WPF or Windows Phone: from controls that aren't available or have been replaced by better-suited controls (eg: a ListView instead of ListBox), to some more fundamental concepts like binding changes, supported interfaces, … </p> <p>There's a great overview available on <a href="http://msdn.microsoft.com/en-us/library/windows/apps/xaml/br229571.aspx" target="_blank">porting Silverlight or WPF XAML to Windows Store XAML</a> at MSDN. </p> <h3>What about our ViewModels?</h3> <p>Technically, we could think we could reuse most of our ViewModel code from our Windows Phone application. That application uses the REST endpoints of our service layer, which is exactly what we'll be using for this client. However, Windows 8 Store Applications rely heavily on async & await, or, in fact, the Parallel Tasks framework (more on this in the next article) - you won't find the typical completed handlers we've got in Windows Phone to execute code when our async service call returns; instead, we should use the async/await keywords.</p> <p>Next to that, due to the fact that a View is implicitly connected to a ViewModel, and the fact that we've concluded that reusing the UI isn't a feasible option (if only for the very different design guidelines), we cannot technically reuse our ViewModels, and we should not either, as the use cases will be implemented differently. </p> <h3>Wait a minute. Is there anything left we can reuse?</h3> <p>Well, of course there is. We've used WCF RIA Services for our back-end services, and these services can be consumed through their REST endpoints, much like we did for our Windows Phone client. Next to that, the Portable Class Library project template supports Windows 8 Store Applications, so that's something we can reuse as well. And of course, there's knowledge & skill reuse.</p> <p>Luckily, it's fairly easy to build Windows 8 Store Applications. The framework might not support everything we're used to (yet), but the concepts it does support are is thought-out quite well. In the next article in this series, we'll effectively start building our Windows 8 client, keeping into account the questions we've raised and answered in this article.</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 applications, mainly XAML-based, and the solution owner for Windows Store Apps. His main focus lies on all things XAML, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a XAML enthusiast, he's a regular speaker on various national and international events, like Microsoft Techdays in Belgium, Portugal & Finland, NDC, Community Day, VISUG, ... Next to that, he also authored two Silverlight books at Packt Publishing, of which the most recent one is the <a href="http://www.packtpub.com/microsoft-silverlight-5-data-and-services-cookbook/book">Silverlight 5 Data and Services Cookbook</a>, together with Gill Cleeren. His blog, which contains various tidbits on XAML, .NET, and the occasional rambling, can be found at <a href="http://blog.kevindockx.com/">http://blog.kevindockx.com/</a>, and you can contact him on Twitter via <a href="http://twitter.com/#!/KevinDockx">@KevinDockx</a>.</p> http://www.silverlightshow.net/items/Part-8-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Part-8-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx#comments http://www.silverlightshow.net/items/Part-8-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx Wed, 24 Oct 2012 10:29:00 GMT Part 7: Developing for a multitude of clients: strategies for code reuse and keeping costs in check. <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Part-7-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.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/Part-7-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" data-count="horizontal" data-text="Developing for a multitude of clients Part 7: Strategies for code reuse and keeping costs in check" data-url="http://slshow.net/KpTA8W">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Part-7-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p>In the <a href="http://www.silverlightshow.net/Profile/KevinDockx/Articles.aspx" target="_blank">previous articles in this article series</a>, we've looked into different ways of <strong>getting our code split up in modules</strong>, so they can be loaded on demand, and easily <strong>reused</strong> across different types of clients - thus cutting costs and saving on development time. </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 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/items/WCF-RIA-Services-Part-1-Getting-Started.aspx">10-part Article Series: WCF RIA Services</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/WCF-RIA-Services-Webinar-5.aspx">Recording of the recent webinar: Prism and WCF RIA Services</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/domain_context.aspx">Kevin's ebook: Silverlight WCF RIA Services</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; width: 110px; height: 154px;" alt="Silverlight WCF RIA Services: Ebook" src="http://www.silverlightshow.net/Storage/Ebooks/domain_context.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> We created a Silverlight web client & OOB client, and in the last part, we started thinking about our <strong>Windows Phone client</strong>. We ended up with some thoughts about what we should and shouldn't reuse - the conclusion was that we could reuse our existing XAML & C# skills, our domain services, and that we would be able to share code through the use of a Portable Class Library. <p>In this article, it's time to delve further into this: we exposed our domain services through SOAP endpoints, and now we'll learn how to consume them. We'll also look into that Portable Class Library.</p> <p>You can <a href="http://cdn.silverlightshow.net/storage/CodeForArticleSeven.zip" target="_blank">download the source code for this article here</a> (you can log in to the demo application with <strong>pete.campbell@madmen.com / <a href="mailto:abc@123">abc@123</a></strong>).</p> <p> </p> <h3>Consuming domain services from Windows Phone.</h3> <p>Let's start with the Windows Phone client. We'll add the necessary references to the Windows Phone application by selecting "Add Service Reference…" and inputting the correct URI's: <a title="http://localhost/SalesDashboard.ServiceHost/EmployeeOpportunityService.svc/soap" href="http://localhost/SalesDashboard.ServiceHost/EmployeeOpportunityService.svc/soap">http://localhost/SalesDashboard.ServiceHost/EmployeeOpportunityService.svc/soap</a> for the EmployeeOpportunity domain service, and <a title="http://localhost/SalesDashboard.ServiceHost/SalesAuthenticationService.svc/soap" href="http://localhost/SalesDashboard.ServiceHost/SalesAuthenticationService.svc/soap">http://localhost/SalesDashboard.ServiceHost/SalesAuthenticationService.svc/soap</a> for the SalesAuthentication domain service. Visual Studio will generate the necessary proxy classes for us, including NotifyPropertyChanged notifications. We end up with 2 service references & corresponding proxies, which we can now use from our application.</p> <p>The first thing we need to do is log in, which can be done with the following code:</p> <pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> Login() { <span class="rem">// try to log in with the provided credentials</span> SalesAuthenticationServicesoapClient authenticationClientProxy = <span class="kwrd">new</span> SalesAuthenticationServicesoapClient(); authenticationClientProxy.LoginCompleted += (sLogin, aLogin) => { <span class="kwrd">if</span> (aLogin.Error == <span class="kwrd">null</span>) { <span class="kwrd">if</span> (aLogin.Result.RootResults != <span class="kwrd">null</span> && aLogin.Result.RootResults.Count() > 0) { LocalStateContainer.AuthenticatedEmployee = aLogin.Result.RootResults.First(); LocalStateContainer.CookieContainer = authenticationClientProxy.CookieContainer; var root = App.Current.RootVisual <span class="kwrd">as</span> PhoneApplicationFrame; root.Navigate(<span class="kwrd">new</span> Uri(<span class="str">"/Views/MainView.xaml"</span>, UriKind.Relative)); Messenger.Default.Send<LoadOpportunitiesMessage>(<span class="kwrd">new</span> LoadOpportunitiesMessage() { EmployeeId = LocalStateContainer.AuthenticatedEmployee.Id }); } } }; authenticationClientProxy.LoginAsync(UserName, Password, <span class="kwrd">true</span>, <span class="str">""</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>After this, we can fetch our data. Note that, if a domain service requires you to be authenticated, you need to pass in the <strong>CookieContainer</strong> value you got after logging in to each service call. We can do that by setting the proxy clients' CookieContainer to that value:</p> <pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> LoadOpportunities(LoadOpportunitiesMessage msg) { var client = <span class="kwrd">new</span> EmployeeOpportunityDomainServicesoapClient(); client.CookieContainer = LocalStateContainer.CookieContainer; client.GetOpportunitiesForUserCompleted += (s, a) => { <span class="kwrd">if</span> (a.Error == <span class="kwrd">null</span>) { Opportunities = a.Result.RootResults; } }; client.GetOpportunitiesForUserAsync(msg.EmployeeId); }</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>When we try to test this… we'll get an error message: <em>"Unable to set the CookieContainer. Please make sure the binding contains an HttpCookieContainerBindingElement."</em></p> <p>Why is this? Well, by adding a service reference, Visual Studio creates a ServiceReferences.ClientConfig file, but by default, the binding that is create is a regular BasicHttpBinding. We need to change this to ensure the HttpCookieContainer is enabled. We can do this by opening the configuration file, and changing the binding to our EmployeeOpportunityDomainService as such:</p> <pre class="csharpcode"><span class="kwrd"><</span><span class="html">binding</span> <span class="attr">name</span><span class="kwrd">="BasicHttpBinding_EmployeeOpportunityDomainServicesoap"</span> <span class="attr">enableHttpCookieContainer</span><span class="kwrd">="true"</span> <span class="attr">maxBufferSize</span><span class="kwrd">="2147483647"</span> <span class="attr">maxReceivedMessageSize</span><span class="kwrd">="2147483647"</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><em>Please note that this alone is not sufficient to secure your services, nor to pass and check credentials - it's just the starting point. Detailing the security aspects (transport security certificates & identity) of a Windows Phone application in combination with WCF RIA Services is out of scope for this article series, but if you're interested in this, you might want to have a look at <a href="http://blog.kevindockx.com/" target="_blank">my blog</a>: in the recent past, I delivered a few sessions on this at various conferences, for which both the source code and slidedecks can be downloaded (<a href="http://blog.kevindockx.com/post/Techdays-2012-Helsinki-slidedeck-code.aspx" target="_blank">Techdays session</a>, <a href="http://blog.kevindockx.com/post/WiPhug-Slidedeck-and-code.aspx" target="_blank">WiPhug session</a>) - the demo application for those sessions also includes code detailing how to submit data to a WCF RIA Service from a Windows Phone application.</em></p> <p>If we build & run our application again and log in, we've got our list of Opportunities, straight from the domain service. However, there seems to be a problem when binding it to our View:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/_________image_2.png"><img style="background-image: none; border: 0px solid; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" title="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/_________image_thumb.png" width="258" height="427" /></a></p> <p>… as you might notice, there seems to be no value for Sector, Status, … What's happening?</p> <p> </p> <h3>Working with child entities.</h3> <p>The problem we're noticing in the above screenshot is due to the fact that only the "simple properties" from our entities are generated by default. While, in the Silverlight application, child entities that were sent over the wire (or were already available in the DomainContext instance) were accessible through, for example, Opportunity.Sector, this Sector property is now missing: we're only getting a SectorId. How can we solve this?</p> <p>If we look at the generated proxy code, we see that the proxies classes for our entities are implemented as partial:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> Opportunity : <span class="kwrd">object</span>, System.ComponentModel.INotifyPropertyChanged</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 enables us to add code to that class in a different file. We can add a new property to another partial implementation of our Opportunity class, and this property will represent the Sector.</p> <p>On to the next part of the problem: where does this Sector-property come from? As mentioned in the previous article, the result you're getting from a call to a domain service query method are actually divided into two properties: RootResults and IncludedResults. The IncludedResults include possible child entities (it's an ObservableCollection<object>, so it can actually contain different types of entities - you'll have to check for this). This means that, if the query method that returns the list of Opportunities is coded in such a way that it also returns the corresponding Sector entity, we can simply fetch that Sector entity from the IncludedResults list, and assign it to the Sector property we implemented in our partial class.</p> <p>Easy enough :-)</p> <p>But… what if the query method didn't return those child entities (remember: we're reusing an existing implementation, and we're trying to change as little as possible to the service layer)? Well, the first part remains the same: extend the partial Opportunity class so it contains a Sector property. You could now go and fetch that entity from another query method for each Opportunity, but that would create a lot of overhead, and way too many requests to our service layer: after all, the list of sectors is quite small, and lots of opportunities share the same sector. So instead, we can opt for loading the list of sectors when we start the application, and storing them in a container. The Sector property would then get the corresponding sector from that list, in its property getter, as such:</p> <pre class="csharpcode"><span class="rem">/// <summary></span> <span class="rem">/// The Sector property</span> <span class="rem">/// </summary></span> <span class="kwrd">public</span> SalesDashboard.PhoneApplication.EmployeeOpportunityRef.Sector Sector { get { <span class="kwrd">return</span> LocalStateContainer.Sectors == <span class="kwrd">null</span> ? <span class="kwrd">null</span> : LocalStateContainer.Sectors.FirstOrDefault(s => s.Id == <span class="kwrd">this</span>.SectorId); } }</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>Either way, our opportunity list now includes the correct sector identification:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/_______image_4.png"><img style="background-image: none; border: 0px solid; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" title="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/_______image_thumb_1.png" width="265" height="439" /></a></p> <p>The same logic can be applied to add the Customer property of an Opportunity to the screen. After this, our application includes all the information we need to provide to the end user while he's on the road.</p> <p> </p> <h3>Sharing code: the Portable Class Library.</h3> <p>In a lot of projects, you have some common code you want to use across different clients: this might be code to execute some common business logic or algorithms, or some often-used functions. Typically, you'd put these in a class library project, which is then referenced by each client that needs that common code.</p> <p>However, references are typically only allowed if they're built against the same CLR, and at the moment we already have 3 different CLR's we're working with: the full .NET 4.0 CLR, the Silverlight CLR, and the Silverlight for Windows Phone CLR. For our initial two clients (Silverlight & Silverlight OOB), we could leverage some of WCF RIA Services' shared code features, but this is getting harder as we progress to the Windows Phone client, and will become even more annoying when we're going to add a Windows 8 Metro client to the equation later on in this article series.</p> <p>One often-used way to achieve code sharing without having to copy code around is by using the "Add as link" option. It works like this:</p> <ul> <li>Create 1 class library project, typically built against the CLR that has the "least" features - in our case, that would be a Windows Phone class library project.</li> <li>Create extra class library projects for each CLR you need the common code to be built against. For example, we'd end up with Common.WP7, Common.SL and Common.Server class library projects.</li> <li>In those class library projects, add the files containing the common code "as link".</li> <li>The class library projects themselves are then referenced by their respective client projects, allowing those clients to access the common code.</li> </ul> <p>While this technique works, it has 2 major disadvantages:</p> <ul> <li>You end up with clutter: extra projects in your solution, simply to be able to reference them.</li> </ul> <ul> <li>It's easy to make mistakes: if you happen to add code to the common code files which doesn't result in a successful build against each CLR, your projects won't run anymore - even though the code successfully builds against one specific CLR version.</li> </ul> <p>The Portable Class Library template solves this. On <a href="http://msdn.microsoft.com/en-us/library/gg597391.aspx" target="_blank">MSDN</a>, we can find the following description:</p> <blockquote> <p>"The Portable Class Library project enables you to write and build managed assemblies that work on more than one .NET Framework platform. You can create classes that contain code you wish to share across many projects, such as shared business logic, and then reference those classes from different types of projects.</p> <p>Using the Portable Class Library project, you can build portable assemblies that work without modification on the .NET Framework, Silverlight, Windows Phone 7, or Xbox 360 platforms. Without the Portable Class Library project, you must target a single platform and then manually rework the class library for other platforms. The Portable Class Library project supports a subset of assemblies from these platforms, and provides a Visual Studio template that makes it possible to build assemblies that run without modification on these platforms."</p> </blockquote> <p>You can add the Portable Class Tools <a href="http://visualstudiogallery.msdn.microsoft.com/b0e0b5e9-e138-410b-ad10-00cb3caf4981/" target="_blank">from this link</a>. </p> <p>So: it allows you to add 1 class library project to your solution, in the properties of which you can tell which CLR's should be supported. The code you add to that class libary project will have to adhere to the lowest common denominator for the combination of selected CLR's (ensuring your code will build against each CLR version you selected). Next to that, Visual Studio allows you to add a reference to this class library from each project which builds against the CLR versions you selected in the class library's project properties, leaving us with only 1 common project.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/____image_6.png"><img style="background-image: none; border: 0px solid; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" title="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/____image_thumb_2.png" width="344" height="309" /></a></p> <p>For reference, I've added a Portable Class Library project to the solution, SalesDashboard.Common, which I referenced without issue in 3 projects built against a different CLR. Doing something like this in the past would have required the "add as link" trick mentioned above - thanks to the Portable Class Library templates, we no longer have to resort to such tricks, making it easier to share code, maintain the code base, and thus: reuse the common library & cut costs.</p> <p> </p> <h3>Conclusion</h3> <p>In this article, we’ve learned how to consume existing domain services from a new type of client: a Windows Phone application.  We’ve also learned how we can reuse common code using the Portable Class Library project template.</p> <p>Stay tuned for the next part! :-)</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 applications, mainly XAML-based, and a solution manager for Rich Applications (Windows 8 Metro, Silverlight, Windows Phone 7 Series, WPF, Surface, HTML5). His main focus lies on all things XAML, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a XAML enthusiast, he's a regular speaker on various national and international events, like Microsoft Techdays in Belgium, Portugal & Finland, NDC2011, Community Day, ... Next to that, he also authored two Silverlight books at Packt Publishing, of which the most recent one is the <a href="http://www.packtpub.com/microsoft-silverlight-5-data-and-services-cookbook/book" target="_blank">Silverlight 5 Data and Services Cookbook</a>, together with Gill Cleeren. His blog, which contains various tidbits on XAML, .NET, and the occasional rambling, can be found at <a href="http://blog.kevindockx.com/">http://blog.kevindockx.com/</a>, and you can contact him on Twitter via <a href="http://twitter.com/#!/KevinDockx">@KevinDockx</a>.</p> http://www.silverlightshow.net/items/Part-7-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Part-7-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx#comments http://www.silverlightshow.net/items/Part-7-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx Tue, 12 Jun 2012 07:55:00 GMT Part 6: Developing for a multitude of clients: strategies for code reuse and keeping costs in check. <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Part-6-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.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/Part-6-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" data-count="horizontal" data-text="Developing for a multitude of clients Part 6: Strategies for code reuse and keeping costs in check" data-url="http://slshow.net/OqPdIw">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Part-6-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p>Welcome to the sixth part of this <a href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" target="_blank">article series on developing for a multitude of clients</a>, in which we talk about strategies for code reuse and keeping costs in check.  In the previous articles, we've looked into different ways of <strong>getting our code split up in modules</strong>, so they can be <strong>loaded on demand</strong>, and easily <strong>reused</strong> across different types of clients - thus cutting costs and saving on development time. However: up until now, we've focused on clients that were alike: a Silverlight web client, and a Silverlight Out of Browser client.  In this article, we'll look into a different one: <strong>a Windows Phone client</strong> - in which code sharing isn't possible by default, as those apps are built against another version of the CLR.</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 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/items/WCF-RIA-Services-Part-1-Getting-Started.aspx">10-part Article Series: WCF RIA Services</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/Recording-of-Contracts-in-Win8-Webinar.aspx">Recording of the recent webinar: Contracts and Charms in Windows 8</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_collections.aspx">Kevin's ebook: Working with Collections in WCF RIA Services</a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_collections.aspx"><img style="border: 0px solid; width: 90px; height: 126px;" alt="Working with Collections in WCF RIA Services: Ebook" src="http://www.silverlightshow.net/Storage/Ebooks/wcfriacoll_ebook_cover.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, we'll look into what we can reuse from the existing code base when creating a Windows Phone client. Interesting to notice here is that <em>"being able to reuse code"</em> doesn't mean <em>"should reuse code"</em>.</p> <p> </p> <h3>What can we reuse from our previous applications and/or backend?</h3> <p>Of course, we've got some skill reuse: after all, Windows Phone development is Silverlight development. That said, there are other things to keep in mind here.</p> <p>The first one: <strong>what do we want to offer to our end users with this mobile application</strong>? As stated in the first part of this article series, the general idea of having a mobile component to an already-existing application is that we do not want to offer the complete set of functionalities the full application has to the end user. We're building a way to extend his experience to on-the-road use, we're not building a replacement of the full application - for our business case to succeed, the end user should still have an incentive to use the full-blown application.</p> <p>Second, there's the <strong>connection we're working with</strong>: you're typically running on an EDGE or 3G connection, meaning: slower than the Wi-Fi or networked connection used with the other Silverlight clients, and, depending on the plan the end user has with his phone company: potentially (exponentially) more expensive. This means that the amount of data transferred should be kept in mind at all times - and preferably as low as possible. We need to find a good trade-off between data transfer, speed and development time.</p> <p>Third, there's the <strong>UI</strong>. When you're designing a Windows Phone application, you're designing for smaller screen estate, with touch-based input, and you'd want your application to feel like it conforms to the way Windows Phone apps typically look. This typically requires a different UI than our Silverlight clients. Microsoft has a great set of guidelines on Metro design, which you can read about <a href="http://www.microsoft.com/design/toolbox/tutorials/windows-phone-7/metro/" target="_blank">here</a>.</p> <p>With all these things in mind, what can we reuse for our phone client? Obviously, we shouldn't reuse the Views, as they will deliver a sub-par user experience, almost by default (different screen estate, different input method). We shouldn't reuse our ViewModels: after all, they are, by convention at least, coupled to the corresponding Views, and designed for regular Silverlight clients - bandwidth considerations are different. And even if we would ignore that, some of the code in those ViewModels won't just recompile in a Windows Phone application: it's built on a different version of the CLR. One obvious example would be the way we'll access our services: working with a Domain Service from Windows Phone = working with the SOAP or REST (JSON) endpoints.</p> <p>What can we reuse then?</p> <ul> <li>Existing skills</li> <li>Our backend services: the Authentication domain service, and the Employee Opportunity domain service.</li> <li>We can also reuse some common login and/or code, typically by transferring that code to a class library that can be referenced by the Silverlight app as well the Windows Phone app. As you might know, this isn't possible by default: Visual Studio disallows referencing assemblies that are built against a different version of the CLR, or (depending on what it's built against) will warn you about this. Luckily, there's a specific project template designed for this, the Portable Class Library.</li> </ul> <p> </p> <h3>Windows Phone client: the demo application case.</h3> <p>The general idea behind our new mobile client is that we want to provide our customers with parts of the functionality of the full application, not all of it. While it's technically possible, we're not trying to rebuild the complete application on the phone: it makes more sense to only provide those parts that are useful when on the road. Coincidently, that fits with the theme of this article series: when you're trying to keep costs in check, scope management is very important.</p> <p>For the demo application, we're going to enable the user to log in to the app on the phone, get an overview of his opportunities, and look at the detail of them. An app like this contains everything we need for this series: reuse of the services, and sharing of some common logic. Note that if we were to build this app for real-life use, we might want to enable the user to edit/add new opportunities on the go as well.</p> <p>There's a tremendous amount of resources available at SilverlightShow if you want to <a href="http://www.silverlightshow.net/Search/Learn.aspx?q=wp7" target="_blank">learn more about building Windows Phone applications</a>.</p> <p> </p> <h3>Reusing the backend: consuming domain services from a Windows Phone application.</h3> <p>WCF RIA Services is a powerful framework for building Silverlight application: you get client-side change tracking, generation of client-side versions of your entities, validation, authentication/authorization, … When you try to use this in a Windows Phone application, you'll immediately notice this isn't possible in the way you're used to: you cannot reference the necessary WCF RIA Services assemblies in your Windows Phone application, you don't get client-side Domain Contexts corresponding to your domain services, … so - are we stuck?</p> <p>No, we're not: domain services can be accessed from a Windows Phone application through a variety of endpoints: SOAP, REST and OData (read-only). For our application, we're going to reuse both domain services: the SalesAuthenticationService to log in, and the EmployeeOpportunityService to get data to the Windows Phone application.</p> <p>The WCF RIA Services Toolkit contains all the necessary components to allow this - and the easiest way to add this is through <a href="http://nuget.org/" target="_blank">NuGet</a>. Locate the RIAServices.Endpoints package, and install it to the Dashboard ServiceHost. Installing this will add a few lines of code to the web.config file:</p> <pre class="csharpcode"><span class="kwrd"><</span><span class="html">domainServices</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">endpoints</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="OData"</span> <span class="attr">type</span><span class="kwrd">="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory, System.ServiceModel.DomainServices.Hosting.OData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"</span> <span class="kwrd">/></span> <span class="kwrd"><</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="soap"</span> <span class="attr">type</span><span class="kwrd">="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"</span> <span class="kwrd">/></span> <span class="kwrd"><</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="JSON"</span> <span class="attr">type</span><span class="kwrd">="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"</span> <span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">endpoints</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">domainServices</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>We're going to use the soap endpoint. As you can see in the web.config file, it's the SoapXmlEndpointFactory that ensures the soap endpoint is created & accessible. To access a domain service through its soap endpoint, you can navigate to "namespace.classname", replacing the dots by dashes, and adding .svc to that url. However, in the <a href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check-part-2.aspx" target="_blank">second article of this series</a>, we enabled better naming for our services: this makes it even easier to access the soap endpoints, as it's exactly the same URL as before: <a href="http://localhost/SalesDashboard.ServiceHost/EmployeeOpportunityService.svc?wsdl">http://localhost/SalesDashboard.ServiceHost/EmployeeOpportunityService.svc?wsdl</a></p> <p>Let's have a look at the WSDL, with these new endpoint factories in the web.config:</p> <pre class="csharpcode"><span class="kwrd"><</span><span class="html">wsdl:service</span> <span class="attr">name</span><span class="kwrd">="EmployeeOpportunityDomainService"</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">wsdl:port</span> <span class="attr">name</span><span class="kwrd">="BasicHttpBinding_EmployeeOpportunityDomainServicesoap"</span> <span class="attr">binding</span><span class="kwrd">="tns:BasicHttpBinding_EmployeeOpportunityDomainServicesoap"</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">soap:address</span> <span class="attr">location</span><span class="kwrd">="http://localhost/SalesDashboard.ServiceHost/EmployeeOpportunityService.svc/soap"</span><span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">wsdl:port</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>(note: the WSDL is much bigger than the excerpt above – this is the SOAP-related part)</p> <p>As you can see, simply by adding the endpoint factories from the RIAServices.Endpoints package, our domain services are accessible through the SOAP endpoint. We're done with the server side for now.</p> <p> </p> <h3>How does a domain service work when exposed through a SOAP endpoint?</h3> <p>An important question remains: how does a domain service function when a client tries to access it through a SOAP endpoint?</p> <ul> <li>For each query method we've defined in our domain service, a corresponding method is generated in the proxy client, so we can load data from the domain service to the Windows Phone application.</li> <li>When the operation completes, we get a set of results through the completed events' arguments. This result object inherits <strong>QueryResult</strong>, and contains two properties that are interesting for us: <strong>RootResults</strong> and <strong>IncludedResults</strong>. RootResults contains the list of parent items returned by the domain service query method. IncludedResults contains possible child items, if you're returning those (as you know, you can include child entities to be sent over the wire with RIA Services by using the [Include] attribute in your metadata file)</li> <li>To submit data, you can create a list of <strong>ChangeSetEntry</strong> on the client, which you can pass to the proxy clients' <strong>SubmitChangesAsync</strong> method. Once this call reaches the server, the corresponding create, update or delete methods will be executed. This will recreate the change set on the server, entry by entry, after which they will be persisted to the data store (in our case, we're using the Entity Framework as backend store).</li> <li>The call to that method will return with a list of <strong>ChangeSetEntry</strong>: this will contain each persisted entry. You can use this list to check for problems when submitting, for ValidationErrors, ...</li> </ul> <p>That is, in a nutshell, how the main functionalities of a domain service are exposed to our Windows Phone application: we've got all our query methods, we can get results including child results, we can create a change set in our Windows Phone app, and we can submit this change set back to our domain service.</p> <p> </p> <h3>What’s next?</h3> <p>In the next article, we’ll look at how we can consume the SOAP endpoints we’ve created from our Windows Phone application: we’ll look into authentication, and passing that authentication cookie to the domain service calls. Next to that, we’ll also look into how we can achieve some further code sharing through the use of a Portable Class Library.</p> <p>Stay tuned! :-)</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 applications, mainly XAML-based, and a solution manager for Rich Applications (Windows 8 Metro, Silverlight, Windows Phone 7 Series, WPF, Surface, HTML5). His main focus lies on all things XAML, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a XAML enthusiast, he's a regular speaker on various national and international events, like Microsoft Techdays in Belgium, Portugal & Finland, NDC2011, Community Day, ... Next to that, he also authored two Silverlight books at Packt Publishing, of which the most recent one is the <a href="http://www.packtpub.com/microsoft-silverlight-5-data-and-services-cookbook/book" target="_blank">Silverlight 5 Data and Services Cookbook</a>, together with Gill Cleeren. His blog, which contains various tidbits on XAML, .NET, and the occasional rambling, can be found at <a href="http://blog.kevindockx.com/">http://blog.kevindockx.com/</a>, and you can contact him on Twitter via <a href="http://twitter.com/#!/KevinDockx">@KevinDockx</a>.</p> http://www.silverlightshow.net/items/Part-6-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Part-6-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx#comments http://www.silverlightshow.net/items/Part-6-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx Tue, 05 Jun 2012 12:33:40 GMT Part 5: Developing for a multitude of clients: strategies for code reuse and keeping costs in check. <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Part-5-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.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/Part-5-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" data-count="horizontal" data-text="Developing for a multitude of clients Part 5: Strategies for code reuse and keeping costs in check" data-url="http://slshow.net/N8b3Ug">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Part-5-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p>Welcome to the fifth part of this article series on strategies for designing your application for a multitude of different clients.  In the <a href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx">first part</a>, we’ve looked into the <strong>business case & some general concerns</strong>, and in the <a href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check-part-2.aspx">second part</a>, we made a choice for a <strong>service layer: WCF RIA Services</strong>.  In the <a href="http://www.silverlightshow.net/items/Part-3-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx">third part</a>, we’ve seen how we can use <strong>MEF for on demand loading & code reuse</strong> across different clients, and in the <a href="http://www.silverlightshow.net/items/Part-4-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" target="_blank">fourth part</a>, we’ve learned how to load a <strong>multitude of assemblies on demand</strong>, and we’ve learned how we can <strong>navigate to views in an on-demand loaded assembly</strong> by implementing a custom content loader in combination with a view factory.</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 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/items/WCF-RIA-Services-Part-1-Getting-Started.aspx">10-part Article Series: WCF RIA Services</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/news/Webinar-Contracts-and-Charms-in-Windows-8.aspx">Upcoming Webinar: Contracts and Charms in Windows 8</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_collections.aspx">Kevin's ebook: Working with Collections in WCF RIA Services</a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_collections.aspx"><img style="border: 0px solid;" alt="Working with Collections in WCF RIA Services: Ebook" src="http://www.silverlightshow.net/Storage/Ebooks/wcfriacoll_ebook_cover.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 part, we’re going to add another client to equation: a Silverlight Out of Browser client.  After all the work we’ve done on the previous articles, we’ll see just how easy it is to reuse most of the code we already have.</p> <p>You can <a href="http://www.silverlightshow.net/Storage/Sources/MultipleClientsPart5.zip">download the source code for this article here</a> (you can log in to the demo application with <strong>pete.campbell@madmen.com / abc@123</strong>).</p> <h3>Getting started: adding a new, Silverlight Out of Browser client</h3> <p>To start, we’re going to have to add a new client to our solution.  I’ve added a new Silverlight client, named SalesDashboard.Silverlight.DesktopClient, to the solution, and configured it to run as an Out of Browser application (project properties –> Silverlight).</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/___image_6.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px; border-style: solid;" title="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/___image_thumb_2.png" width="379" height="227" /></a></p> <p>As we’re aiming to reuse a lot of code, the Out of Browser application itself doesn’t really have to contain a lot of code: in essence, we’ll need to ensure the correct references are there, and the correct assemblies are loaded when we start the application – just like we did with the in-browser Silverlight client.</p> <p>For the references, we can simply go down the same road as explained in the previous article: commonly used code, existing assemblies that contain classes used throughout the application, … are added as a reference.  This includes the MVVM Light related assemblies, Toolkit assemblies, … On the other hand, code that belongs to a specific module is loaded on demand: we do add them as references, but we set the Copy Local flag to false, ensuring they’re not copied to the output directory (and thus not packaged in the resulting XAP file, keeping file size and initial load small).</p> <p>For our new client application, this results in setting the Copy Local flag to false for SalesDashboard.Client.Model (the generated model), SalesDashboard.SL.Modules.EmpOpp.ViewModels (the ViewModels from the Employee Opportunity module) and SalesDashboard.SL.Modules.EmpOpp.Views (the Views from the Employee Opportunity module) : these will be loaded when we start the application.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/________image_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="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/________image_thumb.png" width="393" height="534" /></a></p> <p>For demo purposes, this should result in the same application running in the browser as out of the browser, but remember: as this series is about separating out your application in modules & reusable code, nothing stops us from loading different modules in the Out of Browser application.  </p> <p>But wait – if the resulting applications should be the same, and we’ve separated out as much as possible, shouldn’t we simply be able to copy/paste the code from the in-browser application?  Well, let’s try that, shall we?  Simply copy/paste the MainPage.xaml (and .cs) and App.xaml (and .cs) code into the Out of Browser application, and try to run the application.  </p> <p>It compiles.  But it doesn’t run.  Although we don’t really have to change a lot – two things, actually.  Let’s look into those.</p> <h3>The first issue: errors when loading assemblies.</h3> <p>The first thing we will notice when we try to start our application is a “Type not found” error:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/______image_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="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/______image_thumb_1.png" width="643" height="244" /></a></p> <p>HeaderView is a view which is defined in an assembly we’re loading at startup: SalesDashboard.SL.Modules.EmpOpp.Views.  An error like this suggests the assembly hasn’t been loaded, so therefore, an instance of HeaderView cannot be added to the MainPage.  </p> <p>If we look into what happens at application start, something immediately becomes obvious: we’re passing in a list of assemblies to load to our ParallelAsyncProcessor instance.  Code like this will try to find these assemblies in its own startup directory – that worked fine for the in-browser application (as the assemblies are deployed to the Webhosts’ ClientBin folder), but for the Out of Browser application, this isn’t sufficient anymore.  We need to pass in the exact Uri:</p> <pre class="csharpcode"><span class="kwrd">foreach</span> (var dependency <span class="kwrd">in</span> lstDependencies) { <span class="rem">// note: pass in another variable instead of directly passing in the dependency string. </span> <span class="rem">// This ensures this new value is used when executing the parallel processes instead </span> <span class="rem">// of using the last passed-in string multiple times </span> var foo = dependency; var catalogDep = <span class="kwrd">new</span> SuperDeploymentCatalog( <span class="kwrd">new</span> Uri(<span class="str">"http://localhost/SalesDashboard.WebHost/ClientBin/"</span> + foo)); catalog.Catalogs.Add(catalogDep); EventHandler<AsyncCompletedEventArgs> handler = <span class="kwrd">null</span>; handler = (s, a) => { parallelAsyncProcesser.ProcessComplete(foo); catalogDep.DownloadCompleted -= handler; }; catalogDep.DownloadCompleted += handler; parallelAsyncProcesser.AddToParallelQueue(() => catalogDep.DownloadAsync(), foo); }</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>If we now build and run the application again, we’ll see we won’t get any errors anymore.  The problem?  We don’t get anything at all anymore: just a white page, nothing more.  What’s going on?</p> <h3>The second issue: no more errors, but a white screen instead of an application.</h3> <p>To be honest, this issue actually left me quite puzzled for a while when I first ran into it.  I started looking through my code, but couldn’t find anything out of the ordinary – after all, we’re executing the exact same code as in an in-browser application.  What I did notice was that the callback handlers, used by the SuperDeploymentCatalog, didn’t return anymore: it seemed as though the requests for external assemblies were executed, but they never returned: a callback wasn’t received anymore.  I started looking around on the internet, and finally found out how this issue can be resolved: by setting the RootVisual element before loading the assemblies on-demand (not sure anymore if it was <a href="http://10rem.net/blog" target="_blank">Pete Browns’ blog</a> or <a href="http://csharperimage.jeremylikness.com/" target="_blank">Jeremy Likness’ blog</a> where I read about this first, but both are great resources to check out).</p> <p>Apparently, setting the RootVisual ensures some behind-the-screens wiring is done, so the handlers actually return, and the applications’ code continues.  I don’t find this behavior documented anywhere on MSDN – I would actually qualify this as a bug that only happens in an Out of Browser Silverlight application.</p> <p>How can we solve this?  We cannot set the RootVisual to an instance of MainPage when the application loads, as that would result in composition & instantiation errors: the controls on our MainPage are defined in assemblies that are loaded on-demand.  What we can do is create an extra user control, and set that as the RootVisual when we start the application.  Afterwards, after our assemblies have been loaded, we add an instance of MainPage to that user control, as its only child (note: setting the RootVisual to a dummy control on load, and changing it to an instance of MainPage after the assemblies have been loaded doesn’t work either).</p> <p>To this avail, I created a user control, MainPageHost.  This is actually a simply, empty control, which only contains a LayoutRoot element.</p> <p>In Application_Startup, we set the RootVisual to an instance of MainPageHost. Once the assemblies have been loaded, I call a method on MainPageHost, LoadApplication().  This method sets the MainPageHosts’ LayoutRoot (which is a Border) child to an instance of MainPage().  This results in our application getting instantiated, which now works because all necessary assemblies have been loaded.</p> <p>Code in App.xaml.cs:</p> <pre class="csharpcode">parallelAsyncProcesser.AllProcessesCompleted += () => { <span class="rem">// dependencies have been loaded, init app startpage</span> (<span class="kwrd">this</span>.RootVisual <span class="kwrd">as</span> MainPageHost).LoadApplication(); };</pre> <p>Code in MainPageHost.xaml.cs:</p> <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 class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">void</span> LoadApplication() { LayoutRoot.Child = <span class="kwrd">new</span> MainPage(); }</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>We can now build and run our application – and everything will work as it’s supposed to work.  We’ve now created an Out of Browser client with very little effort, composing the application on-load by reusing the components we’ve separated out in the previous articles of this series.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/_image_8.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px; border-style: solid;" title="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/_image_thumb_3.png" width="599" height="359" /></a></p> <h3>Conclusion</h3> <p>In this article, we’ve seen how we can add an extra client to our solution, which reuses a lot of code from the previous articles in this series.  We’ve also learned how to work around 2 issues: passing in the correct Uri so the assemblies that have to be loaded can be found, and ensuring the necessary behind-the-screens wiring is done so the application execution can continue as expected.</p> <h3>What’s next?</h3> <p>Stay tuned for the next part of this article series, in which we’ll add a Windows Phone client to the equation! </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, HTML5). 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 Techdays in Belgium, Portugal & Finland, NDC2011, Community Day, ... Next to that, he also authored a best-selling Silverlight book, Packt Publishing's <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">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 you can contact him on Twitter via <a href="http://twitter.com/#!/KevinDockx">@KevinDockx</a>.</p> http://www.silverlightshow.net/items/Part-5-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Part-5-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx#comments http://www.silverlightshow.net/items/Part-5-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx Mon, 16 Apr 2012 13:18:00 GMT Interview with Braulio Diez on the new book 'Mastering LOB Development for Silverlight 5: A Case Study in Action' (by Packt Publishing) <p><em><a href="http://www.silverlightshow.net/book/Mastering-LOB-Development-for-Silverlight-5.aspx"><img style="border:0px; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; float: right;" title="lob_book" alt="lob_book" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/lob_book_3.png" width="176" height="209" /></a>In this short SilverlightShow interview we talk with Braulio Diez who is a co-author of the recently released e/book ‘<a href="http://www.silverlightshow.net/book/Mastering-LOB-Development-for-Silverlight-5.aspx">Mastering LOB Development for Silverlight 5: A Case Study in Action</a>’. Thanks to <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=59&Task=Click&Mode=HTML&SiteID=1&PageID=16437" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=59&Task=Get&Mode=HTML&SiteID=1&PageID=16437" width="0" height="0" style="border-width: 0px;border-style: solid;" />Packt Publishing</a>, SilverlightShow readers may now purchase this book with a 27% discount using discount code <strong>dssvl2</strong>! Enjoy!</em></p> <p><strong>SilverlightShow: </strong>Hi Braulio! We have recently announced your new book ‘<strong>Mastering LOB Development for Silverlight 5’ </strong>on <a href="http://www.silverlightshow.net/books.aspx">SilverlightShow Book Shelf</a>, and it already got an unusually high number of visits. Following this interest, and thanks to <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=59&Task=Click&Mode=HTML&SiteID=1&PageID=16437" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=59&Task=Get&Mode=HTML&SiteID=1&PageID=16437" width="0" height="0" style="border-width: 0px;border-style: solid;" />Packt Publishing</a>, we also published <strong>a free chapter from the book</strong> (<a href="http://www.silverlightshow.net/items/Mastering-LOB-Development-for-Silverlight-5-Out-of-Browser-OOB-Applications-.aspx">read here</a>). What do you think is the reason for this interest?</p> <p><strong>BD: </strong>Developing LOB applications using Silverlight is a perfect match, it allows you to develop at high speed level and base your applications on a robust architecture. This book is focused on this hot topic, we have applied on it lessons learned from real world experience.</p> <p><strong>SilverlightShow: </strong>Which parts of the book have you authored, and what would you name as the top/most interesting concepts covered in those? <strong></strong></p> <p><strong>BD: </strong>I have authored the following parts: Architecture, RIA Services, OOB and Security. The parts I like the best from this book, is the “real” life approach to RIA Services, how to manage unhandled errors, and the Architecture part (MVVM + MEF + MVVM Light toolkit).</p> <p><strong>SilverlightShow:</strong> Which do you think are the top 3 reasons for using Silverlight 5 for LOB applications?</p> <p><strong>BD: </strong>Avoid the browser versioning hell, take advantage of using C# on the client side, and separation of concerns + unit testing.</p> <p><strong>SilverlightShow: </strong>Does Silverlight 5 lack something to become a perfect technology for LOB?</p> <p><strong>BD: </strong>Does not work in an iPad or iPhone :)</p> <p><strong>SilverlightShow: </strong>There have been a lot of discussions on the future of Silverlight. What does Windows 8 mean for the future of Silverlight, and how will Win8 affect the development of LOB apps with Silverlight? </p> <p><strong>BD: </strong>Silverlight will have its place inside a desktop, if a tablet / mobile edition of the app is needed, we can take advantage of XAML + <span style="font-size: 12pt; color: #cc0000; font-family: 'times new roman', serif;"></span>C# in WinRT.</p> <p><strong>SilverlightShow: </strong>Finally, why should someone get this book, rather than try to find coverage of the same topics on the Internet?<strong></strong></p> <p>We have tried to cover in this book and end to end guide, based on real world experience, to quickly allow developers start implementing Silverlight LOB applications, it contains a complete LOB case study build gradually from start to finish throughout each chapter.</p> <p><strong>Thanks Braulio! Hope Silverlight developers will truly appreciate this book!</strong></p> http://www.silverlightshow.net/items/Interview-with-Braulio-Diez-on-the-new-book-Mastering-LOB-Development-for-Silverlight-5-A-Case-Study-in-Action-by-Packt-Publishing.aspx editorial@silverlightshow.net (Silverlight Show ) http://www.silverlightshow.net/items/Interview-with-Braulio-Diez-on-the-new-book-Mastering-LOB-Development-for-Silverlight-5-A-Case-Study-in-Action-by-Packt-Publishing.aspx#comments http://www.silverlightshow.net/items/Interview-with-Braulio-Diez-on-the-new-book-Mastering-LOB-Development-for-Silverlight-5-A-Case-Study-in-Action-by-Packt-Publishing.aspx Mon, 09 Apr 2012 12:00:00 GMT Mastering LOB Development for Silverlight 5: Out of Browser (OOB) Applications <div style="border:1px solid #dddddd;border-image: initial; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; margin-left: 10px; padding-top: 5px;"> <p>This is a free chapter of the book "<a href="http://www.silverlightshow.net/book/Mastering-LOB-Development-for-Silverlight-5.aspx">Mastering LOB Development for Silverlight 5: A Case Study in Action</a>".<br /> Thanks to <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=59&Task=Click&Mode=HTML&SiteID=1&PageID=16437" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=59&Task=Get&Mode=HTML&SiteID=1&PageID=16437" width="0" height="0" style="border-width: 0px;border-style: solid;" />Packt Publishing</a>, SilverlightShow readers may now <strong>purchase this book with a 27% discount using discount code <em>dssvl2</em></strong>! Enjoy!</p> </div> <p>LOB (Line of Business) applications executing within a web browser are fine, but if we think from the perspective of a final user, it is not the option that they would choose first. This is due to the fact that:</p> <ul> <li>Having a desktop application is easy. It can be directly accessed by double-clicking so that it is launched quickly. </li> <li>Most of the time, it is necessary to leave Silverlight sandbox application. This happens, for example, when we need to access the filesystem, or with a special hardware via COM (such as an ATM). </li> <li>It is also crucial that, when executing an application, it allows us to work offline. </li> </ul> <p>Similarly, from the point of view of the user, there are certain restrictions which are normally not well accepted, even though they are 100 percent desktop (namely WPF). It would be great to have the possibility of eliminating them:</p> <ul> <li>Installing a desktop application can carry problems, depending on the OS and installation details. It would be fantastic if they could run under a standard, which is independent from those details. </li> <li>In order to update a version already installed, it must be uninstalled and installed again. Wouldn't it be preferable that the application itself detected if there is a new version and updated automatically (even though this process is not dramatic)? </li> <li>Usually, desktop applications only work on a particular OS (that is, Windows). We would love to execute it in different platforms (for example, Mac). </li> <li>A desktop application normally has quite relaxed permissions. Hence, we dream of an application having restricted access to the hardware and software of our machine. It would only have permissions if allowed. </li> <li>A desktop application needs a given version of the .NET Framework installed on the machine. </li> </ul> <p>In this chapter, you will learn how to install and execute our applications as Out of Browser (OOB), work with elevated permissions in and out of the browser, support cross domain calls, and work with the WebBrowser control.</p> <h2>Out of Browser (OOB)</h2> <p>Out of Browser (OOB) applications are executed out of the web browser, or that is the impression they give.</p> <p>Regarding the final user, an OOB application is similar to a desktop application; the user installs it, gets a direct access icon to it, and when executed, it runs under a standard window, as shown in the following screenshot. It can even be uninstalled through the Control Panel.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_01_OOB_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="3548EN_06_01_OOB" alt="3548EN_06_01_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_01_OOB_thumb.png" width="561" height="392" /></a></p> <p>From the point of view of the Software Developer, an OOB application still runs under a hidden browser, that is, it is a Silverlight application with the same features as an application running under a browser.</p> <p>Until the arrival of Silverlight 5, the main difference with an application executing in the browser was the fact that it could work with trusted permissions and perform operations, which the sandbox normally does not allow (accessing the filesystem, executing commands via COM+, and so on).</p> <h2>Executing an application in OOB mode</h2> <p>Allowing a Silverlight application to be executed as an OOB is very easy. We just need to tick a checkbox in the project settings. Let's see how to do it.</p> <p>First, create a new Silverlight application called 01_Simple_OOB_App. In the MainPage, a text block must be added displaying the message Simple OOB App. When you execute it, it will look as a standard in-browser application, as shown in the following screenshot:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_02_OOB_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="3548EN_06_02_OOB" alt="3548EN_06_02_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_02_OOB_thumb.png" width="468" height="163" /></a></p> <p>In order to enable OOB mode, follow these steps:</p> <p>1. Right-click on the Silverlight project root. When the context menu is displayed, click on Properties:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_03_OOB_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="3548EN_06_03_OOB" alt="3548EN_06_03_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_03_OOB_thumb.png" width="425" height="102" /></a></p> <p>2. Select the Silverlight tab and tick the checkbox with the message Enable running application out of the browser:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_04_OOB_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="3548EN_06_04_OOB" alt="3548EN_06_04_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_04_OOB_thumb.png" width="590" height="292" /></a></p> <p>3. When executing the application, it still runs in the browser but, if we right-click on it, there will be a new option Install 01_Simple_OOB Application onto this computer… in the context menu, as shown in the following screenshot:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_05_OOB_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="3548EN_06_05_OOB" alt="3548EN_06_05_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_05_OOB_thumb.png" width="434" height="140" /></a></p> <p>4. If we click on that option, we get a message prompt asking to install the app, as shown in the following screenshot:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_06_OOB_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="3548EN_06_06_OOB" alt="3548EN_06_06_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_06_OOB_thumb.png" width="433" height="190" /></a></p> <p>5. Once we click OK, the application is installed and ready to be used as OOB.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_07_OOB_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="3548EN_06_07_OOB" alt="3548EN_06_07_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_07_OOB_thumb.png" width="441" height="259" /></a></p> <p>It is great to use apps as a final user, but what happens with developers? In case we want to debug our OOB application, will we have to install it every time we run the environment? Of course not. In the project properties (Context menu | Properties), the Debug tab allows us to choose that the application starts up straight in OOB mode (the Silverlight project will have to be chosen as a start-up project):</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_08_OOB_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="3548EN_06_08_OOB" alt="3548EN_06_08_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_08_OOB_thumb.png" width="590" height="314" /></a></p> <h2>Enhancing the experience—tooling up and updating</h2> <p>As we have already seen, enabling the OOB mode in our application is something quite straightforward. Nevertheless, the following doubts may have arisen:</p> <ul> <li>In some cases, I want to know if my application is running in normal or OOB mode to, for instance, show one UI or another. How can I do that? </li> <li>How can I know if the application is already installed? </li> <li>When installing from a not very intuitive contextual menu, is there any way to display our own UI in order to allow the user to install the application? </li> <li>How do I uninstall an OOB application? </li> <li>I would like to let the users install my application from a CD, eliminating the need to be connected to the Web. Is that possible? </li> <li>When a new version of my application is uploaded to the production server, is there any way to detect updates and install new versions automatically? </li> </ul> <h3>In-browser/OOB detection</h3> <p>Sometimes, the UI we want to show differs depending on whether the application is executing in the browser or as an OOB application. It may also happen that, when it is in-browser, we only want to display a button to install it.</p> <p>In order to know the mode we are working with, Silverlight offers a function on the level of the application called IsRunningOutOfBrowser, which returns true or false depending on whether the application is executing in OOB mode or not.</p> <p>To see how it works, let's go back to the previous example, TestOOB, and indicate whether the application is executing in OOB mode or not in the TextBlock we use in the main page. It can be done using the following steps:</p> <p>1. Open the project previously created (Simple_OOB_Application).</p> <p>2. Add an ID to the TextBlock of the main page (it will be named tbStatus):</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;"><Grid x:Name=<span style="color: #006080;">"LayoutRoot"</span> Background=<span style="color: #006080;">"White"</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;"><TextBlock x:Name=<span style="color: #006080;">"tbStatus"</span> Text=<span style="color: #006080;">"Simple OOB App"</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;">FontSize=<span style="color: #006080;">"16"</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;"></Grid></pre> <!--CRLF--></div> </div> <p>3. In the constructor of the page, check the value of the application variable IsRunningOutOfBrowser, which will display one of two messages depending on the state.</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 style="color: #0000ff;">public</span> MainPage()</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;"> InitializeComponent();</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> (App.Current.IsRunningOutOfBrowser == <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;"> tbStatus.Text = <span style="color: #006080;">"I'm running out of browser"</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;">else</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;"> tbStatus.Text = <span style="color: #006080;">"I'm running in browser"</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--></div> </div> <p>4. Therefore, in case we are executing in OOB mode, the following message will be displayed:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_09_OOB_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="3548EN_06_09_OOB" alt="3548EN_06_09_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_09_OOB_thumb.png" width="374" height="146" /></a></p> <h3>Detecting the application installed</h3> <p>Another common scenario arises when the application is being executed in the browser and we need to know if it has already been installed as OOB. For instance, a common example of this is when we want to display a message asking the user whether to install the application or not. We can make use of the application variable InstallState, which returns a type enumerated with one of the following values: NotInstalled, Installed, Installing, or InstallFailed.</p> <p>Thus, in the sample application that has been created, it could be checked whether the application is installed or not in the following way:</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 style="color: #0000ff;">public</span> MainPage()</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;"> InitializeComponent();</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> (App.Current.InstallState == InstallState.Installed)</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;"> tbStatus.Text = <span style="color: #006080;">"Application Installed"</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;">else</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;"> tbStatus.Text = <span style="color: #006080;">"Application not installed"</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--></div> </div> <h3>Installing the custom interface</h3> <p>As mentioned previously, installing the application from the contextual menu of our Silverlight application was not intuitive at all. Perhaps it could be possible to place a button so that the user could begin the installation. Up to what point can we customize the installation process of our Silverlight application? Silverlight allows us to launch the installation process by code, as long as it comes from a user petition (such as a click on a button). The dialog which asks if we want to install the application cannot be customized.</p> <p>To install the application, the method Install of Application must be called. Let's add this functionality to our basic sample:</p> <p>1. Add a button to the main window:</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;"><Grid x:Name=<span style="color: #006080;">"LayoutRoot"</span> Background=<span style="color: #006080;">"White"</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;"><TextBlock x:Name=<span style="color: #006080;">"tbStatus"</span> Text=<span style="color: #006080;">"Simple OOB App"</span> FontSize=<span style="color: #006080;">"16"</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;"><Button Content=<span style="color: #006080;">"Install"</span> Height=<span style="color: #006080;">"23"</span> HorizontalAlignment=<span style="color: #006080;">"Left"</span> Margin=<span style="color: #006080;">"142,55,0,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;">Name=<span style="color: #006080;">"button1"</span> VerticalAlignment=<span style="color: #006080;">"Top"</span> Width=<span style="color: #006080;">"75"</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;"></Grid></pre> <!--CRLF--></div> </div> <p>2. Subscribe to the Click event:</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;"><Button Content=<span style="color: #006080;">"Install"</span> Height=<span style="color: #006080;">"23"</span> HorizontalAlignment=<span style="color: #006080;">"Left"</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;">Margin=<span style="color: #006080;">"142,55,0,0"</span> Name=<span style="color: #006080;">"button1"</span> VerticalAlignment=<span style="color: #006080;">"Top"</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;">"75"</span> Click=<span style="color: #006080;">"button1_Click"</span> /></pre> <!--CRLF--></div> </div> <p>3. Check if the application has already been installed in the handler of the button and add the call to Install:</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 style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> button1_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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;">if</span> (Application.Current.InstallState == InstallState.NotInstalled)</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;"> Application.Current.Install();</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;"> {</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;"> MessageBox.Show(<span style="color: #006080;">"Application already installed"</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--></div> </div> <p>4. Execute the application. When you click on the new button, the dialog box asking you if you want to install the application will be displayed, as shown in the following screenshot:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_10_OOB_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="3548EN_06_10_OOB" alt="3548EN_06_10_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_10_OOB_thumb.png" width="492" height="374" /></a></p> <h3>Uninstalling an OOB application</h3> <p>To uninstall a Silverlight application, the user can choose among several options:</p> <ul> <li>They can right-click on the application and, in the contextual menu, choose the Remove this application… option, as shown in the following screenshot: </li> </ul> <p>              <a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_11_OOB_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="3548EN_06_11_OOB" alt="3548EN_06_11_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_11_OOB_thumb.png" width="324" height="169" /></a></p> <ul> <li>It can be uninstalled right from the Windows Control Panel: </li> </ul> <p>             <a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_12_OOB_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="3548EN_06_12_OOB" alt="3548EN_06_12_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_12_OOB_thumb.png" width="544" height="347" /></a></p> <p>The customization of the installation is an improvement that is pending to be added to Silverlight.</p> <h3>Offline installation</h3> <p>Sometimes, we face scenarios where it is necessary for the user to be able to install the application from a CD, or that an administrator can make an implementation. This scenario is not ideal for Silverlight applications (normally, the user downloads them from a URL, either intranet or extranet and, moreover, benefits from automatic updates).</p> <p>If you face this situation, you may wonder whether it is more convenient to orient development to WPF-Click once, or use the method explained by Tim Heuer in his blog: Installing Silverlight Offline (<a href="http://timheuer.com/blog/archive/2008/09/29/install-silverlight-2-rc0-offline.aspx">http://timheuer.com/blog/archive/2008/09/29/install-silverlight-2-rc0-offline.aspx</a>).</p> <p>Even though this method allows us to install our OOB application in a silent mode, <br /> it has certain limitations:</p> <ul> <li>If the user does not have the Silverlight plug-in installed, they will need to be connected to the Internet to download it from the Microsoft website </li> <li>The installation in silent mode is not valid for trusted OOB applications </li> </ul> <h3>Updates</h3> <p>OOB applications are installed on our own machine, which means there are a lot of advantages, such as fast boot, offline work mode, and so on. Nonetheless, what happens if we upload an update to the server? Is there a way to update our local application? Of course there is. What's more? It is possible in an easy and powerful way. Let's see it in action:</p> <p>In the app.cs file, subscribe to the event named CheckAndDownloadUpdateCompleted and, later, make the asynchronous petition to check if there is a new update and, if so, download it automatically. The following is the source code:</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 style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> Application_Startup(<span style="color: #0000ff;">object</span> sender, StartupEventArgs e)</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;"> CheckAndDownloadUpdateCompleted += </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;">new</span> CheckAndDownloadUpdateCompletedEventHandle</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;"> r(Application_CheckAndDownloadUpdateCompleted);</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;"> CheckAndDownloadUpdateAsync();</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;"> </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> <span style="color: #0000ff;">void</span> Application_CheckAndDownloadUpdateCompleted(<span style="color: #0000ff;">object</span> sender, CheckAndDownloadUpdateCompletedEventArgs 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;">{</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;"> MessageBox.Show(<span style="color: #006080;">"Application updated, please restart."</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> <table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td style="width: 20px;"> </td> <td style="width: 46px;"> </td> <td style="width: 316px;"> </p> <p> </p> <p>Updates will work as long as our XAP is not in a file that needs security.</p> <p> </p> <p> </p> <p></td> <td style="width: 20px;"> </td> </tr> </tbody> </table> </p> <h2>Offline work</h2> <p>An advantage of working with OOB applications is that, once they have been installed, it is not necessary to have an Internet connection to execute them (they are downloaded locally). What does this mean? It is possible to implement an offline work method for our applications, which permits, for example, that a user on a flight can work with the application and, later, when they have an Internet connection, they can synchronize the data with the server.</p> <p>To work offline, it is necessary to have a repository to store reference data, as well as changes or new creations. If our Silverlight applications normally work within a sandbox and we do not have access to the HDD of the local machine, what can we make use of? In such cases, we have two options: either requiring elevated permissions for our application to execute (this will be dealt with later) or making use of the Silverlight Isolated Storage.</p> <p>Isolated Storage is a virtual filesystem that allows a Silverlight application to store data in an invisible folder in the machine. By default, a Silverlight application can use 2 MB of storage. Isolated Storage is a 10 MB OOB application, but the user can <br /> be asked to increase the quota.</p> <p>Let's see a simple sample of how to read and write data in the Isolated Storage. This example is available in the online material on <a href="http://bit.ly/5gEwuM">http://bit.ly/5gEwuM</a>.</p> <p>You can create a file in the Isolated Storage using the following code:</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 style="color: #0000ff;">using</span> System.IO.IsolatedStorage;</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;">using</span> System.IO;</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;">private</span> <span style="color: #0000ff;">void</span> WriteContentToIsoStorage(<span style="color: #0000ff;">string</span> content, <span style="color: #0000ff;">string</span> filename)</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;">using</span> (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())</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;">using</span> (IsolatedStorageFileStream isfs = <span style="color: #0000ff;">new</span> IsolatedStorageFileStream(filename, FileMode.Create, isf))</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;">using</span> (StreamWriter sw = <span style="color: #0000ff;">new</span> StreamWriter(isfs))</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;"> sw.Write(content);</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;"> sw.Close();</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;"> }</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 read the information using the following code:</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 style="color: #0000ff;">using</span> System.IO.IsolatedStorage;</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;">using</span> System.IO;</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;">private</span> <span style="color: #0000ff;">string</span> LoadContentFromIsoStorage(<span style="color: #0000ff;">string</span> filename)</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;">string</span> data = String.Empty;</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;">using</span> (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())</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;">using</span> (IsolatedStorageFileStream isfs = <span style="color: #0000ff;">new</span> IsolatedStorageFileStream(filename, FileMode.Open, isf))</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;">using</span> (StreamReader sr = <span style="color: #0000ff;">new</span> StreamReader(isfs))</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;">string</span> lineOfData = String.Empty;</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;">while</span> ((lineOfData = sr.ReadLine()) != <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;"> data += lineOfData;</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;"> }</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> data;</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> <table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td style="width: 20px;"> </td> <td style="width: 46px;"> </td> <td style="width: 317px;"> </p> <p> </p> <p>To continue learning how this works, you can follow this link: http://bit.ly/qkY9UM.</p> <p> </p> <p> </p> <p></td> <td style="width: 21px;"> </td> </tr> </tbody> </table> </p> <h3>How it works</h3> <p>Normally, when data have to be obtained or updated, we communicate with the server via a web service to get or modify this information.</p> <p>To avoid this connection, we can do the following: first, get the most commonly read data and store them in a cache; second, the user creates his/her own entries, which are stored in the local repository (Isolated Storage). Once the user has an Internet connection again, offline data is sent to be synchronised in the repository.</p> <p>Offline work is not as easy as it may sound. Another book could be written only on this! If you want further information about this, we can recommend the following session by Steve Lasker, Offline Microsoft Silverlight Applications (<a href="http://bit.ly/ltIxNt">http://bit.ly/ltIxNt</a>).</p> <h2>Breaking the sandbox—trusted applications</h2> <p>Up to now, we have seen how an OOB Silverlight application runs within a sandbox. That is to say, its access to certain resources is limited or restricted. What happens if we need to perform operations that the sandbox has restricted due to safety reasons? To solve this issue, there are applications with elevated permissions:</p> <ul> <li>A trusted OOB application is a program the user trusts (similar to when a desktop application is installed on our machine). </li> <li>Its XAP file is signed with a certificate, which ensures its trustworthy origin. </li> <li>It has elevated permissions, which makes it possible, for example, to make calls to COM components, P/Invoke calls, or access the local filesystem. </li> <li>For the application to be installed/executed, it needs the express authorization of the user. </li> </ul> <h3>Enabling trusted mode</h3> <p>How can an OOB application be enabled to require elevated permissions? To configure a Silverlight program that already exists, follow these steps:</p> <p>1. Go to the Properties tab of the Silverlight Project (contextual menu of the project, Silverlight | Properties) and click on the button Out-of-Browser Settings…:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_13_OOB_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="3548EN_06_13_OOB" alt="3548EN_06_13_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_13_OOB_thumb.png" width="481" height="324" /></a></p> <p>2. A dialog is displayed, where the option Require elevated trust when running outside the browser must be checked, as shown in the following screenshot:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_14_OOB_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="3548EN_06_14_OOB" alt="3548EN_06_14_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_14_OOB_thumb.png" width="394" height="504" /></a></p> <p>After these steps, our application will be enabled as OOB trusted. However, if a user tries to install it, they will receive a warning indicating the source that published the application cannot be trusted. To eliminate this message, we will have to use our enterprise's certificate or acquire a new one (we can buy one or, if it is an intranet, our IT administrator can generate a new one). This operation can be performed from the Signing tab in the project's properties (right-click on Silverlight project | Properties | Signing).</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_15_OOB_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="3548EN_06_15_OOB" alt="3548EN_06_15_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_15_OOB_thumb.png" width="518" height="171" /></a></p> <h4>Advantages of trusted applications</h4> <ul> <li>Now we have our trusted application, which has the following additional advantages: </li> <li>We can access the filesystem of the machine (from the Silverlight 5 version). </li> <li>We can make calls to COM components. We can read or write to the registry (only current user entry), call other executable files, and so on. </li> <li>It is possible to make P/Invoke calls. </li> <li>We can make petitions to a URL, even if they are cross domain. It is not necessary that the server has a cross-domain policy enabled. </li> <li>It is possible to integrate a WebBrowser control in our application. That is, we can display HTML in our Silverlight application and interact with it. </li> <li>Real windows can be created. Normally, when new windows are created in a Silverlight application, they are a fantasy; that is to say, they are not physical windows, but they are displayed within the main one. If our application is trusted (only SL version 5), we can create floating windows and, for instance, they can be displayed on several monitors. </li> </ul> <h4>Accessing files</h4> <p>Our trusted application has access to the local filesystem (if it is Silverlight 5; in case it is Silverlight 4, it can only access folders, such as My Documents and via COM calls it's possible to gain additional access). The operations on System.IO, which previously returned safety errors, will now be executed flawlessly.</p> <p>As a sample, let's see how the content of the Program Files file can be listed in our trusted Silverlight application:</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 style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> ViewModel</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> ObservableCollection<<span style="color: #0000ff;">string</span>> DirNames { get; set; }</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> ViewModel()</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;"> DirNames = <span style="color: #0000ff;">new</span> ObservableCollection<<span style="color: #0000ff;">string</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;">// Let's try to enumerate the directories that are</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;">// under Program Files, this operation would throw an</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;">// exception if the application is not a trusted one.</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;"> DirectoryInfo di = <span style="color: #0000ff;">new</span> DirectoryInfo(<span style="color: #006080;">"C:\\Program Files"</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;">foreach</span> (var info <span style="color: #0000ff;">in</span> di.EnumerateDirectories())</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;"> DirNames.Add(info.FullName);</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;">}</pre> <!--CRLF--></div> </div> <h4>Making calls to COM+</h4> <p>We can make calls to COM components, which open plenty of doors, such as reading and (partially) writing on the registry, communicating with devices, launching apps, and even using Excel Automation.</p> <p>However, the main disadvantage of this approach is that it only works in Windows. So if our application needs to run in Mac, this code must be isolated and will not offer this functionality for that platform. <table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td style="width: 20px;"> </td> <td style="width: 46px;"> </td> <td style="width: 366px;"> </p> <p> </p> <p>If you need to detect under which OS a Silverlight application is running, you can use Environment.OSVersion.</p> <p> </p> <p> </p> <p></td> <td style="width: 21px;"> </td> </tr> </tbody> </table> </p> <p>Let's see a couple of examples of how to make these calls.</p> <h5>Writing an entry on the registry</h5> <p>In order to do so, create a new Silverlight Application project and tick the checkboxes (Enable Running application out of the browser, Out-of-Browser Settings | Require elevated trust when running outside the browser).</p> <p>Add the reference to the Microsoft.CSharp DLL (Add Reference | .NET | Microsoft.CSharp):</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_16_OOB_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="3548EN_06_16_OOB" alt="3548EN_06_16_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_16_OOB_thumb.png" width="471" height="399" /></a></p> <p>Make sure this DLL and System.Core are referenced:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_17_OOB_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="3548EN_06_17_OOB" alt="3548EN_06_17_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_17_OOB_thumb.png" width="275" height="327" /></a></p> <p>You can write the entry on the registry using the following code:</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 style="color: #0000ff;">using</span> System.Runtime.InteropServices.Automation;</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> <span style="color: #0000ff;">void</span> button1_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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;">using</span> (dynamic shell = AutomationFactory.CreateObject(<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;"> {</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.RegWrite(<span style="color: #006080;">@"HKCU\Software\MyTest"</span>, <span style="color: #006080;">""</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--></div> </div> <p>The result is as shown in the following screenshot:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_18_OOB_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="3548EN_06_18_OOB" alt="3548EN_06_18_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_18_OOB_thumb.png" width="472" height="270" /></a></p> <h5>Executing notepad from our application</h5> <p>Another interesting feature is the ability of launching other applications from our trusted application. In the following code we will launch a Notepad.</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 style="color: #0000ff;">using</span> System.Runtime.InteropServices.Automation;</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> <span style="color: #0000ff;">void</span> button1_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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;"> dynamic cmd = AutomationFactory.CreateObject(<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;"> cmd.Run(<span style="color: #006080;">@"c:\Windows\notepad.exe"</span>, 1, <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> <h4>P/Invoke</h4> <p>As an innovation, Silverlight 5 includes call support via P/Invoke. Platform Invocation Services allows managed code to call unmanaged functions that are implemented in a DLL. This is only allowed for full-trust applications.</p> <p>Let's see how this works by creating a sample, which calls a kernel32.dll method reproducing system beeps. Follow the steps mentioned next:</p> <p>1. Create a new Silverlight project (application) and configure it to be an OOB application with trusted permissions.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_19_OOB_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="3548EN_06_19_OOB" alt="3548EN_06_19_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_19_OOB_thumb.png" width="487" height="627" /></a></p> <p>2. Add a new class (by means of Add New Class) called MyBeep. Implement the Beep method of the Kernel 32 DLL.</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 style="color: #0000ff;">using</span> System.Runtime.InteropServices;</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;">class</span> MyBeep</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;"> [DllImport(<span style="color: #006080;">"User32.dll"</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;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">extern</span> Boolean MessageBeep(UInt32 beepType);</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> PlaySound(BeepTypes type)</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;">if</span> (!MessageBeep((UInt32)type))</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> Exception(<span style="color: #006080;">"Beep failed!"</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;"> }</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;">enum</span> BeepTypes : <span style="color: #0000ff;">uint</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;"> Ok = 0x00000000,</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;"> Error = 0x00000010,</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;"> Warning = 0x00000030,</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;"> Information = 0x00000040</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;">static</span> <span style="color: #0000ff;">class</span> BeepTypeExtensions</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;">static</span> BeepTypes AsBeepTypeEnum(<span style="color: #0000ff;">this</span> <span style="color: #0000ff;">string</span> beepType)</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;"> BeepTypes beepTypeEnum;</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;">return</span> Enum.TryParse(beepType,<span style="color: #0000ff;">true</span>,<span style="color: #0000ff;">out</span> beepTypeEnum)</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;"> ? beepTypeEnum</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;"> : BeepTypes.Error;</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--></div> </div> <p>3. In the main page (mainpage.xaml), add a button to be bound to the Click event as follows:</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;"><Button Content=<span style="color: #006080;">"Beep !!"</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;">Click=<span style="color: #006080;">"button1_Click"</span> /></pre> <!--CRLF--></div> </div> <p>4. In the Code-Behind (MainPage.cs), make the call to the method defined in the MyBeep class.</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 style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> button1_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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;"> MyBeep myBeep = <span style="color: #0000ff;">new</span> MyBeep();</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;"> myBeep.PlaySound(BeepTypes.Information);</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> <table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td style="width: 20px;"> </td> <td style="width: 46px;"> </td> <td style="width: 343px;"> </p> <p> </p> <p>If an exception appears when executing the action, check the application settings and make sure that it is running in OOB trusted mode.</p> <p> </p> <p> </p> <p></td> <td style="width: 21px;"> </td> </tr> </tbody> </table> </p> <h4>Cross-domain calls</h4> <p>When executing our Silverlight application within the sandbox, we can make calls to services, or ask for resources, which are in our domain. However, if we try to access resources in a different domain (namely a feed of Apple's film trailers) this call can return an error since, due to safety reasons, these calls are restricted unless the web service authorizes them explicitly. The following are the solutions we have within sandbox:</p> <ul> <li>The server may have an XML file with the cross-domain policy indicating we have access to these resources. It can be checked by launching a query to the Apple feed and using the Fiddler packages sniffer. We will then realize if this server exposes a cross-domain policy. </li> <li>It is possible to implement a service in our server acting as a proxy. The bad thing about this approach is that we overload the server and the response to the client is slower. </li> </ul> <p>If our application is executed as trusted, this restriction does not exist. We can make the petition to a cross domain without having the cross-domain policy enabled. For instance, we can make a query to the Apple feed to check new cinema openings.</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 style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> button1_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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;"> WebClient wc = <span style="color: #0000ff;">new</span> WebClient();</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;"> wc.DownloadStringCompleted += <span style="color: #0000ff;">new</span> DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);</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;"> wc.DownloadStringAsync(<span style="color: #0000ff;">new</span> Uri(<span style="color: #006080;">"http://www.apple.com/trailers/home/xml/current.xml"</span>, UriKind.Absolute));</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;">void</span> wc_DownloadStringCompleted(<span style="color: #0000ff;">object</span> sender, DownloadStringCompletedEventArgs 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;">{</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;"> MessageBox.Show(e.Result);</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> <h4>WebBrowser control</h4> <p>Another interesting control we can only use in trusted OOB applications is the WebBrowser control. This allows us to view HTML pages within our Silverlight application. Besides, if the page is in the same domain, we can even interact with it via Silverlight | JavaScript.</p> <h5>How it works</h5> <p>Let's check how this control works by creating a simple example:</p> <p>1. Create a new Silverlight project (application) and configure it so that it is executed as an OOB application with trusted permissions.</p> <p>2. In the XAML, add the namespace System.Windows.Controls and instantiate the control:</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;"><UserControl x:Class=<span style="color: #006080;">"WebBrowser.MainPage"</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;"> xmlns=<span style="color: #006080;">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</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;"> xmlns:x=<span style="color: #006080;">"http://schemas.microsoft.com/winfx/2006/xaml"</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;"> xmlns:d=<span style="color: #006080;">"http://schemas.microsoft.com/expression/blend/2008"</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;"> xmlns:mc=<span style="color: #006080;">"http://schemas.openxmlformats.org/</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;"> markup-compatibility/2006"</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;"> xmlns:controls=<span style="color: #006080;">"clr-namespace:System.Windows.Controls;</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;"> assembly=System.Windows"</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;">mc:Ignorable=<span style="color: #006080;">"d"</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;">d:DesignHeight=<span style="color: #006080;">"300"</span> d:DesignWidth=<span style="color: #006080;">"400"</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;"><Grid x:Name=<span style="color: #006080;">"LayoutRoot"</span> Background=<span style="color: #006080;">"White"</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;"><controls:WebBrowser Source=<span style="color: #006080;">"http://www.bing.com"</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;"></Grid></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;"></UserControl></pre> <!--CRLF--></div> </div> <p>3. The result we obtain is shown in the following screenshot:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_20_OOB_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="3548EN_06_20_OOB" alt="3548EN_06_20_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_20_OOB_thumb.png" width="655" height="515" /></a></p> <p>Limitations to take into account:</p> <ul> <li>Control is placed on top of the ZOrder. In case we want to show a ChildWindow, for example, this will not be visible at first. To give it visibility, we need to create a rectangle using a WebBrowser Brush, make a static picture to the WebBrowser Control content and, when the dialog box is shown, hide the WebBrowser showing our rectangle. </li> <li>For safety reasons, we cannot capture the moment when the user navigates from one page to another; neither can we make JavaScript calls from Silverlight if the page belongs to a different domain. </li> <li>It is a heavy control, so it is not a good idea to create and destroy it dynamically quite often. </li> </ul> <h4>Real windows</h4> <p>Another advantage of trusted OOB applications is the fact that they can show physical windows.</p> <p>At the moment, these windows are not modal in Silverlight 5. The following is how it works:</p> <p>1. Create a Windows object and assign the content property of this control to <br /> a given UserControl.</p> <p>2. Then, we see how this sort of window can be displayed:</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 style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> button1_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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;"> Window wnd = <span style="color: #0000ff;">new</span> Window();</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;"> wnd.Width = 500;</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;"> wnd.Height = 350;</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;"> wnd.Title = <span style="color: #006080;">"This is a test 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;"> <span style="color: #008000;">//We indicate here a custom user control to display in the</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;">//new 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;"> wnd.Content = <span style="color: #0000ff;">new</span> MyControl();</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;"> wnd.Visibility = Visibility.Visible;</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>3. The result is shown in the following screenshot:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_21_OOB_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="3548EN_06_21_OOB" alt="3548EN_06_21_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_21_OOB_thumb.png" width="677" height="363" /></a></p> <h2>In-browser trusted applications</h2> <p>Having trusted applications, which are executed as if they were desktop applications, is a powerful and interesting idea, but what happens if we need to have elevated permissions for applications running in the browser? For instance, a bank's intranet.</p> <p>Silverlight 5 incorporates in-browser trusted applications, whose main features are as follows:</p> <ul> <li>It is a specific functionality for enterprise applications. </li> <li>The administrator controls which applications can be executed via <br /> group policy. </li> <li>The user is not asked and neither is the application installed. It is marked <br /> as valid, so it will be executed by the administrator. </li> <li>It can be integrated as part of an HTML website, without the need to give elevated permissions to the entire site. </li> </ul> <p>On the other hand, the doubt arises, when developing, shall we create our own test certificate? The answer is no. If we execute from localhost, the restriction is not applied.</p> <p>Thus, in the example that was previously implemented (getting the content of C:\Program Files), we only need to select the properties of our Silverlight project (right-click on Silverlight | Properties) and select the option Require elevated trust when running in-browser, as shown in the following screenshot:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_22_OOB_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="3548EN_06_22_OOB" alt="3548EN_06_22_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_22_OOB_thumb.png" width="487" height="441" /></a></p> <p>When executing the application, it can be seen running flawlessly within the browser.</p> <p>As we pointed out earlier, if the application in production is displayed, it will fail as it is not executed from localhost. The following are the necessary steps to avoid it:</p> <ul> <li>The XAP file has to be signed with a certificate (this can be seen in depth in Chapter 11, Security). </li> <li>The network administrator has to specify a setting for the trusted in-browser applications to be executed in all machines. Particularly, the flag of the registry entry HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Silverlight\AllowElevatedTrustAppsInBrowser must have the value of 1. </li> <li>The network administrator has to add the certificate in which the XAP has been signed with as a trusted certificate (CurrentUser\Trusted Publishers). </li> </ul> <p>For more information about the display process, please visit the link <a href="http://bit.ly/kKbdpl">http://bit.ly/kKbdpl</a>.</p> <p> <table border="0" cellspacing="0" cellpadding="0"> <tbody> <tr> <td style="width: 20px;"> </td> <td style="width: 46px;"> </td> <td style="width: 322px;"> </p> <p> </p> <p>In order to know if the application is running with elevated permissions, check the flag Application.Current.HasElevatedPermissions.</p> <p> </p> <p> </p> <p></td> <td style="width: 21px;"> </td> </tr> </tbody> </table> </p> <h2>LOB application case study: applying what we have learned</h2> <p>As final users, one of the disadvantages of using web applications is the fact that we have to remember URLs, open the browser, and so on. Isn't it easier to double-click on a desktop icon and run an application? That is what has been added to our booking application:</p> <ul> <li>We detect whether it is running or not within the browser </li> <li>If so, an option is shown to install the application as OOB </li> <li>Then, we install the application as OOB </li> </ul> <p>Thus, when executing the application within the browser, a new option is added in the navigation menu, as shown in the following screenshot:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_23_OOB_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="3548EN_06_23_OOB" alt="3548EN_06_23_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_23_OOB_thumb.png" width="233" height="89" /></a></p> <p>When clicking the Install button, the confirmation dialog appears and the application gets installed (then, go to the desktop icon and execute it).</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_24_OOB_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="3548EN_06_24_OOB" alt="3548EN_06_24_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_24_OOB_thumb.png" width="389" height="171" /></a></p> <p>It is necessary to bear in mind that the application item has been customized. This can be set up in the project properties, Out-of-Browser Settings.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_25_OOB_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="3548EN_06_25_OOB" alt="3548EN_06_25_OOB" src="http://www.silverlightshow.net/Storage/Users/SilverlightShow/3548EN_06_25_OOB_thumb.png" width="496" height="639" /></a></p> <h2>Summary</h2> <p>The capabilities offered by Out of Browser (OOB) applications are amazing. If we also add the possibility of elevating permission (in-browser and OOB trusted), the result is a light web application that can be almost as powerful and functional as a desktop application. Remember this chapter when a client indicates non-standard requirements of a web application (such as the integration of the application in an ATM, accessing the local filesystem, and so on). Anyway, before accepting, make the possible concept tests and ensure the functionality is covered.</p> <h3>Additional resources</h3> <p>If you need to dive deeper into any of the features presented in this chapter, you can check the following links:</p> <ul> <li>How far can I get using COM+? This post by Justin Angels summarizes it nicely at <a href="http://bit.ly/4Ama4H">http://bit.ly/4Ama4H</a> </li> <li>In-browser http://bit.ly/kKbdpl and settings <a href="http://bit.ly/oKFbzG">http://bit.ly/oKFbzG</a> </li> <li>P/Invoke, how does it work? <a href="http://bit.ly/r2DTQF">http://bit.ly/r2DTQF</a> </li> <li>P/Invoke and Silverlight, an excellent introduction by Vikram Pendse <a href="http://bit.ly/qI3XhN">http://bit.ly/qI3XhN</a> </li> <li>How to create physical windows, by Pete Brown <a href="http://bit.ly/gZ4w7S">http://bit.ly/gZ4w7S</a> </li> </ul> http://www.silverlightshow.net/items/Mastering-LOB-Development-for-Silverlight-5-Out-of-Browser-OOB-Applications-.aspx editorial@silverlightshow.net (Silverlight Show ) http://www.silverlightshow.net/items/Mastering-LOB-Development-for-Silverlight-5-Out-of-Browser-OOB-Applications-.aspx#comments http://www.silverlightshow.net/items/Mastering-LOB-Development-for-Silverlight-5-Out-of-Browser-OOB-Applications-.aspx Tue, 03 Apr 2012 14:57:57 GMT Part 4: Developing for a multitude of clients: strategies for code reuse and keeping costs in check. <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Part-4-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.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/Part-4-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" data-count="horizontal" data-text="Developing for a multitude of clients Part 4: Strategies for code reuse and keeping costs in check" data-url="http://slshow.net/GCpo2Y">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Part-4-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p>Welcome to the fourth part of this article series on strategies for designing your application for a multitude of different clients.  In the <a href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" target="_blank">first part</a>, we’ve looked into the <strong>business case & some general concerns</strong>, and in the <a href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check-part-2.aspx" target="_blank">second part</a>, we made a choice for a <strong>service layer: WCF RIA Services</strong>.  In the <a href="http://www.silverlightshow.net/items/Part-3-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" target="_blank">third part</a>, we’ve seen how we can use <strong>MEF for on demand loading & code reuse</strong> across different clients. </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/items/WCF-RIA-Services-Part-1-Getting-Started.aspx">10-part Article Series: WCF RIA Services</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/Part-2-of-the-Webinar-Metro-and-WinRT.aspx">Recent Webinar Recording: Metro and WinRT for the Silverlight/WPF Developer: Part 2</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_collections.aspx">Kevin's ebook: Working with Collections in WCF RIA Services</a></li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/wcf_ria_collections.aspx"><img style="border:0px solid; border-image: initial;" alt="Working with Collections in WCF RIA Services: Ebook" src="http://www.silverlightshow.net/Storage/Ebooks/wcfriacoll_ebook_cover.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>However, I left out a few things in that article: loading the Views on demand (as it requires extensions to the Silverlight Navigation framework to navigate to Views in an assembly that’s loaded on demand), and loading multiple assemblies on demand (as we need an async component loader for that, to ensure we can load these assemblies at the same time instead of one by one).  This article will deal with these two concerns.</p> <p>You can <a href="http://www.silverlightshow.net/Storage/Sources/MultipleClientsPart4.zip">download the source code for this article here</a> (you can log in to the demo application with <strong>pete.campbell@madmen.com / abc@123</strong>).</p> <p> </p> <h3>Deciding what to load on demand</h3> <p>First of all, we need to decide what exactly we want to load on demand, and what we’ll keep as a regular reference.  As you can see in the following screenshot, the main project requires quite a few assemblies:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/_______image_2.png"><img style="border:0px; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" title="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/_______image_thumb.png" width="351" height="532" /></a></p> <p>What will we load on demand, and what will we keep as reference? You could load almost anything on demand, if you're really set on diminishing the initial load of your application (the size of the XAP), however: I like to keep things a bit more realistic. Take, for example, an assembly like System.Windows.Interactivity. This one contains the classes used to enable commands on any event, like a command on the SelectionChanged event of a ListBox (as you can see throughout the application) - does it make sense to load this on demand?</p> <p>Well, it depends. Some might say it does: after all, theoretically you could have a part of an application that never uses any of the classes from that assembly. And it does keep down the initial load. As an added bonus, it even allows your assembly to be cached automatically by the browser (have a look at the caching overview article for more information on this).</p> <p>On the other hand: this might qualify as overkill. Does it really make sense to separate out an assembly that will be used by almost any module, like System.Windows.Interactivity? Or an assembly that will be used by each ViewModel, like the MVVM Light assemblies? I would argue it doesn't - a matter of "it's not because we can do this, that we should."</p> <p>As a rule of thumb, I like to separate out the assemblies (/classes) that belong to specific modules and aren't used throughout the application. A model, used only by the Employee Opportunity module, would be something that's preferably loaded on demand. The authentication model, used regardless of who's using the application? Not so much. A self-created assembly containing commonly used code, or an existing assembly that contains classes used throughout the application (like System.Windows.Interactivity, or in our case: the MVVM Light-related assemblies), are typically assemblies I'd keep as a reference instead of loading on demand.</p> <p>With this in mind, we can get going. And we'll immediately bump into 2 issues…</p> <p> </p> <h3>Loading a multitude of assemblies at startup.</h3> <p>The first issue: we now have to load a multitude of assemblies when the application starts, and it's only after all these assemblies have been loaded that we can continue with our application execution (in this case: set the RootVisual to an instance of MainPage). The simplest way to solve this is to call the loading of the next assembly in the completed handler of the previous async call, and continue doing this until all the necessary assemblies have been loaded… While this could be a valid approach with 2 or 3 assemblies, the code becomes very cluttered when we need to load more assemblies. Besides that, assemblies will be loaded one by one instead of in parallel - which is a shame, as the last option would result in faster application startup.</p> <p>What we need is a way to execute multiple asynchronous calls, in parallel, and start another action after all these calls have completed.</p> <p>Luckily, this can be done with a bit of custom coding. We'll create a helper class, ParallelAsyncProcessor, in Framework.Silverlight. An instance of this class is initialzed, after which we’ll add the actions to be executed by calling the AddToParallelQueue method.  To start executing them, we’ll call the StartParallelProcessing method, which will start executing them in parallel (as they're async calls). When an action completes, the action should be taken from the list of actions, and when all actions have been completed, another action, AllProcessesCompleted, will be executed.  This is typically where we’ll continue with the execution of the application.</p> <p>The following code illustrates the helper class:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> ParallelAsyncProcesser { <span class="kwrd">public</span> Action AllProcessesCompleted; <span class="kwrd">public</span> Dictionary<<span class="kwrd">object</span>, Action> Processes; <span class="kwrd">private</span> <span class="kwrd">int</span> _numberOfActions = 0; <span class="kwrd">public</span> ParallelAsyncProcesser() { Processes = <span class="kwrd">new</span> Dictionary<<span class="kwrd">object</span>, Action>(); _numberOfActions = 0; } <span class="kwrd">public</span> <span class="kwrd">void</span> StartParallelProcessing() { <span class="kwrd">foreach</span> (var action <span class="kwrd">in</span> Processes.Values) { action.Invoke(); } } <span class="rem">/// <summary></span> <span class="rem">/// Add an action to the parallel queue</span> <span class="rem">/// </summary></span> <span class="rem">/// <param name="action">The action to invoke</param></span> <span class="rem">/// <param name="identifier">An optional identifier. Add this if you want to ensure </span> <span class="rem">/// the correct action is removed from the queue. </span> <span class="rem">/// If not, the processer acts as a counter.</param></span> <span class="kwrd">public</span> <span class="kwrd">void</span> AddToParallelQueue(Action action, <span class="kwrd">object</span> identifier = <span class="kwrd">null</span>) { _numberOfActions++; <span class="kwrd">if</span> (identifier == <span class="kwrd">null</span>) { Processes.Add(_numberOfActions, action); } <span class="kwrd">else</span> { Processes.Add(identifier, action); } } <span class="rem">/// <summary></span> <span class="rem">/// Typically executed in the completed method of an async call</span> <span class="rem">/// </summary></span> <span class="rem">/// <param name="identifier">When this is passed in, the correct action will be removed </span> <span class="rem">/// from the internal dictionary. </span> <span class="rem">/// If not, any action will be removed.</param></span> <span class="kwrd">public</span> <span class="kwrd">void</span> ProcessComplete(<span class="kwrd">object</span> identifier = <span class="kwrd">null</span>) { _numberOfActions--; <span class="kwrd">if</span> (identifier == <span class="kwrd">null</span>) { <span class="rem">// remove any</span> Processes.Remove(Processes.Count); } <span class="kwrd">else</span> { Processes.Remove(identifier); } <span class="rem">// invoke action on all processes complete</span> <span class="kwrd">if</span> (_numberOfActions == 0 && AllProcessesCompleted != <span class="kwrd">null</span>) { AllProcessesCompleted.Invoke(); } } }</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>To use this, we need to change our Application_Startup method a bit. We need a list of assemblies that have to be loaded (this list can vary depending on custom application logic, like the users' rights - if that's the case, these assemblies will of course have to be loaded after the user logs in instead of in the Application_Startup method). We run through this list, and add the DownloadAsync method to the list of actions that have to be executed. We also ensure actions are removed from the list by calling ProcessComplete in the completed handler.</p> <p>Once the last action has been fully completed, the AllProcessesCompleted method will be executed. The method is executed automatically, and is used to set the RootVisual to a new instance of MainPage.  The code for this looks as such:</p> <pre class="csharpcode"><span class="rem">// create a list of external dependencies</span> List<<span class="kwrd">string</span>> lstDependencies = <span class="kwrd">new</span> List<<span class="kwrd">string</span>>() { <span class="str">"SalesDashboard.Client.Model.dll"</span>, <span class="str">"SalesDashboard.SL.Modules.EmpOpp.ViewModels.dll"</span>, <span class="str">"SalesDashboard.SL.Modules.EmpOpp.Views.dll"</span> }; <span class="rem">// instantiate a new aggregate catalag</span> var catalog = <span class="kwrd">new</span> AggregateCatalog(); <span class="rem">// instantiate a new parallel async processer</span> ParallelAsyncProcesser parallelAsyncProcesser = <span class="kwrd">new</span> ParallelAsyncProcesser(); <span class="kwrd">foreach</span> (var dependency <span class="kwrd">in</span> lstDependencies) { <span class="rem">// note: pass in another variable instead of directly passing in the dependency string.</span> <span class="rem">// This ensures this new value is used when executing the parallel processes instead </span> <span class="rem">// of using the last passed-in string multiple times </span> var foo = dependency; var catalogDep = <span class="kwrd">new</span> SuperDeploymentCatalog(foo); catalog.Catalogs.Add(catalogDep); EventHandler<AsyncCompletedEventArgs> handler = <span class="kwrd">null</span>; handler = (s, a) => { parallelAsyncProcesser.ProcessComplete(foo); catalogDep.DownloadCompleted -= handler; }; catalogDep.DownloadCompleted += handler; parallelAsyncProcesser.AddToParallelQueue(() => catalogDep.DownloadAsync(), foo); } parallelAsyncProcesser.AllProcessesCompleted += () => { <span class="rem">// dependencies have been loaded, init app startpage</span> <span class="kwrd">this</span>.RootVisual = <span class="kwrd">new</span> MainPage(); }; <span class="rem">// start fetching the dependencies, parallel instead of one by one</span> parallelAsyncProcesser.StartParallelProcessing();</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 like that, we can now load assemblies on demand, in parallel.</p> <p> </p> <h3>Navigating to a View residing in an assembly that's been loaded on demand.</h3> <p>The second issue we run into actually consists of 2 related issues.</p> <p>First, some background information: we're using a View-first approach. This means View is initialized, and it is provided with a DataContext - the ViewModel - by another component (MEF, in this case - the View isn't responsible for initializing the ViewModel). To ensure the View is initialized, we simply place it on MainPage (for the header) or set it as source for the frame on the MainPage. I'll get into the second part immediately, as this has to do with another challenge, but solving the first problem might not be obvious either: after all, how are you going to place a View on a page if you haven't got a reference to the assembly containing the View? Obviously, your code simply won't compile.</p> <p>Well, let's think back at why exactly we're loading assemblies on demand: it enables shorter initial loading times, makes it easier to roll out changes (you don't have to recompile your complete XAP), but in our case, the most important reason was: allowing reuse of code (the modules) & composability. So how can we reach our goal? It's actually pretty easy: we're going to add a reference to the assembly containing the Views, so we can add an instance of one to the MainPage, AND we're still going to load that assembly on demand. The trick is the "Copy local" value in your reference properties. If you put this on false, this assembly will not be packaged in the XAP (thus keeping your XAP smaller), and thus has to be loaded on demand.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/_____image_4.png"><img style="border:0px; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" title="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/_____image_thumb_1.png" width="433" height="138" /></a></p> <p>Note that we use the “Copy Local = false” technique extensively, especially in the assemblies we load on demand – in fact, if you look at the project containing the Views we’ll load on-demand, you’ll notice that all the references are set to “Copy local = false”, as they all are either references in the main project, or loaded on-demand. </p> <p>If we now build and run our application and look into the XAP, we'll notice it no longer contains the View assembly: this is now loaded when the application is launched. After that, MainPage is initialized, and the Header will be shown.</p> <p>But we immediately run into another challenge, the second of our 2 view-related issues: we get an error on our Frame: apparently, it's not possible to navigate to a View in another assembly when that assembly is loaded on demand. Can we solve this?</p> <p> </p> <h3>Introducing: a custom Content Loader & View Factory</h3> <p>In Silverlight 4, a new interface was introduced: INavigationContentLoader.  Going into the details of this would lead us too far for this article, but if you want, you can read about it <a href="http://msdn.microsoft.com/en-us/library/system.windows.navigation.inavigationcontentloader(v=vs.95).aspx" target="_blank">on MSDN</a> or in <a href="http://www.silverlightshow.net/items/Authorization-in-Silverlight-part-1-Authorized-navigation.aspx" target="_blank">one of my previous articles on Authorized Navigation</a> (where a custom implementation of this interface is used). By writing our own implementation of this, we can decide how exactly our Views should be loaded.  A few implementations and techniques using this interface already exist: David Poll <a href="http://www.davidpoll.com/2010/02/01/on-demand-loading-of-assemblies-with-silverlight-navigation-revisited-for-silverlight-4-beta/" target="_blank">described one on his blog</a>, and Pencho Popadiyn wrote <a href="http://www.silverlightshow.net/items/Navigating-between-Pages-in-Different-Xaps-by-using-MEF.aspx" target="_blank">an article about it on Silverlight Show</a>.  However, we’re not using MEF to export our Views: we’re already using MEF to set the DataContext of our Views to an instance of a certain ViewModel, which therefore makes it quite a hassle to export the Views as well – they’re already dependent on importing a ViewModel from another plugged-in assembly.  So we’ll need another technique.</p> <p>What we need is “something”, a component, to provide us with an instance of the View we need.  We need a component that “knows” about these views, so it can instantiate them with a bit of reflection, and can return them to the custom NavigationContentLoader.  So, in essence: we need a ViewFactory, which should reside in our View assembly, and which we can import using MEF in our NavigationContentLoader.  This ViewFactory instance is then used by the NavigationContentLoader to provide us with the View instance we need.</p> <p>Let’s start with the ViewFactory:</p> <pre class="csharpcode"><span class="kwrd">namespace</span> Framework.Silverlight { [Export(<span class="kwrd">typeof</span>(IViewFactory))] <span class="kwrd">public</span> <span class="kwrd">class</span> ViewFactory : IViewFactory { <span class="kwrd">public</span> Page GetViewInstance(<span class="kwrd">string</span> className) { <span class="kwrd">try</span> { var instance = Activator.CreateInstance(Type.GetType(className)); <span class="kwrd">return</span> instance <span class="kwrd">as</span> Page; } <span class="kwrd">catch</span> (Exception ex) { <span class="kwrd">return</span> <span class="kwrd">null</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>As you can see, this is pretty straightforward.  It expects a class name, and will return an instance of that class (a View), using some reflection, to whichever component we’re calling the ViewFactory from.</p> <p>On to the custom content loader.  First, we import all instances of ViewFactory.  As we need to ensure our application can work with different assemblies containing Views, we need to use ImportMany.  </p> <pre class="csharpcode">[ImportMany(<span class="kwrd">typeof</span>(IViewFactory))] <span class="kwrd">public</span> List<IViewFactory> ViewFactories { get; set; }</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>In BeginLoad, we try to get an instance of a View back from one of the imported ViewFactory instances (note that this code is used to illustrate a technique – for production-ready code, you’ll probably want to refine the way we fetch the class name some more). </p> <pre class="csharpcode"><span class="kwrd">public</span> IAsyncResult BeginLoad(Uri targetUri, Uri currentUri, AsyncCallback userCallback, <span class="kwrd">object</span> asyncState) { NavigationAsyncResult ar = <span class="kwrd">new</span> NavigationAsyncResult(userCallback, asyncState); <span class="kwrd">string</span> fullUri = targetUri.ToString(); <span class="kwrd">string</span> className = (fullUri.Substring(1, fullUri.IndexOf(<span class="str">';'</span>) - 1) + <span class="str">"."</span> + fullUri.Substring(fullUri.LastIndexOf(<span class="str">"/"</span>) + 1, fullUri.IndexOf(<span class="str">".xaml"</span>) - fullUri.LastIndexOf(<span class="str">"/"</span>) - 1)); <span class="rem">// use one of the the ViewFactories to load</span> <span class="kwrd">foreach</span> (var factory <span class="kwrd">in</span> ViewFactories) { Page page = factory.GetViewInstance(className); <span class="kwrd">if</span> (page != <span class="kwrd">null</span>) { ar.Result = page; ar.CompleteCall(<span class="kwrd">false</span>); <span class="kwrd">return</span> ar; } } <span class="rem">// in case nothing is found...</span> <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentException(<span class="str">"No view found in any imported assembly with classname "</span> + className); <span class="kwrd">return</span> <span class="kwrd">null</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>In EndLoad, we ensure our custom loader logic is used instead of the default loader:</p> <pre class="csharpcode"><span class="kwrd">public</span> LoadResult EndLoad(IAsyncResult asyncResult) { <span class="kwrd">if</span> (asyncResult <span class="kwrd">is</span> NavigationAsyncResult) <span class="kwrd">return</span> <span class="kwrd">new</span> LoadResult((asyncResult <span class="kwrd">as</span> NavigationAsyncResult).Result); <span class="kwrd">else</span> <span class="kwrd">return</span> _loader.EndLoad(asyncResult); }</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> And that’s it!  Our custom content loader is ready.  All that’s left now is making sure it’s used, which we can do by adjusting our XAML code a little bit, as such: <pre class="csharpcode"><span class="kwrd"><</span><span class="html">sdk:Frame</span> <span class="attr">x:Name</span><span class="kwrd">="mainFrame"</span> <span class="attr">Background</span><span class="kwrd">="Transparent"</span> <span class="attr">JournalOwnership</span><span class="kwrd">="Automatic"</span> <span class="attr">BorderThickness</span><span class="kwrd">="0"</span> <span class="attr">Margin</span><span class="kwrd">="50,0,50,0"</span> <span class="attr">Source</span><span class="kwrd">="/LoginView"</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">sdk:Frame.ContentLoader</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">fw:CustomXAPContentLoader</span><span class="kwrd">></</span><span class="html">fw:CustomXAPContentLoader</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">sdk:Frame.ContentLoader</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">navigation:Frame.UriMapper</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">sdk:UriMapper</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">sdk:UriMapping</span> <span class="attr">Uri</span><span class="kwrd">="/{page}"</span> <span class="attr">MappedUri</span><span class="kwrd">="/SalesDashboard.SL.Modules.EmpOpp.Views;component/{page}.xaml"</span> <span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">sdk:UriMapper</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">navigation:Frame.UriMapper</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">sdk:Frame</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>We’ve now created a way to ensure our View assembly can be loaded on demand, and we can still navigate to these Views even though they reside in a different assembly, by extending the Navigation framework.</p> <p> </p> <h3>Conclusion</h3> <p>In this article, we've seen some best practices on how you can separate your app into different modules so this code can be reused. We've tackled a few issues, or rather: challenges that come with these techniques, by creating a custom loader queue, and extending the Silverlight Navigation framework in such a way that it allows navigating to View in assemblies that are loaded on demand. We've now got a truly composable application that can consist of various modules, each easily reusable by other client applications.</p> <p>In the next part, we'll add another client to the equation and see how exactly we can reuse all the separated-out components from the last few articles: an Out of Browser Silverlight client.</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, HTML5). 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 Techdays in Belgium, Portugal & Finland, NDC2011, Community Day, ... Next to that, he also authored a best-selling Silverlight book, Packt Publishing's <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">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 you can contact him on Twitter via <a href="http://twitter.com/#!/KevinDockx">@KevinDockx</a>.</p> http://www.silverlightshow.net/items/Part-4-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Part-4-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx#comments http://www.silverlightshow.net/items/Part-4-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx Tue, 20 Mar 2012 06:50:00 GMT Silverlight and Sharepoint working together: event receivers in Silverlight <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-event-receivers-in-Silverlight.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/Silverlight-and-Sharepoint-working-together-event-receivers-in-Silverlight.aspx" data-count="horizontal" data-text="Reading article: #Silverlight & #Sharepoint working together: event receivers in Silverlight" data-url="http://slshow.net/zD5k8c">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-event-receivers-in-Silverlight.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p style="text-align: justify;">In the previous articles of this series (see the panel <strong>From this series</strong> on the right) we dealt with some introductory aspects such as how to integrate Silverlight into Sharepoint, then we built a Silverlight menu capable of interacting with a Sharepoint site as an example. Throughout this journey we have introduced some basic concepts of Sharepoint useful for Silverlight developers. </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>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/Discover-Sharepoint-with-Silverlight.aspx">The article series: Discover Sharepoint with Silverlight</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-the-Silverlight-SharePoint-Web-Parts-part-1.aspx">The article series: Silverlight and Sharepoint working together</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/sharepoint.aspx">Ebook: Discover Sharepoint with Silverlight (also in MOBI and EPUB):</a> </li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/sharepoint.aspx"><img style="border:0px solid; border-image: initial;" alt="Discover Sharepoint with Silverlight Ebook" src="http://www.silverlightshow.net/Storage/sharepoint_sml.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> Now it's time to dig into it at full throttle facing more advanced concepts. In this article we will become familiar with the Sharepoint event receivers, a cool feature which allows the user to be notified about various events occurring inside a Sharepoint environment. An example is the possibility to receive the notification of an item added to a list. Unfortunately, the mechanism works at server side and that means that there is no “out of the box” possibility to use the feature directly in a Silverlight application. <p style="text-align: justify;">Nevertheless, we will find a way to make the event receivers available in a Silverlight web part in order to give a new dimension of interactivity to a Sharepoint solution.</p> <p style="text-align: justify;">As an example we will create a small application to invite our colleagues to a coffee break and get a close to real time answer. This will involve the creation of a wcf service with a service contract for a Sharepoint solution and a service contract for a Silverlight web part. Both contracts are duplex service contracts. Now you may be like “all this mess for a silly application to get someone together for a coffee break?” In fact, it may sound useless but it is not. Event receivers are a great feature of Sharepoint and exporting them into a Silverlight web part opens a very interesting perspective.</p> <h3>The “Coffee break” application</h3> <p style="text-align: justify;">Let’s suppose we want to create a small application running in a Sharepoint site (a kind of widget) to quickly organize a coffee break with colleagues. We want to be able to select a time and send an invitation to our user’s group. The other users should be notified quite immediately and they should be able to accept or turn down the invitation. Eventually we should be notified about all the confirmations received from our colleagues. All this without the need to refresh any page.</p> <p>The images below sum it all up:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/applicationsdr_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="applicationsdr" alt="applicationsdr" src="http://www.silverlightshow.net/Storage/Users/walterf/applicationsdr_thumb.png" width="500" height="708" /></a></p> <p> </p> <p>A <strong>video showing the application in action </strong>is available <a href="http://www.silverlightshow.net/video/Video-for-Coffee-Break-App.aspx" target="_blank">here</a>.<strong></strong></p> <p>The <strong>source code of the application</strong> is available <a href="http://www.silverlightshow.net/Storage/Sources/EventReceiverSilverlight.zip">here</a>.</p> <p> </p> <h3>The big picture</h3> <p style="text-align: justify;">In the introduction I gave some clues. I mentioned Sharepoint event receivers, a wcf service with duplex service contracts, a Sharepoint solution and a Silverlight web part. Let me put together the pieces of the mosaic starting with the event receivers. (As usual Sharepoint developers can skip this part)</p> <p style="text-align: justify;"> </p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/__sharepoint_2010_icon_2.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="sharepoint_2010_icon" alt="sharepoint_2010_icon" src="http://www.silverlightshow.net/Storage/Users/walterf/__sharepoint_2010_icon_thumb.jpg" width="64" height="63" /></a><em> Event receivers are a convenient way to get notifications about Sharepoint events. The trappable events most used are synthesized in the tables below:</em></p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/ListEventsTable_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="ListEventsTable" alt="ListEventsTable" src="http://www.silverlightshow.net/Storage/Users/walterf/ListEventsTable_thumb_1.png" width="686" height="154" /></a></p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/ListItemsTable_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="ListItemsTable" alt="ListItemsTable" src="http://www.silverlightshow.net/Storage/Users/walterf/ListItemsTable_thumb.png" width="857" height="167" /></a></p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/WorkflowTable_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="WorkflowTable" alt="WorkflowTable" src="http://www.silverlightshow.net/Storage/Users/walterf/WorkflowTable_thumb.png" width="473" height="128" /></a></p> <p style="text-align: justify;"><em>The nice thing is that you can create these event receivers from Visual Studio 2010 selecting the “Event receiver” template for a “new project” or for a “new item” of an existing project.</em></p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/NewProjectEV_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="NewProjectEV" alt="NewProjectEV" src="http://www.silverlightshow.net/Storage/Users/walterf/NewProjectEV_thumb.png" width="644" height="449" /></a></p> <p><em>The template lets you choose the type of event you want to trap and then creates the skeleton code for you</em>.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/NewProjectEV1_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="NewProjectEV1" alt="NewProjectEV1" src="http://www.silverlightshow.net/Storage/Users/walterf/NewProjectEV1_thumb.png" width="603" height="479" /></a></p> <p> </p> <p style="text-align: justify;">Once clarified what the event receivers are, let’s move on and suppose you want to trap the events related to the built-in Sharepoint Calendar list. In fact, this list seems the ideal candidate where to store the “coffee break appointments”. So the idea is that when someone (user A) proposes a coffee break, he/she inserts a new item in this list. Then, “an item was added” event is fired and caught by the event receiver that we previously created in a web part. From here the web part should be able to redirect the notification to a Silverlight application.</p> <p style="text-align: justify;">Obviously the Silverlight application must be hosted in a Silverlight web part in order to be available in a Sharepoint page. </p> <p style="text-align: justify;">When the Silverlight app received the notification it should be able to display the information to the user B and allow him to express a positive feedback. If a positive feedback is given, the item in the Calendar list is updated causing the firing of a “an item was updated” event. Another event receiver pointed on this event should redirect the feedback to the client Silverlight app of user A.</p> <p style="text-align: justify;">So the key point is: who is in charge of transferring the signalling of events from the server code in the web part to the client code in the Silverlight application? </p> <p style="text-align: justify;">The answer is : a wcf Service that serves as a bridge. </p> <p style="text-align: justify;">Hopefully the following images will help to clarify this.</p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/BigPicture1_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="BigPicture1" alt="BigPicture1" src="http://www.silverlightshow.net/Storage/Users/walterf/BigPicture1_thumb.png" width="700" height="417" /></a></p> <h5>Figure 1: How the “new coffee break event” is passed from the Silverlight of the user A to the Silverlight app of the user B</h5> <p> </p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/BigPicture2_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="BigPicture2" alt="BigPicture2" src="http://www.silverlightshow.net/Storage/Users/walterf/BigPicture2_thumb.png" width="700" height="432" /></a></p> <h5>Figure 2: How the “coffee break event confirmation” is passed from the Silverlight app of the user B to the Silverlight app of the user A</h5> <p> </p> <h4>Note that the built-in Calendar list does not contain any field specifically dedicated to storing the participants of an event or their confirmations. So for this purpose I used the “Description” field of the Calendar. Basically, when user B in figure 2 confirms his will to take a coffee break with user A, he updates the “coffee break” item in the Calendar list by adding his confirmation in the Description field. </h4> <p> </p> <h3>A wcf service as a bridge</h3> <p style="text-align: justify;">In the previous paragraph we learned that the idea (behind the possibility to extend the event receivers to a client application) is to use an “ad hoch” wcf service. Furthermore, this wcf service should be able to manage a one-to-many relation when a new item in the Calendar is created and when an item is updated. The image below shows both cases:</p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/wcfService1_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="wcfService1" alt="wcfService1" src="http://www.silverlightshow.net/Storage/Users/walterf/wcfService1_thumb.png" width="650" height="926" /></a></p> <h5>Figure 3: the wcf service manages a one-to-many relation</h5> <p> </p> <p>In this way all the users of a group will receive a notification about a new coffee break proposal and a notification about the confirmations of one or more of them.</p> <p style="text-align: justify;">Previously we have also stated that all these notifications should appear without the need to refresh the Sharepoint page containing the Silverlight application. This means that the Silverlight application should implement some kind of polling to the wcf service or better, the wcf service should be able to “push” the data into the Silverlight application. You as Silverlight developers surely know that there are several ways to accomplish this. For the “coffee break” application I used HTTP Polling Duplex following the details explained in this excellent <a href="http://weblogs.asp.net/dwahlin/archive/2011/02/06/syncing-data-with-a-server-using-silverlight-and-http-polling-duplex.aspx">article</a>. Without going too much in detail (for further explanations you can download and look at the source code linked to this article), I added the following interfaces to the service: the first defines the methods that the client can call on the service:</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"> <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;" id="codeSnippet">[ServiceContract(Namespace = <span style="color: #006080;">"Silverlight"</span>, CallbackContract = <span style="color: #0000ff;">typeof</span>(ISPDataServiceCallback))]<br /> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">interface</span> ISPDataService<br /> {<br /> [OperationContract(IsOneWay = <span style="color: #0000ff;">true</span>)]<br /> <span style="color: #0000ff;">void</span> DataFromClient(SPData <span style="color: #0000ff;">value</span>);<br /><br /> [OperationContract(IsOneWay = <span style="color: #0000ff;">true</span>)]<br /> <span style="color: #0000ff;">void</span> DataFromSP(SPData <span style="color: #0000ff;">value</span>);<br /> }</pre> <br /> </div> <p style="text-align: justify;">As for the <em>DataFromSP(SPData value)</em> method we will come back on this in a while. Instead, the <em>DataFromClient(SPData value)</em> method is called by the Silverlight client application at the first start to be registered on the service. As you may remember, this is due to the fact that the service must ensure a relation “one to many” with the running clients. For this reason the service must keep track of each client available. </p> <p>The registration is made by the client as follows:</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"> <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;" id="codeSnippet"><span style="color: #008000;">// registration to the server</span><br /> SPData regData = <span style="color: #0000ff;">new</span> SPData();<br /> regData.Event = events.client_reg;<br /> regData.User = currentUser;<br /> _Proxy.DataFromClientAsync(regData);<br />}<br />…<br /><span style="color: #0000ff;">void</span> _Proxy_ReceiveSPDataReceived(<span style="color: #0000ff;">object</span> sender, ReceiveSPDataReceivedEventArgs e)<br /> {<br /> <span style="color: #0000ff;">if</span> (e.spData.Event == events.client_reg)<br /> {<br /> LogtxtBlock.Text = <span style="color: #006080;">"Connection estabilished."</span>;<br /> AddBreakBtn.IsEnabled = <span style="color: #0000ff;">true</span>;<br /> }</pre> <br /> </div> <p> </p> <p>At the service level the <em>DataFromClient(SPData value)</em> method is implemented as follows:</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"> <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;" id="codeSnippet"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> DataFromClient(SPData <span style="color: #0000ff;">value</span>)<br />{<br /> <span style="color: #008000;">//Get client callback channel</span><br /> var context = OperationContext.Current;<br /> var sessionID = context.SessionId;<br /> var currClient = context.GetCallbackChannel<ISPDataServiceCallback>();<br /> context.Channel.Faulted += Disconnect;<br /> context.Channel.Closed += Disconnect;<br /><br /> ISPDataServiceCallback client;<br /> <span style="color: #0000ff;">if</span> (!_ClientCallbacks.TryGetValue(sessionID, <span style="color: #0000ff;">out</span> client))<br /> {<br /> <span style="color: #0000ff;">lock</span> (_Key)<br /> {<br /> _ClientCallbacks[sessionID] = currClient;<br /> }<br /> }<br /><br /> <span style="color: #008000;">// Get SPData</span><br /> <span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">value</span>.Event == events.client_reg)<br /> {<br /> <span style="color: #0000ff;">value</span>.ItemValue = <span style="color: #006080;">"acknowledgment"</span>;<br /> currClient.ReceiveSPData(<span style="color: #0000ff;">value</span>);<br /> }<br /> <br />}</pre> <br /> </div> <p style="text-align: justify;"> </p> <p style="text-align: justify;">For each new client a specific channel is reserved for future communications. Only in the event of a new registration an “acknowledgment” is sent back to the client as feedback that the communication channel has been established.</p> <p style="text-align: justify;">If you were careful you may have noticed that in the snippet of the code above there was a reference to a ISPDataServiceCallback interface. This interface defines the callback methods that the service can use to communicate with a client:</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"> <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;" id="codeSnippet">[ServiceContract]<br /><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">interface</span> ISPDataServiceCallback<br />{<br /> [OperationContract(IsOneWay = <span style="color: #0000ff;">true</span>)]<br /> <span style="color: #0000ff;">void</span> ReceiveSPData(SPData spData);<br /><br /> [OperationContract(IsOneWay = <span style="color: #0000ff;">true</span>, AsyncPattern = <span style="color: #0000ff;">true</span>)]<br /> IAsyncResult BeginReceiveSPData(SPData spData, AsyncCallback callback, <span style="color: #0000ff;">object</span> state);<br /> <span style="color: #0000ff;">void</span> EndReceiveSPData(IAsyncResult result);<br /><br /> [OperationContract(IsOneWay = <span style="color: #0000ff;">true</span>)]<br /> <span style="color: #0000ff;">void</span> DataFromSPCallback(<span style="color: #0000ff;">string</span> message);<br />}</pre> <br /> </div> <p> </p> <p style="text-align: justify;">Here you may notice the definition of the <em>ReceiveSPData(SPData spData)</em> method used above to communicate to the client that the communication channel is ready.</p> <p style="text-align: justify;">Let's take a breath now and think: ok, we have seen how the client Silverlight app and the service can communicate but… one more piece is missing. In what way does the event receiver communicate with the service and instruct it to redirect the information gathered to the client?</p> <p style="text-align: justify;">You can add another service endpoint and a new binding to the wcf service. Using the Microsoft Configuration Editor” in the “coffee break” application I added a new endpoint called “wsdual” and a binding of type “wsDualHttpBinding”. So I was able to use the same contract type used by the Silverlight application. </p> <p style="text-align: justify;">The <em>DataFromSP(SPData value)</em> method included in the first interface (ISPDataService) that I put in a corner some paragraphs above is just the method used in the event receivers to transfer the notification about new/updated items in the Calendar list into the service.</p> <p style="text-align: justify;">The snippet below shows the method used by the event receivers:</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"> <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;" id="codeSnippet"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> SendSPDataToClient(events eventType, SPItemEventProperties properties, <span style="color: #0000ff;">string</span> userColumn)<br />{<br /> InitConnectionToWCF();<br /><br /> DateTime eventDate = (DateTime)properties.ListItem[<span style="color: #006080;">"EventDate"</span>];<br /><br /> SPData spdata = <span style="color: #0000ff;">new</span> SPData();<br /> spdata.Event = eventType;<br /> spdata.ItemValue = eventDate.ToShortTimeString();<br /> spdata.listName = properties.List.Title;<br /> spdata.ItemID = properties.ListItemId.ToString();<br /><br /> SPFieldLookupValue userValues = <span style="color: #0000ff;">new</span> SPFieldLookupValue(Convert.ToString(properties.ListItem[userColumn]));<br /><br /> spdata.User = userValues.LookupValue;<br /> spdataService.DataFromSP(spdata);<br /><br />}</pre> <br /> </div> <p> </p> <p>Once the service receives the notification, it sends the information directly to the clients as follows:</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"> <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;" id="codeSnippet"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> DataFromSP(SPData spData)<br />{<br /> SendSPDataToClient(spData);<br />}<br /><br /><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> SendSPDataToClient(SPData spData)<br />{<br /> var cbs = _ClientCallbacks.Where(cb => ((IContextChannel)cb.Value).State == CommunicationState.Opened);<br /> <span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < cbs.Count(); i++)<br /> {<br /> var cb = cbs.ElementAt(i).Value;<br /> <span style="color: #0000ff;">try</span><br /> {<br /> cb.BeginReceiveSPData(spData, _ReceiveSPDataCompleted, cb);<br /> }<br /> <span style="color: #0000ff;">catch</span> (TimeoutException texp)<br /> {<br /> <span style="color: #008000;">//Log timeout error </span><br /> }<br /> <span style="color: #0000ff;">catch</span> (CommunicationException cexp)<br /> {<br /> <span style="color: #008000;">//Log communication error </span><br /> }<br /> }<br /> <br />}</pre> <br /> </div> <p> </p> <h3>Insert/update items in the Sharepoint Calendar List from Silverlight</h3> <p style="text-align: justify;">If you have read my previous articles on this topic you should be familiar with the use of the Silverlight client object model. In the “coffee break” application the insert/update is carried out in a secondary thread in order to be able to use the synchronous <em>ExecuteQuery()</em> method instead of the conventional <em>ExecuteQueryAsync()</em>. There is no particular reason behind that, it is just another way. Here below the snippet of code that creates a new item:</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"> <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;" id="codeSnippet"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> InsertEventThreadFunc(<span style="color: #0000ff;">object</span> objData)<br />{<br /> ThreadData mthData = (ThreadData)objData;<br /><br /> List list = mthData.ThClientContext.Web.Lists.GetByTitle(mthData.ThSPData.listName);<br /> ListItemCreationInformation itemCreateInfo = <span style="color: #0000ff;">new</span> ListItemCreationInformation();<br /><br /> ListItem newEvent = list.AddItem(itemCreateInfo);<br /> newEvent[<span style="color: #006080;">"Title"</span>] = <span style="color: #006080;">"Coffee break for "</span> + mthData.ThSPData.User;<br /> newEvent[<span style="color: #006080;">"EventDate"</span>] = (DateTime)mthData.ThSPData.ItemValue;<br /> newEvent[<span style="color: #006080;">"EndDate"</span>] = (DateTime)mthData.ThSPData.ItemValue;<br /> newEvent.Update();<br /><br /> mthData.ThClientContext.Load(list, i => i.Title);<br /> <br /> mthData.ThClientContext.ExecuteQuery(); <br />}</pre> <br /> </div> <p> </p> <p style="text-align: justify;">And below the snippet that updates the item:</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"> <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;" id="codeSnippet"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> UpdateEventThreadFunc(<span style="color: #0000ff;">object</span> objData)<br />{<br /> ThreadData mthData = (ThreadData)objData;<br /><br /> List list = mthData.ThClientContext.Web.Lists.GetByTitle(mthData.ThSPData.listName);<br /><br /> CamlQuery camlQuery = <span style="color: #0000ff;">new</span> CamlQuery();<br /> <br /> camlQuery.ViewXml =<br /> <span style="color: #006080;">@"<View><br /> <Query><br /> <Where><br /> <Eq><br /> <FieldRef Name='ID'/><br /> <Value Type='Counter'>"</span> + mthData.ThSPData.ItemID + <span style="color: #006080;">@"</Value><br /> </Eq><br /> </Where><br /> </Query><br /> </View>"</span>;<br /> <br /> <br /> ListItemCollection listItems = list.GetItems(camlQuery);<br /> <br /> mthData.ThClientContext.Load(listItems,<br /> items => items.Include(item => item[<span style="color: #006080;">"Description"</span>]));<br /> <br /> mthData.ThClientContext.ExecuteQuery();<br /><br /> <span style="color: #0000ff;">if</span> (listItems[0] != <span style="color: #0000ff;">null</span>)<br /> {<br /> listItems[0][<span style="color: #006080;">"Description"</span>] = listItems[0][<span style="color: #006080;">"Description"</span>] + <span style="color: #006080;">" "</span> + mthData.CurrentUser.Substring(mthData.CurrentUser.LastIndexOf(<span style="color: #006080;">@"\") + 1) + "</span> will join the coffee <span style="color: #0000ff;">break</span>!";<br /> listItems[0].Update();<br /> mthData.ThClientContext.ExecuteQuery();<br /> }<br /><br />}</pre> <br /> </div> <p> </p> <h3>Summary</h3> <p style="text-align: justify;">In this article we have introduced another interesting feature of Sharepoint: the event receivers. Although this feature seems to be reserved to server side applications like classic Sharepoint web parts, we have explored a way to make it available for a Silverlight application embedded in a Sharepoint web part. The simple application that we have created, i.e. a widget to quickly organize a coffee break with colleagues, is able to transfer to the client code the notification of an item added/updated to the built-in Calendar list. To do that it uses an external wcf service that exposes a HTTP Polling Duplex binding to communicate with the Silverlight part and a WSDualHttp binding to communicate with the server code of the event receiver. This example opens interesting perspectives of interaction between Silverlight and Sharepoint. In one of the next articles we will try to apply this strategy to another big chapter of the Sharepoint world: the workflows. But now, I definitely need a coffee break.</p> http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-event-receivers-in-Silverlight.aspx editorial@silverlightshow.net (Walter Ferrari ) http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-event-receivers-in-Silverlight.aspx#comments http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-event-receivers-in-Silverlight.aspx Tue, 13 Mar 2012 16:17:00 GMT Part 3: Developing for a multitude of clients: strategies for code reuse and keeping costs in check. <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Part-3-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.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/Part-3-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" data-count="horizontal" data-text="Developing for a multitude of clients Part 3: Strategies for code reuse and keeping costs in check" data-url="http://slshow.net/xyi4we">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Part-3-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <h3>Introduction</h3> <p>Welcome to the third part of this article series on strategies for designing your application for a multitude of different clients. In the <a href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" target="_blank">first part of this series</a>, we've had a look at the <strong>business case & some general concerns</strong> we'll have to tackle. </p> In the <a href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check-part-2.aspx" target="_blank">second part</a>, we made a <strong>choice for a service layer: WCF RIA Services</strong>, looked into what this choice offered us and why we made it, and looked into some general guidelines you should keep in mind when designing a service layer which will be used by a multitude of clients. <p>In this part, we'll start with the<strong> development of the first client: a web-based Silverlight client</strong>. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/______image_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="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/______image_thumb.png" width="479" height="253" /></a> </p> <p>You can <a href="http://www.silverlightshow.net/Storage/Sources/SalesDashboard_3.zip"><strong>download the source code for this article here</strong></a> (you can log in to the demo application with <strong>pete.campbell@madmen.com / abc@123</strong>). </p> <p>  </p> <h3>Quick 'n dirty?</h3> <p>As stated, the first client we're going to build will be a Silverlight client. </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/items/WCF-RIA-Services-Part-1-Getting-Started.aspx">10-part Article Series: WCF RIA Services</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/Part-2-of-the-Webinar-Metro-and-WinRT.aspx">Recent Webinar Recording: Metro and WinRT for the Silverlight/WPF Developer: Part 2</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; border-image: initial;" 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></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> The easy, quick 'n dirty way would be to simply add a Silverlight application to our solution, add our Views, ViewModels and application app logic to it, and let it communicate with the EmployeeOpportunityService we've created in the second part. <p>However, as we know we'll have to build multiple clients, that's probably not the best option: reuse of code would be fairly limited, in fact: we would only be able to reuse the service layer (and accompanying client-side model, generated through WCF RIA Services). There's got to be a way to improve on this, right? </p> <p>The answer lies in modularity. As you might remember from the first parts of this article series, we're only creating one module for demo purposes: the Employee Opportunity module. The main Silverlight client could, before going into production, import multiple modules: a Management Module, a Reporting Module, .... It makes sense to logically separate these out: some clients might offer all modules, some of the modules, … . Separating this out offers an advantage: code reuse. Each module could be reused by a variety of clients (for example: our Silverlight Out of Browser client can reuse the same assemblies). </p> <p>  </p> <h3>Add reference…</h3> <p>The first approach is quite similar to what any .NET developer is used to. Instead of adding the Views and ViewModels in our WebClient project, we create a new Silverlight class library. In this class library, we add the Views and ViewModels that logically belong to the Employee Opportunity Module. For other modules, we do the same. </p> <p>In our WebClient project, we now add a reference to the class librar(y)(ies) of the modules that can be used by this specific client, and we add references to any assemblies that might be used by any of these modules. </p> <p>Build, run, and we're set. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/____image_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="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/____image_thumb_1.png" width="525" height="349" /></a> </p> <p>Or are we? </p> <p>  </p> <h3>A better approach.</h3> <p>While the previous approach might be valid (we've got our reusability), it does offer a disadvantage: your final XAP contains all the code from the assemblies from the different modules, in other words: it can get quite big, resulting in slower load times and higher bandwidth consumption. Moreover, in quite a few applications the modules the user can access depends on his rights: why would we want to get an XAP, containing all modules, to a client who only has access to one module? </p> <p>And what's more: as this is an article series on code reuse, something's not quite right with our modules either: we've still got no way to reuse Views without importing a specific ViewModel implementation, or the other way around: the module contains both. As we're building different clients, it's not unimaginable we'll want to reuse the code in a specific ViewModel, but use it as DataContext to a different View. Or we could have a client which want to reuse a specific View, but has no need for the ViewModel, as it provides its own, client-specific implementation. </p> <p>So, what we want to do is keep our Views in one assembly, and keep our ViewModels in a different assembly. When we start our Silverlight client, the Employee Opportunity module will be composed by importing what's needed. </p> <p>What we really need here is composability & on-demand loading: say hello to MEF. </p> <p>  </p> <h3>The Managed Extensibility Framework - a short introduction.</h3> <p>MEF, or the Managed Extensibility Framework, was designed to simplify the design of extensible applications and components. Applications can have changing requirements, or need to be able to plug in extra pieces of logic. After some amount of time, it can become difficult to add new functionality easily to your application. MEF solves this problem by making it easy to “plug in” new functionality into your application. In our example, we can use this to "plug in" the modules when needed. </p> <ul> <li>First of all, there's the concept of Composition: you start by telling MEF where it can find the parts of the application it needs to provide by creating a catalog. From this catalog, you then create a CompositionContainer. </li> <li>Next, there's the Export concept: by using the Export attribute on a component, you tell MEF you want to export this component (type, property), so it can be composed via the container. </li> <li>Lastly, there's the Import (or ImportMany) concept, which tells MEF what type of components should be imported in a specific part of your application. </li> </ul> <p>These 3 simple concepts are the basics of MEF, and should give a basic understanding of what MEF is and what it does. A lot more information can be found at <a href="http://mef.codeplex.com/">http://mef.codeplex.com/</a> </p> <p>Note: in quite a few projects, MEF is used as a replacement for an Inversion of Control container, like Castle or Ninject. In my opinion, this is defendable (depending on your project requirements, of course), but in essence MEF is designed managing unknown dependencies (hence: plugability), while a classic IoC container is used for managing known dependencies. </p> <p>  </p> <h3>Some refactoring & custom code</h3> <p>The first thing to do is separate out our Views from our ViewModels: they both need to be in separate assemblies. This results in the following project division: </p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/__image_6.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/__image_thumb_2.png" width="401" height="300" /></a> </p> <p>For now, we'll keep the View assembly as a reference to our WebClient project, and we'll load the ViewModel assembly on-demand when the application starts (more on why I'm making this choice can be found at the end of the article). </p> <p>… and we've bumped into a problem. In Silverlight, you can load XAP-files on demand with MEF, but you can't load assemblies on demand. Out of the box, there's no way to compose our application with external assemblies - which is what we'd like. </p> <p>Luckily, Chris Pietschman (<a href="http://pietschsoft.com/">http://pietschsoft.com/</a>) made this possible through his SuperDeploymentCatalog implementation. This is actually for about 95% the same code as a regular DeploymentCatalog, but he changed the HandleOpenReadCompleted method so it allows DLL importing. The complete code can be found in the accompanying source code, in Framework.Silverlight, but this is the part that matters:</p> <pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> HandleOpenReadCompleted(<span class="kwrd">object</span> sender, OpenReadCompletedEventArgs e) { Exception error = e.Error; <span class="kwrd">bool</span> cancelled = e.Cancelled; <span class="kwrd">if</span> (Interlocked.CompareExchange(<span class="kwrd">ref</span> <span class="kwrd">this</span>._state, 0xbb8, 0x7d0) != 0x7d0) { cancelled = <span class="kwrd">true</span>; } <span class="kwrd">if</span> ((error == <span class="kwrd">null</span>) && !cancelled) { <span class="kwrd">try</span> { <span class="rem">// Check if a XAP or DLL was downloaded, based on file extension</span> <span class="kwrd">if</span> (<span class="kwrd">this</span>._uri.OriginalString.ToLower().EndsWith(<span class="str">".xap"</span>)) { <span class="rem">// Load Assemblies from XAP</span> IEnumerable<Assembly> assemblies = Package.LoadPackagedAssemblies(e.Result); <span class="kwrd">this</span>.DiscoverParts(assemblies); } <span class="kwrd">else</span> { <span class="rem">// Load DLL Assembly</span> var assemblies = <span class="kwrd">new</span> List<Assembly>(); assemblies.Add((<span class="kwrd">new</span> AssemblyPart()).Load(e.Result)); <span class="kwrd">this</span>.DiscoverParts(assemblies); } } <span class="kwrd">catch</span> (Exception exception2) { error = <span class="kwrd">new</span> InvalidOperationException(<span class="str">"Strings.InvalidOperationException_ErrorReadingXap"</span>, exception2); } } <span class="kwrd">this</span>.OnDownloadCompleted(<span class="kwrd">new</span> AsyncCompletedEventArgs(error, cancelled, <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>  </p> <p>In the Application_Startup method, we'll load our ViewModel assembly. First, we create a new AggregateCatalog instance. To this type of catalog, other catalogs can be added dynamically (this will also come in useful later on in this article series). Next, we create a new SuperDeploymentCatalog, pointing to the ViewModel assembly. This catalog is added to the Catalogs collection of the AggregateCatalog instance. </p> <p>We add an event handler to the DownloadCompleted event of our SuperDeploymentCatalog instance. When this event is correctly completed, we set the RootVisual to a new instance of our applications' MainPage. Note that this shouldn't be done earlier, as MainPage contains a View which in turn imports a ViewModel instance: that ViewModel instance is only available after the ViewModel assembly has been loaded. </p> <p>Next, we'll call the DownloadAsync() method, and we initialize MEF's CompositionHost by passing in our AggregateCatalog instance. </p> <pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> Application_Startup(<span class="kwrd">object</span> sender, StartupEventArgs e) { <span class="kwrd">this</span>.Resources.Add(<span class="str">"WebContext"</span>, WebContext.Current); WebRequest.RegisterPrefix(<span class="str">"http://"</span>, WebRequestCreator.ClientHttp); WebRequest.RegisterPrefix(<span class="str">"https://"</span>, WebRequestCreator.ClientHttp); var catalog = <span class="kwrd">new</span> AggregateCatalog(); var catalogVM = <span class="kwrd">new</span> SuperDeploymentCatalog(<span class="str">"SalesDashboard.SL.Modules.EmpOpp.ViewModels.dll"</span>); catalog.Catalogs.Add(catalogVM); catalogVM.DownloadCompleted += (senderVM, argsVM) => { <span class="kwrd">if</span> (argsVM.Error != <span class="kwrd">null</span>) { MessageBox.Show(argsVM.Error.Message); } <span class="kwrd">else</span> { <span class="kwrd">this</span>.RootVisual = <span class="kwrd">new</span> MainPage(); } }; catalogVM.DownloadAsync(); CompositionHost.Initialize(catalog); CompositionInitializer.SatisfyImports(<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>We can now build and run our application. The application is composed on-demand: the ViewModels are not included as a reference, they are loaded when needed. This results in a smaller XAP (faster loading times), composability, and an assembly that can easily be reused. We've now got a technique for code reuse across clients: instead of having to rewrite your ViewModel code, you can simply reuse the existing code. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/image_8.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/image_thumb_3.png" width="527" height="313" /></a></p> <p>Note: as we're loading assemblies on-demand, you might want to ensure the correct version is loaded. By default, when you build a project in debug-mode, the resulting assembly is put in the projects' bin/debug-folder (wherefrom it can't be loaded on demand by the Silverlight application, as you won't have rights to access that folder). An easy way to ensure the resulting assembly is always available is by changing its output path to the ClientBin folder of the WebClient.</p> <p> </p> <h3>Conclusion </h3> <p>We've seen a few different techniques to separate out parts of our application: referencing & loading on demand through MEF. This allows us to reuse code across different clients. </p> <p>Then again, we're not quite there yet. In fact, we're just getting started with this: can we do better? </p> <p> </p> <h3>What's coming up? </h3> <p>You might notice I've carefully avoided a few pretty obvious issues in this article: why are we not loading the Views on demand, but keeping them as a reference instead? And what about those other assemblies, like the model assembly? As we're modularizing the application, it would make sense to only load the model assembly when the ViewModels using that model are necessary, no? </p> <p>Of course, those are valid concerns, and this is exactly what we'll tackle in the next part of this series. It requires quite a bit of custom coding: we'll need some extensions to the Silverlight Navigation framework (as it's not as straightforward as we would like to navigate to views in assemblies that are loaded on-demand), and we'll need a component loader component (to ensure we can load all necessary assemblies at once, instead of one by one). After that part, we'll end up with a truly composable app, separated out in modules/assemblies that can easily be reused across different clients. </p> <p>Up until then: happy coding! </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, HTML5). 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 Belgium & Portugal, NDC2011, ... Next to that, he also authored a best-selling Silverlight book, Packt Publishing's <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">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 you can contact him on Twitter via <a href="http://twitter.com/#!/KevinDockx">@KevinDockx</a>.</p> http://www.silverlightshow.net/items/Part-3-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Part-3-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx#comments http://www.silverlightshow.net/items/Part-3-Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx Fri, 24 Feb 2012 20:23: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 Part 2: Developing for a multitude of clients: Strategies for code reuse and keeping costs in check <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check-part-2.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/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check-part-2.aspx" data-count="horizontal" data-text="Developing for a multitude of clients Part 2: Strategies for code reuse and keeping costs in check" data-url="http://slshow.net/xyx7p8">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check-part-2.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <h3>Introduction</h3> <p>Welcome to the second part of this article series on strategies for designing your application for a multitude of different clients. A lot of businesses face this problem today: your customers expect a rich desktop client, an almost equally rich web client, a mobile client, … and of course, on different form factors and for use with different types of input: typically, a mouse-keyboard combination, or touch.</p> <p>That typically amounts to higher costs. And in reality, it will - after all, you are building multiple client applications. The good news is: your costs don't necessarily have to spin out of control. The aim of this article series is to look into how you can cut costs when you're faced with these demands: where can you reuse existing code, and how?</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/items/WCF-RIA-Services-Part-1-Getting-Started.aspx">10-part Article Series: WCF RIA Services</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/Recording-of-Metro-and-WinRT-Webinar.aspx">Recent Webinar Recording: Metro and WinRT for the Silverlight/WPF Developer: Part 1</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; border-image: initial;" 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></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 the <a href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx" target="_self">first part</a>, we've had a look at the business case, and the clients we're going to develop. We've also looked at the provided data model.  In this part, we'll look at the service layer. We've got a few requirements we need take into account. First of all, the service layer should be able to be consumed by the different clients: Silverlight, Windows Phone, HTML, Windows Phone, Metro. We've also got a few common concerns we should tackle: validation & authentication come to mind. And we require something that allows us to rapidly get our applications to the market: development time is an issue to take into account as well.</p> <p>The accompanying source code for this article can be downloaded <a href="http://www.silverlightshow.net/Storage/Sources/SalesDashboard.zip">here</a>. <br /> <br /> </p> <h3>Say hello to WCF RIA Services</h3> <p>If you have been building serious Silverlight Line of Business applications, you've undoubtedly heard of WCF RIA Services. A Silverlight client will typically get its data from a server via asynchronous service calls - so when you're building a Silverlight application, you're forced to build it in an asynchronous, service-oriented way. This can quickly become quite cumbersome: you'll have to write quite a lot of application logic to solve some common concerns, like validation logic and authentication, which quickly results in writing code on both sides (client and server), plugging in some code generator or your own mapping tool, …</p> <p>Here, we're trying to get our applications to the market quickly, and we're trying to cut down on development time & costs. This is where WCF RIA Services really stands out: it obscures a lot of the plumbing details you'd have to write yourself otherwise, and more importantly: it solves most of our common concerns. You'll typically write the code on the server side, and WCF RIA Services will generate the corresponding code on the client - including your validation logic, your domain model, and all the logic you need to fetch and submit entities. </p> <p>Working with WCF RIA Services feels a lot like working with the Entity Framework (of course, I’m talking about the “feel” here, not the technicalities): you'll load entities to your client, construct change sets, and submit them back to the server, which will take care of committing them to your data store: it obscures the intermittent service layer. This is, of course, a simplified explanation, and in reality it's not as easy as a typical marketing department would like you to believe, but I've used WCF RIA Services on a multitude of real-life Line of Business projects, and I'm convinced it's the fastest option on the market, while still allowing great extensibility and robustness, making it a good fit for most Line of Business applications. In this series, we won't look into the specifics of developing with WCF RIA Services, as there are already some great resources out there: you can learn a lot more about WCF RIA Services in Brian Noyes <a href="http://www.silverlightshow.net/items/WCF-RIA-Services-Part-1-Getting-Started.aspx" target="_blank">excellent series on this site</a>, or have a look at some of the WCF RIA Services related articles I wrote. <br /> <br /> </p> <h3>What about the other clients?</h3> <p>Ok, so it's a no-brainer for building a Silverlight application, and our two main clients are Silverlight-based (web & out of browser), but what about those other clients? Weren't we supposed to build a mobile client (Windows Phone), an HTML-based client, and even a Windows 8 Metro client? Yes, we are, so let's have a look at those.</p> <p><strong>The mobile client (Windows Phone 7):</strong> when you're developing for Windows Phone, you're developing in Silverlight. However, this isn't the same version as the Web/OOB plugin. Contrary to what you might hope, WCF RIA Services isn't supported as we're used to in regular Silverlight. However, WCF RIA Services can expose its Domain Services as SOAP, REST or OData (read-only) endpoints, making it easily accessible from a Windows Phone client. We'll look into how we can enable this a bit further on in this article.</p> <p><strong>The HTML-based client:</strong> for this client, a WCF RIA Services implementation is available, namely <a href="http://wcf.codeplex.com/wikipage?title=jQueryRia&referringTitle=WCF%20jQuery" target="_blank">RIA/JS</a>: a jQuery client for WCF RIA Services. With this JavaScript-based framework, you get most of what you're used to with a Silverlight-based WCF RIA Services client, but with using JavaScript. You can load data using your Domain Services (query support, including sorting, paging and filtering), you get your validation logic on the client (your server side validation metadata is exposed in jQuery validation format), you can create change sets and you can submit them.</p> <p><strong>Windows 8 Metro client:</strong> at this point, it's unclear whether or not we'll get WCF RIA Services support for Windows 8 Metro apps. However, even it doesn't happen, the SOAP, REST or OData endpoints can be used.</p> <p><strong>Other future clients (iOS, Android):</strong> these would typically use the SOAP or REST endpoints. <br /> <br /> </p> <h3>Setting it up: logically dividing your services</h3> <p>It may seem like a no-brainer, but it's often forgotten: you should logically divide your domain model into different services, and a service should only expose what's needed, nothing more. This is especially true if you're building different clients: not every client will provide the users with the same functionality, so a client that provides limited functionality shouldn't consume a service which exposes a lot more - for example, if you look at our business case, the mobile client will deal with quickly inputting new opportunities, and thus shouldn't have access to service methods that allow him to access back-end functionality, or customer administration. So, instead of having only one Domain Service which exposes all your logic & entities, you should divide them in different "modules": a Domain Service for customer administration, a Domain Service for employee/opportunity management (this is the one we'll build), … Also, don’t expose unneeded operations: for example, a Domain Service for managing opportunities will probably require access to the Employee object, but shouldn’t be able to edit it (so there’s no need for Insert, Update or Delete operations).</p> <p>Using this type of division also offers you more scalability options: often-used modules, by various clients, can be published to servers with higher bandwidth capabilities, whereas little-used modules can kept on low-bandwidth servers.</p> <p>Same goes for security: a back-end service module can be kept in-house, hosted on your intranet rather than on the internet. <br /> <br /> </p> <h3>Setting it up: the solution division</h3> <p>Often, the WCF RIA Services class library template is used. This creates a .Web project (full .NET 4 CLR), containing your domain services, and a Silverlight class library project, containing the generated code. However, the naming of these projects is quite unclear, and not exactly correct. We're going to change that a bit, resulting in better naming.</p> <p>First, we'll add a class library to our solution, SalesDashboard.EmployeeOpportunityService. This will contain the Domain Service we'll use throughout this demo application. You'll typically want one of these for each of your logically divided modules, as explained in the previous paragraph. For the demo application we're building, two are sufficient: one for the EmployeeOpportunity service, and one for an authentication service.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/_clip_image001_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="clip_image001" alt="clip_image001" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/_clip_image001_thumb.png" width="273" height="61" /></a></p> <p>Next, we'll add a Silverlight class library to the project, SalesDashboard.Client.Model. This is the project which will be referenced by our Silverlight clients, and this is where we want the generated code to end up. That can be achieved by setting the WCF RIA Services link to the project containing our Domain Service:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/clip_image002_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="clip_image002" alt="clip_image002" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/clip_image002_thumb.png" width="603" height="286" /></a></p> <p>All we need now is a Service Host. Create a new ASP .NET application, and make sure it references SalesDashboard.EmployeeOpportunityService. Next, add an SVC file to it, EmployeeOpportunityService.svc. Double-click it, and put in the following code:</p> <pre class="csharpcode"><%@ ServiceHost Language=<span class="str">"C#"</span> Debug=<span class="str">"true"</span> <br />Service=<span class="str">"SalesDashboard.EmployeeOpportunityService.EmployeeOpportunityDomainService"</span> Factory=<span class="str">"System.ServiceModel.DomainServices.Hosting.DomainServiceHostFactory, <br />System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, <br />PublicKeyToken=31bf3856ad364e35"</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>As you can see, we're stating here that the DomainServiceHostFactory should be used to instantiate a new EmployeeOpportunityDomainService - making our service accessible through the explicit EmployeeOpportunityService.svc URI instead of the auto-generated SVC you normally get with WCF RIA Services.</p> <p>Note: as this is now your service host, this project should contain all necessary WCF RIA Service references and configuration in the web.config - just as you would normally have in a service host.  This is how it looks in the provided solution: </p> <pre class="csharpcode"><p><span class="kwrd"><</span><span class="html">configuration</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">system.webServer</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">modules</span> <span class="attr">runAllManagedModulesForAllRequests</span><span class="kwrd">="true"</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="DomainServiceModule"</span> <span class="attr">preCondition</span><span class="kwrd">="managedHandler"</span> <br /><span class="attr">type</span><span class="kwrd">="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, <br />System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, <br />PublicKeyToken=31bf3856ad364e35"</span> <span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">modules</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">validation</span> <span class="attr">validateIntegratedModeConfiguration</span><span class="kwrd">="false"</span> <span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">system.webServer</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">connectionStrings</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="SalesDashboardAuthenticationEntities"</span> <br /><span class="attr">connectionString</span><span class="kwrd">="metadata=res://*/SalesDashboardAuthenticationModel.csdl|<br />res://*/SalesDashboardAuthenticationModel.ssdl|res://*/SalesDashboardAuthenticationModel.msl;<br />provider=System.Data.SqlClient;provider connection string=&quot;data source=.\sql2008;<br />initial catalog=SalesDashboard;persist security info=True;user id=salesdashboard;<br />password=salesdashboard;multipleactiveresultsets=True;App=EntityFramework&quot;"</span> <br /><span class="attr">providerName</span><span class="kwrd">="System.Data.EntityClient"</span> <span class="kwrd">/></span> <span class="kwrd"><</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="SalesDashboardEmployeeOpportunityEntities"</span> <br /><span class="attr">connectionString</span><span class="kwrd">="metadata=res://*/SalesDashboardEmployeeOpportunityModel.csdl|<br />res://*/SalesDashboardEmployeeOpportunityModel.ssdl|res://*/SalesDashboardEmployeeOpportunityModel.msl;<br />provider=System.Data.SqlClient;provider connection string=&quot;data source=.\sql2008;<br />initial catalog=SalesDashboard;persist security info=True;user id=salesdashboard;<br />password=salesdashboard;multipleactiveresultsets=True;App=EntityFramework&quot;"</span> <br /><span class="attr">providerName</span><span class="kwrd">="System.Data.EntityClient"</span> <span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">connectionStrings</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">system.serviceModel</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">behaviors</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">serviceBehaviors</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">behavior</span> <span class="attr">name</span><span class="kwrd">=""</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">serviceMetadata</span> <span class="attr">httpGetEnabled</span><span class="kwrd">="true"</span> <span class="kwrd">/></span> <span class="kwrd"><</span><span class="html">serviceDebug</span> <span class="attr">includeExceptionDetailInFaults</span><span class="kwrd">="false"</span> <span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">behavior</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">serviceBehaviors</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">behaviors</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">serviceHostingEnvironment</span> <span class="attr">aspNetCompatibilityEnabled</span><span class="kwrd">="true"</span> <span class="attr">multipleSiteBindingsEnabled</span><span class="kwrd">="true"</span> <span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">system.serviceModel</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">system.web</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">compilation</span> <span class="attr">debug</span><span class="kwrd">="true"</span><span class="kwrd">></</span><span class="html">compilation</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">httpModules</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="DomainServiceModule"</span> <br /><span class="attr">type</span><span class="kwrd">="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, <br />System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, <br />PublicKeyToken=31bf3856ad364e35"</span> <span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">httpModules</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">system.web</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">configuration</span><span class="kwrd">></span></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> </p> <h3>Setting it up: making the service layer available for other clients</h3> <p>Non-Silverlight clients will communicate with our service layer through OData, SOAP or REST endpoints.  Setting these up is quite easy – the OData endpoint is even provided out of the box.  When you’re going through the Domain Service wizard, simply check the “Create OData endpoint” checkbox, and it will be created for you (you’ll still need to copy/paste the relevant code to the web.config of the Service Host).  </p> <p>If you want to do this manually, you should add some following code to the web.config on the Service Host.  This should be added right underneath the configuration tag:</p> <pre class="csharpcode"><span class="kwrd"><</span><span class="html">configSections</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">sectionGroup</span> <span class="attr">name</span><span class="kwrd">="system.serviceModel"</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">section</span> <span class="attr">name</span><span class="kwrd">="domainServices"</span> <br /><span class="attr">type</span><span class="kwrd">="System.ServiceModel.DomainServices.Hosting.DomainServicesSection, <br />System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, <br />PublicKeyToken=31bf3856ad364e35"</span> <span class="attr">allowDefinition</span><span class="kwrd">="MachineToApplication"</span> <span class="attr">requirePermission</span><span class="kwrd">="false"</span> <span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">sectionGroup</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">configSections</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>And this should be added underneath system.serviceModel:</p> <pre class="csharpcode"><p><span class="kwrd"><</span><span class="html">domainServices</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">endpoints</span><span class="kwrd">></span> <span class="kwrd"><</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="OData"</span> <span class="attr">type</span><span class="kwrd">="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory, <br /></span><span class="kwrd">System.ServiceModel.DomainServices.Hosting.OData, Version=4.0.0.0, Culture=neutral, <br />PublicKeyToken=31bf3856ad364e35"</span> <span class="kwrd">/></span> <span class="kwrd"></</span><span class="html">endpoints</span><span class="kwrd">></span> <span class="kwrd"></</span><span class="html">domainServices</span><span class="kwrd">></span></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>The other two endpoints are provided through the WCF RIA Services Toolkit.  The most convenient way of getting these is by using <a href="http://www.nuget.org/" target="_blank">NuGet</a>, as they are provided as a NuGet package.  Use NuGet to manage the packages for the Service Host, locate the RIAServices.Endpoints package, and click install.  The following endpoints will be added to your web.config file:</p> <pre class="csharpcode"><span class="kwrd"><</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="soap"</span> <span class="attr">type</span><span class="kwrd">="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory, <br />Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, <br />PublicKeyToken=31bf3856ad364e35"</span> <span class="kwrd">/></span> <span class="kwrd"><</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">="JSON"</span> <span class="attr">type</span><span class="kwrd">="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory, <br />Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, <br />PublicKeyToken=31bf3856ad364e35"</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>That’s really all there is to it: from now on, our Domain Service is accessible through OData (read-only), SOAP and JSON (REST) endpoints.</p> <h3>Conclusion</h3> <p>In this article, we’ve looked into our service layer options, and we’ve settled on WCF RIA Services.  We choose this framework mainly for its extensibility, RAD characteristics and possible reuse across different clients. We’ve looked into some pointers on service layer design, and created the Domain Service for the module we’ll develop.  At the end, we’ve made this Domain Service available for other (non-Silverlight) clients through the use of endpoints from the WCF RIA Services Toolkit.</p> <p>In the next part, we’ll start with the first Silverlight client. </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, HTML5). 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 Belgium & Portugal, NDC2011, etc. Next to that, he also authored a best-selling Silverlight book, Packt Publishing's <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">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 you can contact him on Twitter via <a href="http://twitter.com/#!/KevinDockx">@KevinDockx</a>.</p> http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check-part-2.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check-part-2.aspx#comments http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check-part-2.aspx Wed, 08 Feb 2012 18:41:00 GMT Part 1: Developing for a multitude of clients: Strategies for code reuse and keeping costs in check <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.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/Windows-8-and-the-future-of-XAML-Part-2-The-Windows-Runtime-WinRT.aspx" data-count="horizontal" data-text="Developing for a multitude of clients Part 1: Strategies for code reuse and keeping costs in check" data-url="http://slshow.net/zadXEW">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <h3>Introduction</h3> <p>In this article series, we're going to try and tackle a problem (or opportunity, depending on how you want to put it) a lot of business face today: customers expect to be able to use your applications on a multitude of devices, with different form factors, supporting different technologies. </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/items/Silverlight-5-Part-1-of-10.aspx">Article Series: 10 Laps around Silverlight 5</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/video/Recording-of-Metro-and-WinRT-Webinar.aspx">Recent Webinar Recording: Metro and WinRT for the Silverlight/WPF Developer: Part 1</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; border-image: initial;" 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></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 you're supposed to provide them with the best possible experience on all these devices, if you want to keep them. In today's world, consumers are used to the beautiful experiences they get from apps on their smartphones - and yes, enterprise users are consumers as well -, up to the point that they will prefer a nicely designed application which offers a good user experience to an application which has more features, but a badly thought out UI (on a side note, a very interesting post on why projects need to focus on design, and thus <a href="http://10rem.net/blog/2012/01/25/now-more-than-ever-you-need-a-designer" target="_blank">need a designer</a>, can be read at <a href="http://10rem.net/blog/" target="_blank">Pete Browns' blog</a>). <h3> </h3> <h3>The situation, today</h3> <p>So, where are we at? More devices, more technologies, more focus on design. For most business, this means: extra costs. You'll have to hire a designer: arguably, this will diminish costs in the long run, but it definitely is an extra cost when your project is starting. However, don't try cut costs by not hiring one: in todays' world, you will definitely regret this when you see potential customers fleeing to the competition because your application isn't user-friendly and intuitive enough. </p> <p>You'll typically have to adjust your UI to a specific form factor: it's obvious that a UI designed for use with a mouse and keyboard on a laptop with a high screen resolution is unfit for a smartphone or a tablet, which typically have smaller screen estate and touch-based input. Next to that, every technology has its own specifics, its own quirks even - and its own learning curve: you can 't just expect a Silverlight developer, who is used to a stateful model, MVVM and XAML, to be as productive on, for example, an ASP .NET project - in which he has to keep postbacks in his mind and have some knowledge of HTML + JavaScript + CSS.</p> <p>Depending on the type of service layer you choose, it will take more code to get it working depending on the technology used by the clients which consume the services. Most client technologies are pretty good at communicating with a variety of services, but we'll see that the choice of this service layer can already have a big impact on the total development time & cost - think about a Silverlight client versus a HTML-based client: your Silverlight client should have proxy classes (or a separate layer + mapping component) that implement INotifyPropertyChanged to ensure binding functions correctly. Preferably, there should also be an implementation of INotifyDataErrorInfoChanged, to get client-side validation (and thus diminish client-server communication) - things which you typically don't need in an HTML-based app (well… sometimes they come in handy, but more on that later). There's the place of validation to think about (server side or server/client-side), authentication and authorization, ... How you expose your service layer can have quite an impact on the total cost of your project. </p> <h3>The different clients we’ll build</h3> <p>SilverlightShow is a site which focuses on Silverlight (or, if you want to expand on it: XAML), so you might argue this is the logical choice for our main client applications. But that's not the reason we'll choose this technology: skill reuse is of importance as well if you want to cut costs, and so is the ability to share code between different clients - more code than just the service layer.</p> <p>Our main clients will be a Silverlight web application (typically used on every laptop which has the Silverlight plugin installed), a Silverlight Out of Browser application (typically used on the home laptop of the user), and a Windows Phone application (for use on the road) - this ensures we have a bit of skill reuse, but we'll also see we can reuse quite a bit of code: what are the options on sharing Views across XAML applications? What about ViewModels, and splitting up our code in different modules? We'll talk about code reuse, but we'll also talk about when we can reuse code, but probably shouldn't. But we won't stop there: not everyone has a Silverlight plugin - or wants to install it, so we'll dive into a HTML5 based client, as this is becoming more prevalent these days. And, why not, a Windows 8 WinRT Metro client (offering even more skill reuse across technologies)? <br /> <br /> Lastly, as we're building an application that can be used on a multitude of clients, you can image the usage of your application going up. We'll also dive into some options on how to tackle this: we’re going to take part of our application to the cloud. </p> <h3>Our business case</h3> <p>But let's start with the beginning: the application itself. What we're going to build is a dashboard application to add, edit and follow-up product sales. The company we're building it for sells this software (as a service) to other companies. Clients of this company expect to get an immediate overview of their running offers, past offers, … and the company wants to offer this to them in a nice, modern, user-friendly user interface.</p> <p>As can be expected, the sales people of their clients are typically on the road a lot, so they've asked for a mobile client. This client won't be as full-featured as the desktop client: the sales people just need to be able to quickly input a possible opportunity, right when they spot one, instead of having to wait until they're in front of their laptops.</p> <p>When they are (for example: at the customers' location), they prefer to access the application through a web browser, either via a Silverlight plug-in (if it's installed) or via a HTML5-based web application. And when they're behind their own computers, they could prefer to use a desktop-based application which can interact more with their locally installed application. A typical use case would be that the application can look in their Outlook inbox, to check if they've had contact with a specific customer in the past.</p> <p>The company also expects a lot of its clients will switch to Windows 8 tablets once they become available, so they're looking into developing a Windows 8 Metro application for this.</p> <p>As you can see: quite a lot of applications, quite a lot of requirements - and very costly. The main purpose of this article series is looking into what can be done to keep costs (and development time) in check - this is not necessarily the same as building the best architecture for every type of situation; it's about building the best architecture for this specific situation with these specific requirements, when you only have a relatively short time to put your app(s) on the market.</p> <h3>Let’s get started with the technical stuff: the data model</h3> <p>Let's look at the data model of the application first: as most of the people reading this are probably quite technical, this should help to clarify the business case somewhat:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/KevinDockx/_____image_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="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/KevinDockx/_____image_thumb.png" width="681" height="720" /></a></p> <p>As you can guess from this model, it's actually suitable for more than just one type of dashboard: we've got different roles for different employees, and an employee can have another employee as his boss - this implies we'll have different views in our application, for example: an employee might only be able to view his own opportunities, but his boss might want to get an overview of all the opportunities of everyone in his department. Next to that, there's also room for a back-end application (for user administration), and different modules (you might have one where a user can register a new opportunity, but you might also have one where a user with a specific role can manage customers). The focus of this series lies on clarifying techniques, and not on building the complete application: we're going to take one part of the dashboard app, one module if you wish, the employee/opportunity module, and use that to illustrate this series.</p> <h3>Conclusion & coming up next</h3> <p>In this article, we’ve had a look at the problem lots of businesses are facing today: multiple devices, multiple clients.  We’ve also dived into the business case we’ll use throughout this article series, and the different clients we’ll build – all the time focusing on code reuse and keeping costs in-check.  Lastly, we’ve looked at the data model we’ll use for our applications.</p> <p>In the next article, it’s time talk about how we're going to design the service layer. </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, HTML5). 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 Belgium & Portugal, NDC2011, ... Next to that, he also authored a best-selling Silverlight book, Packt Publishing's <a href="https://www.packtpub.com/microsoft-silverlight-4-data-and-services-cookbook/book">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 you can contact him on Twitter via <a href="http://twitter.com/#!/KevinDockx">@KevinDockx</a>.</p> <p>  </p> http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx editorial@silverlightshow.net (Kevin Dockx ) http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx#comments http://www.silverlightshow.net/items/Developing-for-a-multitude-of-clients-strategies-for-code-reuse-and-keeping-costs-in-check.aspx Tue, 07 Feb 2012 10:40:00 GMT Using the Live SDK in Windows 8 XAML/C# Metro 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/Using-the-Live-SDK-in-Windows-8-XAML-C-Metro-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/Using-the-Live-SDK-in-Windows-8-XAML-C-Metro-Applications.aspx" data-count="horizontal" data-text="Reading @mbcrump's article 'Using the Live SDK in #Windows8 XAML/C# Metro Applications' #win8" data-url="http://slshow.net/zsh5cA">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Using-the-Live-SDK-in-Windows-8-XAML-C-Metro-Applications.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <h3>Introduction</h3> <p>The Microsoft’s Live SDK (or commonly referred to as Live Connect), provides a set of controls and APIs that enables applications to integrate single sign-on (SSO) functionality using Windows Live ID. You can also use it to access data in SkyDrive, Hotmail, and Windows Live Messenger.</p> <div style="border: 1px solid #dddddd; width: 200px; padding-top: 5px; padding-bottom: 5px; padding-left: 10px; margin-top: 5px; margin-right: 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/Recording-of-Webinar-Introduction-to-XAML-Development-on-Windows-8-by-Gill-Cleeren.aspx">Webinar recording: Introduction to XAML Development on Windows 8</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/news/Free-SilverlightShow-Webinar-Metro-and-WinRT-for-the-Silverlight-WPF-Developer-.aspx">Webinar on Feb 2nd: Metro and WinRT for the Silverlight/WPF Developer</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> The library supports multiple platforms, including Windows Phone 7 Mango and Windows 8 Metro Style applications using either C#, Visual Basic or JavaScript.  In this article, we will build our first metro style application using the Live SDK and XAML/C#. <h3>Download the Bits</h3> <p>Let’s begin by downloading the following items:</p> <ul> <li>You will need to download the <a href="http://msdn.microsoft.com/en-us/windows/">Windows 8 Developer Preview</a> to follow along with this article. This will install Windows 8 along with the new Visual Studio 11 which is required to build Metro applications. </li> <li>Download the <a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=28195">Live SDK v5.0</a> or higher - The Live SDK provides a set of controls and APIs that enable applications to integrate single sign-on (SSO) using Windows Live ID and to access data in SkyDrive, Hotmail, and Windows Live Messenger. </li> <li>Optional, but highly recommended - The <a href="http://code.msdn.microsoft.com/windowsapps/">Metro Style App Samples</a> which provides various sample metro applications for future reference. It is licensed for public use, so feel free to use it in your own applications. </li> <li>Optional, but recommended - Read the <a href="http://download.microsoft.com/download/1/E/4/1E455D53-C382-4A39-BA73-55413F183333/Windows_Developer_Preview-Windows8_guide.pdf">Windows 8 Developer Preview guide</a> to start learning about the features/functionality coming in Windows 8. </li> </ul> <h3> <br /> Signing into Windows 8 Using your Windows Live ID</h3> <p>One of the most important things to learn before building your first application that uses the Live SDK is the various ways to sign into your Windows 8 machine. <br /> <br /> You currently have two ways to sign into your Windows 8 machine and each way determines the prompts the users will receive when launching a application that uses the Live SDK. </p> <ol> <li>A Local Account – which stores all of the data regarding your profile on the local machine. <ul> <li>If you user is using this method, then they will get the prompt to sign in and to allow access. </li> </ul> </li> <li>A Windows Live ID – retrieves profile information directly from your Live ID and enables features such as roaming and easy sign-on to Microsoft services. <ul> <li>If you user is using this method, then they will only get the prompt to allow access.  </li> </ul> </li> </ol> <p>In this tutorial, we will be signing into <strong>Windows 8 using our Live ID</strong>. </p> <p>If you have already setup a “Local Account” then you can switch very easily by going to Control Panel –> Users then clicking on “Switch to a Windows Live ID” as shown below. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/__1_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="1" alt="1" src="http://www.silverlightshow.net/Storage/Users/mbcrump/__1_thumb_1.png" width="574" height="108" /></a></p> <p>You will then be prompted to enter your current password of the local account and log in using your Live ID username/password. If you don’t have one then you may sign up for one through this wizard. </p> <p>Immediately following you should receive an email similar to the one below: </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/___________2_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="2" alt="2" src="http://www.silverlightshow.net/Storage/Users/mbcrump/___________2_thumb.png" width="569" height="301" /></a></p> <p>If you click on the link to confirm your identity then a web browser will pop open and you will be greeted with “Manage Security Info”. This screen will list mobile devices, email address and trusted PC linked to your account. As we can see below that I have three Windows 8 machines linked to my account. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/__________3_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="3" alt="3" src="http://www.silverlightshow.net/Storage/Users/mbcrump/__________3_thumb.png" width="331" height="106" /></a></p> <p>You can also add a new trusted PC manually with the “Add New” link. To use this feature, you must access your account using Internet Explorer and have Windows Live Essentials installed.</p> <h3>Let’s Get Started</h3> <p>Now that we have the necessary tools to begin building a Metro Application using C#/XAML and we we have signed into Windows 8 using our Live ID, let’s begin. </p> <p>In this sample application, we are going to retrieve the following information from the users profile: </p> <ul> <li>Users First and Last Name </li> <li>What gender they are and what region they live in </li> <li>URL to their Live Profile </li> </ul> <p>As well as add a contact to their address book. </p> <p>Launch Visual Studio 11 Developer Preview and select <strong>Visual C#</strong> -> <strong>Windows Metro style</strong> –> <strong>Application</strong>. Give the project the name <strong>MyFirstLiveConnectApp</strong> and hit OK. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/_________4_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="4" alt="4" src="http://www.silverlightshow.net/Storage/Users/mbcrump/_________4_thumb.png" width="663" height="419" /></a></p> <h3>Adding the Live SDK References</h3> <p>In case you haven’t already, please download and install the <a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=28195">Live SDK v5.0</a> before proceeding.  </p> <p>Once that is complete, we can add the references to our project by Right Clicking on References inside of Visual Studio 11 and selecting “Add Reference”. Next, you will need to select Windows –> Extension SDKs –> Live SDK then Add. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/_5_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="5" alt="5" src="http://www.silverlightshow.net/Storage/Users/mbcrump/_5_thumb_1.png" width="629" height="353" /></a></p> <h3>Registering the Application with Windows Live</h3> <p>Before we begin building this app, you need to register it with Windows Live.  You can register your app by going to the <a href="https://manage.dev.live.com/build">application management site</a> and following the instructions on the site.</p> <p>The only item that you want to pay special attention to is the <strong>Package Name</strong> in Step 3 as you will copy and paste that into your <strong>Application’s Package.appxmanifest</strong> file. (A walk-through is included in that site).</p> <p>If you don’t register your application and try to use Live services, then your user will be presented with the following error message. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/6_6.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px; border-style: solid;" title="6" alt="6" src="http://www.silverlightshow.net/Storage/Users/mbcrump/6_thumb_2.png" width="469" height="114" /></a></p> <p>Once this process is complete you can view your registered applications <a href="https://manage.dev.live.com/Applications/Index">here</a>. This page will contain all the API settings needed to use the Live SDK in your projects. </p> <h3>Understanding what is under the hood…</h3> <p>When we select the C#/XAML Application template, Visual Studio 11 provides us with basic application structure. Before we begin building our own, it makes sense to spend a few minutes examining the XAML pages included in the existing structure.  </p> <ul> <li><strong>References – </strong>It is empty by default because Microsoft decided that all the WinRT assemblies are always referenced by default and they have no reason to display them. Any of your own referenced assemblies or third party references will be shown as in this case our Windows Live SDK is shown. </li> <li><strong>App.xaml</strong> is used by Metro applications (amongst other XAML technologies) to declare shared resources like brushes, various style objects etc. The code behind file of App.xaml is used to handle global application level events like OnLaunched and OnActivated. </li> <li><strong>MainPage.xaml</strong> contains the markup of what our user interface will look like once the application is executed. The default Metro MainPage.xaml file consists of a UserControl and a Grid. </li> <li><strong>Package.appxmanifest</strong> – Is basically an XML file, but if you double click it then you will notice four tab panels inside it (named: Application UI, Capabilities, Declarations and Packaging) </li> </ul> <h3> <br /> Back to Building a Simple User Interface</h3> <p>Here is a mock-up screen of what our app will look like: </p> <h3><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/_____8_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="8" alt="8" src="http://www.silverlightshow.net/Storage/Users/mbcrump/______8_thumb.png" width="556" height="271" /></a></h3> <p>As you can see we have 2 buttons: </p> <ol> <li>Windows Live Sign-In – Provided by the Live SDK and is used to log the user into the app to retrieve Live Services information. </li> <li>Create Contact – Just a regular button that will be used to create a contact in the users address book. </li> </ol> <p>On the left hand side you can see information retrieved by the Live SDK including first and last name, gender, location and live profile URL. </p> <p>Double click on your MainPage.xaml and replace the existing Grid with the code snippet provided below.</p> <div style="border: 1px solid silver; padding: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; text-align: left;" id="codeSnippetWrapper"> <div style="padding: 0px; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; text-align: left;" id="codeSnippet"> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum1" style="color: #606060;"> 1:</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;">="#FF0C0C0C"</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum2" style="color: #606060;"> 2:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Grid.ColumnDefinitions</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum3" style="color: #606060;"> 3:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">ColumnDefinition</span> <span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="251*"</span><span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum4" style="color: #606060;"> 4:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">ColumnDefinition</span> <span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="1116*"</span><span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum5" style="color: #606060;"> 5:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">Grid.ColumnDefinitions</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum6" style="color: #606060;"> 6:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">StackPanel</span> <span style="color: #ff0000;">Grid</span>.<span style="color: #ff0000;">ColumnSpan</span><span style="color: #0000ff;">="2"</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum7" style="color: #606060;"> 7:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">live:SignInButton</span> <span style="color: #ff0000;">Name</span><span style="color: #0000ff;">="btnLogIn"</span> <span style="color: #ff0000;">Scopes</span><span style="color: #0000ff;">="wl.signin wl.basic wl.contacts_create"</span><span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum8" style="color: #606060;"> 8:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Button</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="btnCreateContact"</span> <span style="color: #ff0000;">Content</span><span style="color: #0000ff;">="Create Contact"</span> <span style="color: #ff0000;">Click</span><span style="color: #0000ff;">="btnCreateContact_Click"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum9" style="color: #606060;"> 9:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Name</span><span style="color: #0000ff;">="tbName"</span> <span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="600"</span> <span style="color: #ff0000;">Height</span><span style="color: #0000ff;">="150"</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="32"</span> <span style="color: #ff0000;">TextWrapping</span><span style="color: #0000ff;">="Wrap"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum10" style="color: #606060;"> 10:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Name</span><span style="color: #0000ff;">="tbGender"</span> <span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="600"</span> <span style="color: #ff0000;">Height</span><span style="color: #0000ff;">="150"</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="32"</span> <span style="color: #ff0000;">TextWrapping</span><span style="color: #0000ff;">="Wrap"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum11" style="color: #606060;"> 11:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Name</span><span style="color: #0000ff;">="tbLiveProfile"</span> <span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="600"</span> <span style="color: #ff0000;">Height</span><span style="color: #0000ff;">="150"</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="32"</span> <span style="color: #ff0000;">TextWrapping</span><span style="color: #0000ff;">="Wrap"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum12" style="color: #606060;"> 12:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Name</span><span style="color: #0000ff;">="tbError"</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">="Error Message"</span> <span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="600"</span> <span style="color: #ff0000;">Height</span><span style="color: #0000ff;">="150"</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="32"</span><span style="color: #0000ff;">/></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum13" style="color: #606060;"> 13:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">StackPanel</span><span style="color: #0000ff;">></span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum14" style="color: #606060;"> 14:</span>  </pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum15" style="color: #606060;"> 15:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">Grid</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>You will also want to make sure that your XML Namespaces for the Live SDK have been added to the page: </p> <div style="border: 1px solid silver; padding: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; text-align: left;" id="codeSnippetWrapper"> <div style="padding: 0px; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; text-align: left;" id="codeSnippet"> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum1" style="color: #606060;"> 1:</span> xmlns:live="using:Microsoft.Live.Controls"</pre> <!--CRLF--></div> </div> <p><em>Note: You will get “Invalid Markup” with the XAML provided because we are still in the developer preview stage. It is ok to proceed. </em></p> <p>The only thing to really pay attention to here is the <a href="http://msdn.microsoft.com/en-us/library/hh243646.aspx">Scopes</a> listed in the <strong>SignInButton</strong>. As you see we have three scopes. </p> <ol> <li>wl.signin - Single sign-in behavior. With <em>single sign-in</em>, users who are already signed in to Live Connect are also signed in to your website. </li> <li>wl.basic - Read access to a user's basic profile info. Also enables read access to a user's list of contacts. </li> <li>wl.contacts_create - Creation of new contacts in the user's address book. </li> </ol> <p>The first two are core and the last is an extended scope. We need all three of these to complete the requirements listed in this sample application. </p> <p>This will give us our user interface, now we will just need to wire up the event handlers which I am going to split up into two sections for learning purposes. </p> <h3>Coding Time – Basic User Information</h3> <p>Let’s go ahead and add in functionality to retrieve basic user information from the Live SDK. </p> <p>First, add the proper namespaces and then the following code:</p> <div style="border: 1px solid silver; padding: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; text-align: left;" id="codeSnippetWrapper"> <div style="padding: 0px; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; text-align: left;" id="codeSnippet"> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum1" style="color: #606060;"> 1:</span> <span style="color: #0000ff;">using</span> Microsoft.Live;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum2" style="color: #606060;"> 2:</span> <span style="color: #0000ff;">using</span> Microsoft.Live.Controls;</pre> <!--CRLF--></div> </div> <div style="border: 1px solid silver; padding: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; text-align: left;" id="codeSnippetWrapper"> <div style="padding: 0px; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; text-align: left;" id="codeSnippet"> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum1" style="color: #606060;"> 1:</span> <span style="color: #0000ff;">private</span> LiveConnectClient liveClient;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum2" style="color: #606060;"> 2:</span> <span style="color: #0000ff;">private</span> LiveConnectSession session;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum3" style="color: #606060;"> 3:</span>  </pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum4" style="color: #606060;"> 4:</span> <span style="color: #0000ff;">public</span> MainPage()</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum5" style="color: #606060;"> 5:</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum6" style="color: #606060;"> 6:</span> InitializeComponent();</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum7" style="color: #606060;"> 7:</span> <span style="color: #0000ff;">this</span>.btnLogIn.SessionChanged += btnLogIn_OnSessionChanged;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum8" style="color: #606060;"> 8:</span> }</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum9" style="color: #606060;"> 9:</span>  </pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum10" style="color: #606060;"> 10:</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> btnLogIn_OnSessionChanged(<span style="color: #0000ff;">object</span> sender, LiveConnectSessionChangedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum11" style="color: #606060;"> 11:</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum12" style="color: #606060;"> 12:</span> <span style="color: #0000ff;">if</span> (e.Session != <span style="color: #0000ff;">null</span> && e.Status == LiveConnectSessionStatus.Connected)</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum13" style="color: #606060;"> 13:</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum14" style="color: #606060;"> 14:</span> <span style="color: #0000ff;">this</span>.liveClient = <span style="color: #0000ff;">new</span> LiveConnectClient(e.Session);</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum15" style="color: #606060;"> 15:</span> session = e.Session;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum16" style="color: #606060;"> 16:</span> <span style="color: #0000ff;">this</span>.liveClient.GetCompleted += OnGetCompleted;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum17" style="color: #606060;"> 17:</span> <span style="color: #0000ff;">this</span>.liveClient.GetAsync(<span style="color: #006080;">"me"</span>, <span style="color: #0000ff;">null</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum18" style="color: #606060;"> 18:</span> }</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum19" style="color: #606060;"> 19:</span> <span style="color: #0000ff;">else</span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum20" style="color: #606060;"> 20:</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum21" style="color: #606060;"> 21:</span> <span style="color: #0000ff;">this</span>.liveClient = <span style="color: #0000ff;">null</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum22" style="color: #606060;"> 22:</span> }</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum23" style="color: #606060;"> 23:</span> }</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum24" style="color: #606060;"> 24:</span>  </pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum25" style="color: #606060;"> 25:</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> OnGetCompleted(<span style="color: #0000ff;">object</span> sender, LiveOperationCompletedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum26" style="color: #606060;"> 26:</span> { </pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum27" style="color: #606060;"> 27:</span> <span style="color: #0000ff;">if</span> (e.Error == <span style="color: #0000ff;">null</span>)</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum28" style="color: #606060;"> 28:</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum29" style="color: #606060;"> 29:</span> dynamic result = e.Result;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum30" style="color: #606060;"> 30:</span> <span style="color: #0000ff;">this</span>.tbName.Text = <span style="color: #006080;">"Hello, "</span> + result.first_name + <span style="color: #006080;">" "</span> + result.last_name;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum31" style="color: #606060;"> 31:</span> <span style="color: #0000ff;">this</span>.tbGender.Text = <span style="color: #006080;">"You are a "</span> + result.gender + <span style="color: #006080;">" that lives in "</span> + result.locale + <span style="color: #006080;">"."</span>;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum32" style="color: #606060;"> 32:</span> <span style="color: #0000ff;">this</span>.tbLiveProfile.Text = <span style="color: #006080;">"Your Live Profile can be found at: "</span> + result.link;</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum33" style="color: #606060;"> 33:</span> }</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum34" style="color: #606060;"> 34:</span> <span style="color: #0000ff;">else</span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum35" style="color: #606060;"> 35:</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum36" style="color: #606060;"> 36:</span> <span style="color: #0000ff;">this</span>.tbError.Text = e.Error.ToString();</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum37" style="color: #606060;"> 37:</span> }</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum38" style="color: #606060;"> 38:</span> }</pre> <!--CRLF--></div> </div> <p>The first thing that you will notice is that we are creating an event hander to handle the SessionChanged event. If we can determine that the session is valid then we create a new LiveConnectClient and pass the session to our LiveConnectSession. We finish up with adding an event handler on GetCompleted which will return the current users profile information and display them in our TextBlocks. Finally, we are outputting all errors to the tbError TextBlock. </p> <h3>Coding Time – Adding a new contact to the users Address Book</h3> <p>Let’s go ahead and add in functionality to add a new contact to the users address book from the Live SDK. </p> <div style="border: 1px solid silver; padding: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'courier new', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; text-align: left;" id="codeSnippetWrapper"> <div style="padding: 0px; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; text-align: left;" id="codeSnippet"> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum1" style="color: #606060;"> 1:</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> btnCreateContact_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum2" style="color: #606060;"> 2:</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum3" style="color: #606060;"> 3:</span> LiveConnectClient createContact = <span style="color: #0000ff;">new</span> LiveConnectClient(session);</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum4" style="color: #606060;"> 4:</span> var contact = <span style="color: #0000ff;">new</span> Dictionary<<span style="color: #0000ff;">string</span>, <span style="color: #0000ff;">object</span>>();</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum5" style="color: #606060;"> 5:</span> contact.Add(<span style="color: #006080;">"first_name"</span>, <span style="color: #006080;">"Michael"</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum6" style="color: #606060;"> 6:</span> contact.Add(<span style="color: #006080;">"last_name"</span>, <span style="color: #006080;">"Crump"</span>);</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum7" style="color: #606060;"> 7:</span> createContact.PostCompleted +=</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum8" style="color: #606060;"> 8:</span> <span style="color: #0000ff;">new</span> EventHandler<LiveOperationCompletedEventArgs>(CreateContactProperties_PostCompleted);</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum9" style="color: #606060;"> 9:</span> createContact.PostAsync(<span style="color: #006080;">"me/contacts"</span>, contact);</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum10" style="color: #606060;"> 10:</span>  </pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum11" style="color: #606060;"> 11:</span>  </pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum12" style="color: #606060;"> 12:</span> }</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum13" style="color: #606060;"> 13:</span>  </pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum14" style="color: #606060;"> 14:</span> <span style="color: #0000ff;">void</span> CreateContactProperties_PostCompleted(<span style="color: #0000ff;">object</span> sender, LiveOperationCompletedEventArgs e)</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum15" style="color: #606060;"> 15:</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum16" style="color: #606060;"> 16:</span> <span style="color: #0000ff;">if</span> (e.Error == <span style="color: #0000ff;">null</span>)</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum17" style="color: #606060;"> 17:</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum18" style="color: #606060;"> 18:</span> tbName.Text = <span style="color: #006080;">"Contact"</span> +</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum19" style="color: #606060;"> 19:</span> e.Result[<span style="color: #006080;">"first_name"</span>].ToString() + <span style="color: #006080;">" "</span> + e.Result[<span style="color: #006080;">"last_name"</span>].ToString() +</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum20" style="color: #606060;"> 20:</span> <span style="color: #006080;">" created with ID "</span> +</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum21" style="color: #606060;"> 21:</span> e.Result[<span style="color: #006080;">"id"</span>].ToString();</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum22" style="color: #606060;"> 22:</span> }</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum23" style="color: #606060;"> 23:</span> <span style="color: #0000ff;">else</span></pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum24" style="color: #606060;"> 24:</span> {</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum25" style="color: #606060;"> 25:</span> tbError.Text = <span style="color: #006080;">"Error calling API: "</span> + e.Error.ToString();</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum26" style="color: #606060;"> 26:</span> }</pre> <!--CRLF--> <pre style="text-align: left; padding: 0px; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'courier new', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none;"><span id="lnum27" style="color: #606060;"> 27:</span> }</pre> <!--CRLF--></div> </div> <p>In this sample, we are creating a new <strong>LiveConnectClient</strong> by passing into it the existing session. Once that is complete, we create a Dictionary and add the users first_name and last_name to the dictionary. Finally, we create a PostCompleted event handler which will return the textblock with a success or an error. The last call is PostAsync which send a POST request to the specified Uri as an asynchronous operation.</p> <h3>Ready for Liftoff</h3> <p>Go ahead and build the application and run it. </p> <p>When you first hit the “Sign In” Button you will be presented with the following: </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/____7_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="7" alt="7" src="http://www.silverlightshow.net/Storage/Users/mbcrump/____7_thumb.png" width="504" height="429" /></a></p> <p><em>Note: After you accept this one time then you will not have to accept it again.</em> </p> <p>Notice that the application says it you allow access then it will view your profile and contact list. The application automatically knows which features it is using by the scopes defined earlier. </p> <p>Select “Yes” and then click the “Sign In Button” located on the right hand side of your screen and you should see your Live profile information as long as you have filled it out in Windows Live. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/____9_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="9" alt="9" src="http://www.silverlightshow.net/Storage/Users/mbcrump/____9_thumb.png" width="326" height="219" /></a></p> <p>Next, click on the Create Contact button and you should see the following: </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/____10_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="10" alt="10" src="http://www.silverlightshow.net/Storage/Users/mbcrump/____10_thumb.png" width="411" height="63" /></a></p> <p>You can now sign into your <a href="http://explore.live.com/">Windows Live</a> account and select “Contacts” under “Hotmail” and see the contact that you just created. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/____11_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="11" alt="11" src="http://www.silverlightshow.net/Storage/Users/mbcrump/____11_thumb.png" width="541" height="208" /></a></p> <p>Congratulations, you have now completed your first Metro application using XAML/C# that uses the Live SDK. </p> <h3>Conclusion</h3> <p>At this point, we have seen how you would create a Windows 8 Metro application using XAML/C# that retrieves and updates information from the Live SDK. Now that you are equipped with the basics of using the Live SDK, I encourage you to explore the Live SDK further as we have barely scratched the surface. I want to thank you for reading this article and if you ever have any questions feel free to contact me on the various sources listed below. I also wanted to thank SilverlightShow for giving me the opportunity to share this information with everyone. </p> <p>You can follow Michael on Twitter at <a href="http://www.twitter.com/mbcrump">mbcrump</a> or keep up with his blog by visiting <a href="http://michaelcrump.net/">michaelcrump.net</a>.</p> http://www.silverlightshow.net/items/Using-the-Live-SDK-in-Windows-8-XAML-C-Metro-Applications.aspx editorial@silverlightshow.net (Michael Crump ) http://www.silverlightshow.net/items/Using-the-Live-SDK-in-Windows-8-XAML-C-Metro-Applications.aspx#comments http://www.silverlightshow.net/items/Using-the-Live-SDK-in-Windows-8-XAML-C-Metro-Applications.aspx Mon, 30 Jan 2012 03:59:34 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 10 Laps around Silverlight 5 (Part 10 of 10) <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-10-of-10.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/10-Laps-around-Silverlight-5-Part-10-of-10.aspx" data-count="horizontal" data-text="Reading SilverlightShow article '10 Laps around Silverlight 5 (Part 10 of 10)' by @mbcrump #sl5" data-url="http://slshow.net/vtToOa">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-10-of-10.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <div style="border:1px solid #dddddd;border-image: initial; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; padding-top: 5px; text-align: center;"><em><strong>This article is sponsored by <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=81&Task=Click&Mode=HTML&SiteID=1&PageID=41808" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=81&Task=Get&Mode=HTML&SiteID=1&PageID=41808" width="0" height="0" style="border-width: 0px;border-style: solid;" />Telerik RadControls for Silverlight</a>. For similarly awesome content check out <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=82&Task=Click&Mode=HTML&SiteID=1&PageID=3019" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=82&Task=Get&Mode=HTML&SiteID=1&PageID=3019" width="0" height="0" style="border-width: 0px;border-style: solid;" />Telerik XAMLflix</a>, your step-by-step guide to Telerik Silverlight and WPF controls. Get access to video tutorials, written tutorials, and tons of code! </strong></em></div> <p> <br /> To contact me directly please visit my blog at <a href="http://michaelcrump.net/">http://michaelcrump.net/</a> or through twitter at <a href="http://twitter.com/mbcrump">http://twitter.com/mbcrump</a>.</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/news/Free-Silverlight-Show-Webinar-Introduction-to-XAML-Development-on-Windows-8.aspx">Recording of Webinar: XAML Development on Windows 8</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/GetStarted.aspx">Get Started with Silverlight 4</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; border-image: initial;" 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></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 10 of the series “10 Laps around Silverlight 5.” If you have missed any other section then please see the Roadmap below. </p> To refresh your memory on what Silverlight is: <p>Microsoft Silverlight is an application framework for writing Rich Internet Applications. </p> The run-time environment is available as a plug-in for most web browsers and works on a variety of operating systems including Windows, Mac and Linux. <p>To recap what we learned in the previous section:</p> <ul> <li>We took a look at several new controls in Silverlight 5 including: Double and Triple click support and ComboBox Type-Ahead. </li> <li>We then took a deeper dive into the PivotViewer control as it is more complex than the others and provided additional links. </li> </ul> <p>In this article, I am going to discuss several new features that did not fit in any of the above categories.  We will discuss In-Browser HTML, PostScript and Tasks for TPL. Please review the Roadmap for the series before going any further.</p> <h3>The Roadmap for this Series</h3> <p>I’ve included the Roadmap for the series below as you may want to visit other sections as you learn Silverlight 5. I picked the following features as I thought that you may find them useful in your day-to-day work. If you want a specific topic covered then please leave it in the comments below.</p> <p>1) <strong><a href="http://www.silverlightshow.net/items/Silverlight-5-Part-1-of-10.aspx">Introduction to SL5 – This post which provides a brief history of Silverlight and relevant links.</a></strong> </p> <p>2) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-2-of-10.aspx">Binding- Ancestor Relative Source Binding and Implicit Data Templates.</a></strong></p> <p>3) <strong></strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-3.aspx" target="_self"><strong>Graphics</strong> <strong>–XNA 3D API and Improved Graphics Stack</strong>.</a></p> <p>4) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-4-of-10.aspx">Media - Low-Latency Sound using XNA and Remote Control and Media Command (Keys) Support.</a></strong></p> <p>5) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-5-of-10.aspx">Text - Text Tracking and Leading, Linked and Multi-column Text, OpenType Support, Pixel Snapped Text and TextOptions.</a></strong></p> <p>6) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-6-of-10.aspx">Operating System Integration - Part 1 - P/Invoke, Multiple Windows and Unrestricted File System Access in Full Trust.</a></strong></p> <p>7) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-7-of-10.aspx">Operating System Integration - Part 2 - Default Filename for SaveFileDialog, 64-bit browser support and Power Awareness.</a></strong></p> <p>8) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-8-of-10.aspx">Productivity and Performance - XAML Binding Debugging, Parser Performance Improvements and Multi-core JIT for improved start-up time.</a></strong></p> <p>9) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-9-of-10.aspx">Controls - Double and Triple click support, PivotViewer and ComboBox Type-Ahead.</a></strong></p> <p>10) <strong>Other items <strong>[This post] </strong></strong>- In-Browser HTML, PostScript and Tasks for TPL.</p> <h3></h3> <h3>In-Browser HTML</h3> <p>In Silverlight 4, we could use the WebBrowser control only in an “Out-of-Browser” application. This has changed in Silverlight 5 as we can now use the WebBrowser control in the browser (IE). It will however require that you make a few changes to your system. Let’s get started: </p> <p>1)<strong> Update the registry</strong> – Locate the following keys:</p> <p>If you running on a 32 bit machine, </p> <p><strong>HKEY_LOCAL_MACHINE\Software\Microsoft\Silverlight\</strong></p> <p>and if you are running on a 64-bit machine, </p> <p><strong>HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Silverlight\</strong></p> <p>change the <strong>UpdateConsentMode</strong> from a 0 to 1. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/________1_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="1" alt="1" src="http://www.silverlightshow.net/Storage/Users/mbcrump/________1_thumb.png" width="627" height="282" /></a></p> <p>2) <strong>Sign the XAP File</strong> - Right click on the Silverlight application and go to properties. Choose <strong>Signing</strong> and check the checkbox<strong> Sign the .XAP file</strong>. Now click on the button <strong>Create Test Certificate</strong>. Enter any password that you want and hit the OK button. Now click on the <strong>More Details</strong> button.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/__________2_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="2" alt="2" src="http://www.silverlightshow.net/Storage/Users/mbcrump/__________2_thumb.png" width="544" height="350" /></a></p> <p>Click on the <strong>Install Certificate</strong> button. Clicking on the button brings up the <strong>Certificate Import wizard</strong>. Click on the <strong>Next</strong> button and choose Place all certificates in the following store. Click on the Browse button. This will show you a Certificate Store. Choose <strong>Trusted Publisher</strong> and finish the wizard. Now repeat the same step to install this certificate in <strong>Trusted Root Certification Authorities</strong>.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/3_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="3" alt="3" src="http://www.silverlightshow.net/Storage/Users/mbcrump/3_thumb_1.png" width="486" height="442" /></a></p> <p>3) <strong>Enable Out-of-Browser and Require elevated trust when running in-browser.</strong> Right click on the Silverlight application and go to properties. Place a checkmark in <strong>Enable Out-of-Browser</strong> and <strong>Require elevated trust when running in-browser.</strong></p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/________4_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="4" alt="4" src="http://www.silverlightshow.net/Storage/Users/mbcrump/________4_thumb.png" width="573" height="464" /></a></p> <p>Now let’s switch over to the MainPage.xaml and replace the Grid with the following code:</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;">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 id="lnum2" style="color: #606060;"> 2:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">WebBrowser</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="webBrowser"</span> <span style="color: #ff0000;">Source</span><span style="color: #0000ff;">="http://michaelcrump.net/"</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;">Grid</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>If we run our application now (using Internet Explorer), then we will see the WebBrowser control working inside of the browser.</p> <p><em>Note: This will not work in Chrome, Safari, others (Only Internet Explorer).</em></p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/______5_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="5" alt="5" src="http://www.silverlightshow.net/Storage/Users/mbcrump/______5_thumb.png" width="566" height="360" /></a></p> <p>You can also add html pages to your project and point the source to that file as well. </p> <h3>PostScript Vector Printing</h3> <p>In Silverlight 4, we had bitmap-based printing. This meant that every time a page was going to print that Silverlight 4 sent the bitmap representing the entire page to the printer. We quickly found out that this resulted in horrible performance for larger print jobs. Now in Silverlight 5 we have PostScript Vector printing. This provides us with a much faster solution. Let’s get started building a sample application that uses this features. </p> <p>Let’s switch over to the MainPage.xaml and replace the Grid with the following code:</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;">StackPanel</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: #ff0000;">HorizontalAlignment</span><span style="color: #0000ff;">="Center"</span> <span style="color: #ff0000;">VerticalAlignment</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 id="lnum2" style="color: #606060;"> 2:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Button</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="basicVector"</span> <span style="color: #ff0000;">Click</span><span style="color: #0000ff;">="basicVector_Click"</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;">Button</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="forceVector"</span> <span style="color: #ff0000;">Click</span><span style="color: #0000ff;">="forceVector_Click"</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="lnum4" style="color: #606060;"> 4:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">StackPanel</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>We can navigate over to our MainPage.xaml.cs file and add in the following code snippet for our button event handlers:</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;">private</span> <span style="color: #0000ff;">void</span> basicVector_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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> PrintDocument document = <span style="color: #0000ff;">new</span> PrintDocument();</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> document.PrintPage += (s, ea) =></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="lnum6" style="color: #606060;"> 6:</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="lnum7" style="color: #606060;"> 7:</span> StackPanel stPanel = <span style="color: #0000ff;">new</span> StackPanel(); </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="lnum8" style="color: #606060;"> 8:</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="lnum9" style="color: #606060;"> 9:</span> <span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < 10; i++)</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="lnum10" style="color: #606060;"> 10:</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="lnum11" style="color: #606060;"> 11:</span> TextBlock tb = <span style="color: #0000ff;">new</span> TextBlock();</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="lnum12" style="color: #606060;"> 12:</span> tb.Text = <span style="color: #006080;">"Basic Vector mode."</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="lnum13" style="color: #606060;"> 13:</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="lnum14" style="color: #606060;"> 14:</span> stPanel.Children.Add(tb);</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="lnum15" style="color: #606060;"> 15:</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="lnum16" style="color: #606060;"> 16:</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="lnum17" style="color: #606060;"> 17:</span> ea.PageVisual = stPanel;</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="lnum18" style="color: #606060;"> 18:</span> ea.HasMorePages = <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;"><span id="lnum19" style="color: #606060;"> 19:</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="lnum20" style="color: #606060;"> 20:</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="lnum21" style="color: #606060;"> 21:</span> document.Print(<span style="color: #006080;">"Basic Vector Demo"</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="lnum22" style="color: #606060;"> 22:</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="lnum23" style="color: #606060;"> 23:</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="lnum24" style="color: #606060;"> 24:</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="lnum25" style="color: #606060;"> 25:</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> forceVector_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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="lnum26" style="color: #606060;"> 26:</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="lnum27" style="color: #606060;"> 27:</span> PrintDocument document = <span style="color: #0000ff;">new</span> PrintDocument();</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="lnum28" style="color: #606060;"> 28:</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="lnum29" style="color: #606060;"> 29:</span> document.PrintPage += (s, ea) =></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="lnum30" style="color: #606060;"> 30:</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="lnum31" style="color: #606060;"> 31:</span> StackPanel stPanel = <span style="color: #0000ff;">new</span> StackPanel();</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="lnum32" style="color: #606060;"> 32:</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="lnum33" style="color: #606060;"> 33:</span> <span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < 10; i++)</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="lnum34" style="color: #606060;"> 34:</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="lnum35" style="color: #606060;"> 35:</span> TextBlock tb = <span style="color: #0000ff;">new</span> TextBlock();</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="lnum36" style="color: #606060;"> 36:</span> tb.Text = <span style="color: #006080;">"Forced Vector mode."</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="lnum37" style="color: #606060;"> 37:</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="lnum38" style="color: #606060;"> 38:</span> stPanel.Children.Add(tb);</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="lnum39" style="color: #606060;"> 39:</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="lnum40" style="color: #606060;"> 40:</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="lnum41" style="color: #606060;"> 41:</span> ea.PageVisual = stPanel;</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="lnum42" style="color: #606060;"> 42:</span> ea.HasMorePages = <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;"><span id="lnum43" style="color: #606060;"> 43:</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="lnum44" style="color: #606060;"> 44:</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="lnum45" style="color: #606060;"> 45:</span> PrinterFallbackSettings settings = <span style="color: #0000ff;">new</span> PrinterFallbackSettings();</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="lnum46" style="color: #606060;"> 46:</span> settings.ForceVector = <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;"><span id="lnum47" style="color: #606060;"> 47:</span> settings.OpacityThreshold = 0.7;</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="lnum48" style="color: #606060;"> 48:</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="lnum49" style="color: #606060;"> 49:</span> document.Print(<span style="color: #006080;">"Forced Vector Print"</span>, settings);</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="lnum50" style="color: #606060;"> 50:</span> }</pre> <!--CRLF--></div> </div> <p>In our first button, we have a basic PostScript Vector Printing job. We create a <strong>PrintDocument</strong> (which was also in SL4), then add a <strong>PrintPage</strong> with some basic text to it. We finally print the document using Vector printing with <strong>document.Print</strong>.</p> <p>In our second button, we do the same thing but we call <strong>PrinterFallbackSettings</strong> and force the print job to print in Vector mode. We can also set the Opacity value by calling <strong>OpacityThreshold</strong>. </p> <h3>Tasks Parallel Library (TPL)</h3> <p>In short, TPL is to simply asynchronous methods. Silverlight 5 does not include the full TPL but it does provide Tasks and it’s related factories. Which is exactly what you want! Let’s get started. </p> <p>We are going to use a sample XML file provided by Microsoft found <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms762271(v=vs.85).aspx">here</a>. Go ahead and download it and add it to your Web Project with the name of books.xml. </p> <p>Next, Let’s go ahead and navigate over to our MainPage.xaml.cs file and add in the proper namespaces to use TPL. Next, we will add in the second code snippet:</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;">using</span> System;</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;">using</span> System.Linq;</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;">using</span> System.Net;</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> <span style="color: #0000ff;">using</span> System.Threading.Tasks;</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> <span style="color: #0000ff;">using</span> System.Windows;</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="lnum6" style="color: #606060;"> 6:</span> <span style="color: #0000ff;">using</span> System.Windows.Controls;</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="lnum7" style="color: #606060;"> 7:</span> <span style="color: #0000ff;">using</span> System.Diagnostics;</pre> <!--CRLF--></div> </div> <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;">public</span> MainPage()</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> InitializeComponent();</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> Loaded += <span style="color: #0000ff;">new</span> RoutedEventHandler(MainPage_Loaded);</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> }</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="lnum6" style="color: #606060;"> 6:</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="lnum7" style="color: #606060;"> 7:</span> <span style="color: #0000ff;">void</span> MainPage_Loaded(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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="lnum8" style="color: #606060;"> 8:</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="lnum9" style="color: #606060;"> 9:</span> <span style="color: #0000ff;">string</span> uri = <span style="color: #006080;">"http://localhost:15863/books.xml"</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="lnum10" style="color: #606060;"> 10:</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="lnum11" style="color: #606060;"> 11:</span> var request = HttpWebRequest.Create(uri);</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="lnum12" style="color: #606060;"> 12:</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="lnum13" style="color: #606060;"> 13:</span> Task.Factory.FromAsync<WebResponse>(</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="lnum14" style="color: #606060;"> 14:</span> request.BeginGetResponse, request.EndGetResponse, <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;"><span id="lnum15" style="color: #606060;"> 15:</span> .ContinueWith(</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="lnum16" style="color: #606060;"> 16:</span> task =></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="lnum17" style="color: #606060;"> 17:</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="lnum18" style="color: #606060;"> 18:</span> var response = (HttpWebResponse)task.Result;</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="lnum19" style="color: #606060;"> 19:</span> Debug.WriteLine(<span style="color: #006080;">"Content Type: "</span> + response.ContentType);</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="lnum20" style="color: #606060;"> 20:</span> Debug.WriteLine(<span style="color: #006080;">"Content Length: "</span> + response.ContentLength);</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="lnum21" style="color: #606060;"> 21:</span> Debug.WriteLine(<span style="color: #006080;">"Method: "</span> + response.Method);</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="lnum22" style="color: #606060;"> 22:</span> Debug.WriteLine(<span style="color: #006080;">"Status Code: "</span> + response.StatusCode);</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="lnum23" style="color: #606060;"> 23:</span> Debug.WriteLine(<span style="color: #006080;">"Status Description: "</span> + response.StatusDescription); </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="lnum24" style="color: #606060;"> 24:</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="lnum25" style="color: #606060;"> 25:</span> }</pre> <!--CRLF--></div> </div> <p><em>Note: You will need to change the localhost port in the above code sample before proceeding. </em></p> <p>Go ahead and run the application and then look at your Output window in VS2010. You should see the following information. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/______6_2.png"><img style="border:0px; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" title="6" alt="6" src="http://www.silverlightshow.net/Storage/Users/mbcrump/______6_thumb.png" width="479" height="311" /></a></p> <p>The thing to note here is Task.Factory.FromAsync. This creates a Tasks that represents a pair of begin and end methods that conform to the Asynchronous Programming Model Pattern. </p> <h3>Conclusion</h3> <p>At this point, we have taken a dive into all of the new features of Silverlight 5. Now that you are equipped with a solid understanding of what Silverlight 5 has to offer, you can begin to use this in your own applications. I want to thank you for reading this series and if you ever have any questions feel free to contact me on the various sources listed below. I also wanted to thank <a href="http://www.silverlightshow.net/">SilverlightShow.Net</a> and <a href="http://www.telerik.com/">Telerik</a> for giving me the opportunity to share this information  with everyone. I hope that you enjoyed this series and if you To contact me directly please visit my blog at <a href="http://michaelcrump.net/">http://michaelcrump.net/</a> or through twitter at <a href="http://twitter.com/mbcrump">http://twitter.com/mbcrump</a>.</p> http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-10-of-10.aspx editorial@silverlightshow.net (Michael Crump ) http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-10-of-10.aspx#comments http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-10-of-10.aspx Mon, 12 Dec 2011 21:50:15 GMT 10 Laps around Silverlight 5 (Part 9 of 10) <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-9-of-10.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/10-Laps-around-Silverlight-5-Part-9-of-10.aspx" data-count="horizontal" data-text="Reading SilverlightShow article '10 Laps around Silverlight 5 (Part 9 of 10)' by @mbcrump #sl5" data-url="http://slshow.net/uprKjj">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-9-of-10.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <div style="border:1px solid #dddddd;border-image: initial; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; padding-top: 5px; text-align: center;"><em><strong>This article is sponsored by <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=81&Task=Click&Mode=HTML&SiteID=1&PageID=41808" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=81&Task=Get&Mode=HTML&SiteID=1&PageID=41808" width="0" height="0" style="border-width: 0px;border-style: solid;" />Telerik RadControls for Silverlight</a>. For similarly awesome content check out <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=82&Task=Click&Mode=HTML&SiteID=1&PageID=3019" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=82&Task=Get&Mode=HTML&SiteID=1&PageID=3019" width="0" height="0" style="border-width: 0px;border-style: solid;" />Telerik XAMLflix</a>, your step-by-step guide to Telerik Silverlight and WPF controls. Get access to video tutorials, written tutorials, and tons of code! </strong></em></div> <p> <br /> To contact me directly please visit my blog at <a href="http://michaelcrump.net/">http://michaelcrump.net/</a> or through twitter at <a href="http://twitter.com/mbcrump">http://twitter.com/mbcrump</a>.</p> <p>This article is Part 9 of the series “10 Laps around Silverlight 5.” If you have missed any other section then please see the Roadmap below. </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/news/Free-Silverlight-Show-Webinar-Introduction-to-XAML-Development-on-Windows-8.aspx">Upcoming Webinar on Nov 29th: XAML Development on Windows 8</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/GetStarted.aspx">Get Started with Silverlight 4</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; border-image: initial;" 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></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> To refresh your memory on what Silverlight is: <p>Microsoft Silverlight is an application framework for writing Rich Internet Applications. </p> The run-time environment is available as a plug-in for most web browsers and works on a variety of operating systems including Windows, Mac and Linux. <p>To recap what we learned in the previous section:</p> <ul> <li>We learned how you could specify a break point inside of a Binding Expressions in Silverlight 5. We also learned how you could use this same functionality inside of Silverlight 4 with the Silverlight 5 SDK installed. </li> <li>We then created a sample application that contained a binding error and took a look at the output window to investigate it further.  We were then able to determine the source of our error and correct it quickly. </li> <li>We finished up with listing several productivity and performance improvements in Silverlight 5 that you may not be aware of. </li> </ul> <p>In this article, I am going to discuss several new features/controls such as Double and Triple click support, PivotViewer and ComboBox Type-Ahead. Please review the Roadmap for the series before going any further.</p> <h3>The Roadmap for this Series</h3> <p>I’ve included the Roadmap for the series below as you may want to visit other sections as you learn Silverlight 5. I picked the following features as I thought that you may find them useful in your day-to-day work. If you want a specific topic covered then please leave it in the comments below.</p> <p>1) <strong><a href="http://www.silverlightshow.net/items/Silverlight-5-Part-1-of-10.aspx">Introduction to SL5 – This post which provides a brief history of Silverlight and relevant links.</a></strong> </p> <p>2) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-2-of-10.aspx">Binding- Ancestor Relative Source Binding and Implicit Data Templates.</a></strong></p> <p>3) <strong></strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-3.aspx" target="_self"><strong>Graphics</strong> <strong>–XNA 3D API and Improved Graphics Stack</strong>.</a></p> <p>4) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-4-of-10.aspx">Media - Low-Latency Sound using XNA and Remote Control and Media Command (Keys) Support.</a></strong></p> <p>5) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-5-of-10.aspx">Text - Text Tracking and Leading, Linked and Multi-column Text, OpenType Support, Pixel Snapped Text and TextOptions.</a></strong></p> <p>6) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-6-of-10.aspx">Operating System Integration - Part 1 - P/Invoke, Multiple Windows and Unrestricted File System Access in Full Trust.</a></strong></p> <p>7) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-7-of-10.aspx">Operating System Integration - Part 2 - Default Filename for SaveFileDialog, 64-bit browser support and Power Awareness.</a></strong></p> <p>8) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-8-of-10.aspx">Productivity and Performance - XAML Binding Debugging, Parser Performance Improvements and Multi-core JIT for improved start-up time.</a></strong></p> <p>9) <strong>Controls</strong> <strong>[This post] </strong>- Double and Triple click support, PivotViewer and ComboBox Type-Ahead.</p> <p>10) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-10-of-10.aspx" target="_self">Other items - In-Browser HTML, PostScript and Tasks for TPL</a>.</strong></p> <h3></h3> <h3>Double and Triple Click Support</h3> <p>One of the new features in Silverlight 5 is the ability to use Double and Triple Click Support. This functionality will tell you how many times the user has clicked the mouse button. The property is called <strong>ClickCount</strong> and resides in the <strong>MouseButtonEventArgs</strong> class. Let’s take a look at how to use this new feature.</p> <p>Fire up a new Silverlight 5 project and give it any name that you want. </p> <p>Switch over to the MainPage.xaml.cs and add the following code:<em> (Note: You may not need the MainPage() Method section)</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;">public</span> MainPage()</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> InitializeComponent();</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>  </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="lnum6" style="color: #606060;"> 6:</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> textBlock1_MouseLeftButtonDown(<span style="color: #0000ff;">object</span> sender, MouseButtonEventArgs 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 id="lnum7" style="color: #606060;"> 7:</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="lnum8" style="color: #606060;"> 8:</span> textBlock1.Text = e.ClickCount.ToString();</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="lnum9" style="color: #606060;"> 9:</span> }</pre> <!--CRLF--></div> </div> <p>Switch back over to the MainPage.xaml and add in the following code replacing the current Grid:</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;">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 id="lnum2" style="color: #606060;"> 2:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Border</span> <span style="color: #ff0000;">BorderBrush</span><span style="color: #0000ff;">="Black"</span> <span style="color: #ff0000;">BorderThickness</span><span style="color: #0000ff;">="1"</span> <span style="color: #ff0000;">Margin</span><span style="color: #0000ff;">="52,49,68,74"</span> <span style="color: #ff0000;">CornerRadius</span><span style="color: #0000ff;">="10"</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;">TextBlock</span> <span style="color: #ff0000;">Height</span><span style="color: #0000ff;">="152"</span> <span style="color: #ff0000;">HorizontalAlignment</span><span style="color: #0000ff;">="Center"</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="textBlock1"</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">="0"</span> <span style="color: #ff0000;">VerticalAlignment</span><span style="color: #0000ff;">="Center"</span> <span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="244"</span> <span style="color: #ff0000;">MouseLeftButtonDown</span><span style="color: #0000ff;">="textBlock1_MouseLeftButtonDown"</span> <span style="color: #ff0000;">Foreground</span><span style="color: #0000ff;">="#FFFF2E2E"</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="96"</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 id="lnum4" style="color: #606060;"> 4:</span> <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 id="lnum5" style="color: #606060;"> 5:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">Grid</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>If we go ahead and run the application then we will see the following application. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/SNAGHTMLf7d6db1.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="SNAGHTMLf7d6db1" alt="SNAGHTMLf7d6db1" src="http://www.silverlightshow.net/Storage/Users/mbcrump/SNAGHTMLf7d6db1_thumb.png" width="304" height="268" /></a></p> <p>Go ahead and begin clicking inside of the border and you will see the number increase. If you wait a few seconds and click again then you will notice that it reset itself. You could easily add If..Then… statements to determine what click count number they are on. This may be helpful for a 35 click Easter egg. :) </p> <h3>PivotViewer</h3> <br /> <p>Microsoft’s Silverlight Team defines it as the following: The Silverlight PivotViewer makes it easier to interact with massive amounts of data on the web in ways that are powerful, informative and valuable. I couldn’t agree more. Let’s begin today by creating a SL5 application that uses the PivotViewer control and displays a collection of movies. <em>(Classic example, eh?) </em></p> <p>Please note that this sample barely scratches the surface of what you can do with the PivotViewer. I’ve included an official link by Microsoft at the bottom of this post for your reference. </p> <p>Fire up a new Silverlight 5 project and give it the name <strong>PivotViewer</strong>. </p> <p>Switch over to the MainPage.xaml.cs and add the following code:</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;">using</span> System;</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;">using</span> System.Linq;</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;">using</span> System.Windows;</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> <span style="color: #0000ff;">using</span> System.Windows.Controls;</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> <span style="color: #0000ff;">using</span> System.Collections.ObjectModel;</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="lnum6" style="color: #606060;"> 6:</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="lnum7" style="color: #606060;"> 7:</span> <span style="color: #0000ff;">namespace</span> PivotViewer</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="lnum8" style="color: #606060;"> 8:</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="lnum9" style="color: #606060;"> 9:</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; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; 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="lnum10" style="color: #606060;"> 10:</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="lnum11" style="color: #606060;"> 11:</span> <span style="color: #0000ff;">private</span> ObservableCollection<Movie> Movies;</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="lnum12" style="color: #606060;"> 12:</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="lnum13" style="color: #606060;"> 13:</span> <span style="color: #0000ff;">public</span> MainPage()</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="lnum14" style="color: #606060;"> 14:</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="lnum15" style="color: #606060;"> 15:</span> InitializeComponent();</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="lnum16" style="color: #606060;"> 16:</span> Movies = <span style="color: #0000ff;">new</span> ObservableCollection<Movie>();</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="lnum17" style="color: #606060;"> 17:</span> <span style="color: #0000ff;">for</span> (Int64 i = 0; i < 500; i++)</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="lnum18" style="color: #606060;"> 18:</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="lnum19" style="color: #606060;"> 19:</span> Movies.Add(<span style="color: #0000ff;">new</span> Movie() { Title = <span style="color: #006080;">"Ice Age"</span> + i.ToString(), CountryOfOrigin = <span style="color: #006080;">"USA"</span>, Description = <span style="color: #006080;">"Set during the Ice Age."</span>, Director = <span style="color: #006080;">"Chris Wedge"</span> + i.ToString(), Duration = 90, ReleaseDate = <span style="color: #0000ff;">new</span> DateTime(2002, 09, 03) });</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="lnum20" style="color: #606060;"> 20:</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="lnum21" style="color: #606060;"> 21:</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="lnum22" style="color: #606060;"> 22:</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="lnum23" style="color: #606060;"> 23:</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="lnum24" style="color: #606060;"> 24:</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> UserControl_Loaded(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs 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 id="lnum25" style="color: #606060;"> 25:</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="lnum26" style="color: #606060;"> 26:</span> MoviePivot.ItemsSource = Movies;</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="lnum27" style="color: #606060;"> 27:</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="lnum28" style="color: #606060;"> 28:</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="lnum29" style="color: #606060;"> 29:</span> }</pre> <!--CRLF--></div> </div> <br /> We need to create a new class now named <strong>Movie</strong>.  Inside of that class should look like the following: <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;">using</span> System;</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> <span style="color: #0000ff;">namespace</span> PivotViewer</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> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> Movie</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="lnum6" style="color: #606060;"> 6:</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="lnum7" style="color: #606060;"> 7:</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> Title { get; set; }</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="lnum8" style="color: #606060;"> 8:</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> Duration { get; set; }</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="lnum9" style="color: #606060;"> 9:</span> <span style="color: #0000ff;">public</span> DateTime ReleaseDate{ get; set; }</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="lnum10" style="color: #606060;"> 10:</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> CountryOfOrigin { get; set; }</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="lnum11" style="color: #606060;"> 11:</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> Description { get; set; }</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="lnum12" style="color: #606060;"> 12:</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> Director { get; set; }</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="lnum13" style="color: #606060;"> 13:</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="lnum14" style="color: #606060;"> 14:</span> }</pre> <!--CRLF--></div> </div> <p>Switch back over to the MainPage.xaml and add in the following code replacing everything:</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;">UserControl</span> <span style="color: #ff0000;">x:Class</span><span style="color: #0000ff;">="PivotViewer.MainPage"</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: #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: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; 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: #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: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; 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> <span style="color: #ff0000;">xmlns:d</span><span style="color: #0000ff;">="http://schemas.microsoft.com/expression/blend/2008"</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> <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 id="lnum6" style="color: #606060;"> 6:</span> <span style="color: #ff0000;">xmlns:pivot</span><span style="color: #0000ff;">="clr-namespace:System.Windows.Controls.Pivot;assembly=System.Windows.Controls.Pivot"</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="lnum7" style="color: #606060;"> 7:</span> <span style="color: #ff0000;">Loaded</span><span style="color: #0000ff;">="UserControl_Loaded"</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="lnum8" style="color: #606060;"> 8:</span> <span style="color: #ff0000;">mc:Ignorable</span><span style="color: #0000ff;">="d"</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="lnum9" style="color: #606060;"> 9:</span> <span style="color: #ff0000;">d:DesignHeight</span><span style="color: #0000ff;">="300"</span> <span style="color: #ff0000;">d:DesignWidth</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: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; 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="lnum10" style="color: #606060;"> 10:</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="lnum11" style="color: #606060;"> 11:</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; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; 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="lnum12" style="color: #606060;"> 12:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">pivot:PivotViewer</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="MoviePivot"</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="lnum13" style="color: #606060;"> 13:</span> <span style="color: #ff0000;">AccentColor</span><span style="color: #0000ff;">="LightGreen"</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="lnum14" style="color: #606060;"> 14:</span> <span style="color: #ff0000;">Background</span><span style="color: #0000ff;">="LightGray"</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="lnum15" style="color: #606060;"> 15:</span> <span style="color: #ff0000;">ControlBackground</span><span style="color: #0000ff;">="LightYellow"</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="lnum16" style="color: #606060;"> 16:</span> <span style="color: #ff0000;">SecondaryBackground</span><span style="color: #0000ff;">="AntiqueWhite"</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="lnum17" style="color: #606060;"> 17:</span> <span style="color: #ff0000;">SecondaryForeground</span><span style="color: #0000ff;">="Bisque"</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="lnum18" style="color: #606060;"> 18:</span> <span style="color: #ff0000;">SecondaryItemValueBackgroundColor</span><span style="color: #0000ff;">="Chocolate"</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="lnum19" style="color: #606060;"> 19:</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="lnum20" style="color: #606060;"> 20:</span> <span style="color: #008000;"><!--Setting PivotProperties--></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="lnum21" style="color: #606060;"> 21:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">pivot:PivotViewer.PivotProperties</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="lnum22" style="color: #606060;"> 22:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">pivot:PivotViewerStringProperty</span> <span style="color: #ff0000;">Id</span><span style="color: #0000ff;">="FTitle"</span> <span style="color: #ff0000;">Options</span><span style="color: #0000ff;">="CanFilter"</span> <span style="color: #ff0000;">DisplayName</span><span style="color: #0000ff;">="Title"</span> <span style="color: #ff0000;">Binding</span><span style="color: #0000ff;">="{Binding 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 id="lnum23" style="color: #606060;"> 23:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">pivot:PivotViewerStringProperty</span> <span style="color: #ff0000;">Id</span><span style="color: #0000ff;">="FDuration"</span> <span style="color: #ff0000;">Options</span><span style="color: #0000ff;">="CanFilter"</span> <span style="color: #ff0000;">DisplayName</span><span style="color: #0000ff;">="Duration"</span> <span style="color: #ff0000;">Binding</span><span style="color: #0000ff;">="{Binding Duration}"</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="lnum24" style="color: #606060;"> 24:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">pivot:PivotViewerStringProperty</span> <span style="color: #ff0000;">Id</span><span style="color: #0000ff;">="FDirector"</span> <span style="color: #ff0000;">Options</span><span style="color: #0000ff;">="CanFilter"</span> <span style="color: #ff0000;">DisplayName</span><span style="color: #0000ff;">="Director"</span> <span style="color: #ff0000;">Binding</span><span style="color: #0000ff;">="{Binding Director}"</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="lnum25" style="color: #606060;"> 25:</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="lnum26" style="color: #606060;"> 26:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">pivot:PivotViewer.PivotProperties</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="lnum27" style="color: #606060;"> 27:</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="lnum28" style="color: #606060;"> 28:</span> <span style="color: #008000;"><!--Setting data--></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="lnum29" style="color: #606060;"> 29:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">pivot:PivotViewer.ItemTemplates</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="lnum30" style="color: #606060;"> 30:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">pivot:PivotViewerItemTemplate</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="lnum31" style="color: #606060;"> 31:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Border</span> <span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="200"</span> <span style="color: #ff0000;">Height</span><span style="color: #0000ff;">="200"</span> <span style="color: #ff0000;">Background</span><span style="color: #0000ff;">="CadetBlue"</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="lnum32" style="color: #606060;"> 32:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">StackPanel</span> <span style="color: #ff0000;">Orientation</span><span style="color: #0000ff;">="Vertical"</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="lnum33" style="color: #606060;"> 33:</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="lnum34" style="color: #606060;"> 34:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">StackPanel</span> <span style="color: #ff0000;">Orientation</span><span style="color: #0000ff;">="Horizontal"</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="lnum35" style="color: #606060;"> 35:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">="{Binding Title}"</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="16"</span> <span style="color: #ff0000;">Foreground</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 id="lnum36" style="color: #606060;"> 36:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">="("</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="16"</span> <span style="color: #ff0000;">Foreground</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: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; 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="lnum37" style="color: #606060;"> 37:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">="{Binding Duration}"</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="16"</span> <span style="color: #ff0000;">Foreground</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 id="lnum38" style="color: #606060;"> 38:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">=")"</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="16"</span> <span style="color: #ff0000;">Foreground</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: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; 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="lnum39" style="color: #606060;"> 39:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">StackPanel</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="lnum40" style="color: #606060;"> 40:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">="{Binding Director}"</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="16"</span> <span style="color: #ff0000;">Foreground</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: white; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; 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="lnum41" style="color: #606060;"> 41:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">="{Binding CountryOfOrigin}"</span> <span style="color: #ff0000;">FontSize</span><span style="color: #0000ff;">="16"</span> <span style="color: #ff0000;">Foreground</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 id="lnum42" style="color: #606060;"> 42:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">StackPanel</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="lnum43" style="color: #606060;"> 43:</span> <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: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; 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="lnum44" style="color: #606060;"> 44:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">pivot:PivotViewerItemTemplate</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="lnum45" style="color: #606060;"> 45:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">pivot:PivotViewer.ItemTemplates</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="lnum46" style="color: #606060;"> 46:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">pivot:PivotViewer</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="lnum47" style="color: #606060;"> 47:</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; background-color: #f4f4f4; margin-top: 0em; margin-right: 0em; margin-bottom: 0em; 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="lnum48" style="color: #606060;"> 48:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">UserControl</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>If we run our application and select a few items then we will see the following screen. As you can tell when the application loaded that it contained 500 items – Wow!</p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/SNAGHTMLf991cf3.png"><img style="border:0px; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" title="SNAGHTMLf991cf3" alt="SNAGHTMLf991cf3" src="http://www.silverlightshow.net/Storage/Users/mbcrump/SNAGHTMLf991cf3_thumb.png" width="613" height="570" /></a></p> <p>I’ve barely touched on the amount of things that you can do with PivotViewer. If you want to learn more than please visit the Silverlight site located <a href="http://www.silverlight.net/learn/data-networking/pivot-viewer/pivotviewer-control">here</a>. </p> <h3>Combo-Box Type Ahead</h3> <br /> <p>Another new feature in Silverlight 5 is Combo-Box Type Ahead. This makes choosing items from a long list very simple. Let’s go ahead and build a sample application. </p> <p>Fire up a new Silverlight 5 project and give it any name that want. </p> <p>Switch over to the MainPage.xaml.cs and add the following code:</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;">public</span> MainPage()</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> InitializeComponent();</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> var lstDevelopers = <span style="color: #0000ff;">new</span> List<<span style="color: #0000ff;">string</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> { <span style="color: #006080;">"Michael Crump"</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="lnum6" style="color: #606060;"> 6:</span> <span style="color: #006080;">"Pete Brown"</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="lnum7" style="color: #606060;"> 7:</span> <span style="color: #006080;">"Victor G."</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="lnum8" style="color: #606060;"> 8:</span> <span style="color: #006080;">"Scott Hanselman"</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="lnum9" style="color: #606060;"> 9:</span> <span style="color: #006080;">"Jesse Liberty"</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="lnum10" style="color: #606060;"> 10:</span> <span style="color: #006080;">"Shawn Wildermuth"</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="lnum11" style="color: #606060;"> 11:</span> <span style="color: #006080;">"Scott Gu"</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="lnum12" style="color: #606060;"> 12:</span> <span style="color: #006080;">"Joel Cochran"</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="lnum13" style="color: #606060;"> 13:</span> <span style="color: #006080;">"Kunal Chowdhurry"</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="lnum14" style="color: #606060;"> 14:</span> cbDevelopers.ItemsSource = lstDevelopers;</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="lnum15" style="color: #606060;"> 15:</span> }</pre> <!--CRLF--></div> </div> <p>Switch back over to the MainPage.xaml and add in the following code replacing the existing Grid:</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;">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 id="lnum2" style="color: #606060;"> 2:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">ComboBox</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="cbDevelopers"</span> <span style="color: #ff0000;">Height</span><span style="color: #0000ff;">="40"</span> <span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="150"</span> <span style="color: #ff0000;">Margin</span><span style="color: #0000ff;">="20"</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;">Grid</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>If we run our application and begin typing then we will see the ComboBox automatically highlights the row that matches our selection.</p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/_image_2.png"><img style="border:0px; border-image: initial; background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" title="image" alt="image" src="http://www.silverlightshow.net/Storage/Users/mbcrump/_image_thumb.png" width="161" height="240" /></a></p> <h3>Conclusion</h3> <p>At this point, we have seen how you would use Double and Triple click support, PivotViewer and ComboBox Type-Ahead. In the next and final part of the series, I am going to take a look at several new features shipping with Silverlight 5 including : In-Browser HTML, PostScript and Tasks for TPL.  Again, thanks for reading and please come back for the next part.</p> <p>To contact me directly please visit my blog at <a href="http://michaelcrump.net/">http://michaelcrump.net/</a> or through twitter at <a href="http://twitter.com/mbcrump">http://twitter.com/mbcrump</a>.</p> http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-9-of-10.aspx editorial@silverlightshow.net (Michael Crump ) http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-9-of-10.aspx#comments http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-9-of-10.aspx Tue, 06 Dec 2011 12:27:00 GMT 10 Laps around Silverlight 5 (Part 8 of 10) <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-8-of-10.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/10-Laps-around-Silverlight-5-Part-8-of-10.aspx" data-count="horizontal" data-text="Reading SilverlightShow article '10 Laps around Silverlight 5 (Part 8 of 10)' by @mbcrump #sl5" data-url="http://slshow.net/tf6K6i">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-8-of-10.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <div style="border:1px solid #dddddd;border-image: initial; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; padding-top: 5px; text-align: center;"><em><strong>This article is sponsored by <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=81&Task=Click&Mode=HTML&SiteID=1&PageID=41808" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=81&Task=Get&Mode=HTML&SiteID=1&PageID=41808" width="0" height="0" style="border-width: 0px;border-style: solid;" />Telerik RadControls for Silverlight</a>. For similarly awesome content check out <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=82&Task=Click&Mode=HTML&SiteID=1&PageID=3019" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=82&Task=Get&Mode=HTML&SiteID=1&PageID=3019" width="0" height="0" style="border-width: 0px;border-style: solid;" />Telerik XAMLflix</a>, your step-by-step guide to Telerik Silverlight and WPF controls. Get access to video tutorials, written tutorials, and tons of code! </strong></em></div> <p> To contact me directly please visit my blog at <a href="http://michaelcrump.net/">http://michaelcrump.net/</a> or through twitter at <a href="http://twitter.com/mbcrump">http://twitter.com/mbcrump</a>.</p> <p>This article is Part 8 of the series “10 Laps around Silverlight 5.” If you have missed any other section then please see the Roadmap below. <br /> <br /> </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/news/Free-Silverlight-Show-Webinar-Introduction-to-XAML-Development-on-Windows-8.aspx">Upcoming Webinar on Nov 29th: XAML Development on Windows 8</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/GetStarted.aspx">Get Started with Silverlight 4</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; border-image: initial;" 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></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> To refresh your memory on what Silverlight is: <p>Microsoft Silverlight is an application framework for writing Rich Internet Applications. </p> The run-time environment is available as a plug-in for most web browsers and works on a variety of operating systems including Windows, Mac and Linux. <p>To recap what we learned in the previous section:</p> <ul> <li>We learned how you could specify a default filename when using the SaveFileDialog prompt. We also discussed how you could run the application in elevated trust to prevent the security warning from being displayed.  </li> <li>We then took a look at 64-bit browser support that is included with Silverlight 5 and learned that if your user is using a 64-bit browser then they will be redirected to a location to download the Silverlight 5 x64 runtime.  </li> <li>We wrapped up a short section on new and improved power awareness for media applications. </li> </ul> <p>In this article, I am going to discuss productivity and performance enhancements in Silverlight 5 including: XAML Binding Debugging, Parser Performance Improvements and Multi-core JIT for improved start-up time. Please review the Roadmap for the series before going any further.</p> <h3>The Roadmap for this Series</h3> <p>I’ve included the Roadmap for the series below as you may want to visit other sections as you learn Silverlight 5. I picked the following features as I thought that you may find them useful in your day-to-day work. If you want a specific topic covered then please leave it in the comments below.</p> <p>1) <strong><a href="http://www.silverlightshow.net/items/Silverlight-5-Part-1-of-10.aspx">Introduction to SL5 – This post which provides a brief history of Silverlight and relevant links.</a></strong> </p> <p>2) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-2-of-10.aspx">Binding- Ancestor Relative Source Binding and Implicit Data Templates.</a></strong></p> <p>3) <strong></strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-3.aspx" target="_self"><strong>Graphics</strong> <strong>–XNA 3D API and Improved Graphics Stack</strong>.</a></p> <p>4) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-4-of-10.aspx">Media - Low-Latency Sound using XNA and Remote Control and Media Command (Keys) Support.</a></strong></p> <p>5) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-5-of-10.aspx">Text - Text Tracking and Leading, Linked and Multi-column Text, OpenType Support, Pixel Snapped Text and TextOptions.</a></strong></p> <p>6) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-6-of-10.aspx">Operating System Integration - Part 1 - P/Invoke, Multiple Windows and Unrestricted File System Access in Full Trust.</a></strong></p> <p>7) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-7-of-10.aspx">Operating System Integration - Part 2 - Default Filename for SaveFileDialog, 64-bit browser support and Power Awareness.</a></strong></p> <p>8) <strong>Productivity and Performance [This post] - </strong>XAML Binding Debugging, Parser Performance Improvements and Multi-core JIT for improved start-up time.</p> <p>9) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-9-of-10.aspx">Controls - Double and Triple click support, PivotViewer and ComboBox Type-Ahead.</a></strong></p> <p>10) <strong></strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-10-of-10.aspx" target="_self"><strong>Other items</strong> - In-Browser HTML, PostScript and Tasks for TPL.</a></p> <h3></h3> <h3>XAML Binding Debugging</h3> <p>XAML Binding Debugging, is one of the most important features in the Silverlight 5. We have all been stuck with Binding expressions at one point or another and wanted an easier way to debug them. Now anywhere that you see a {<strong>Binding</strong>} expression you can put a break point on it just like your typical C# code. Let’s take a look at a sample:</p> <p>Fire up a new Silverlight 5 project and give it any name that you want. </p> <p>Go ahead and add a new class to the project named <strong>Podcast.cs</strong> and add the following code.</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;">public</span> <span style="color: #0000ff;">class</span> Podcast</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> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> Description { get; set; }</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> <span style="color: #0000ff;">public</span> DateTime ReleaseDate { get; set; }</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> <span style="color: #0000ff;">public</span> Uri Link { get; set; }</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="lnum6" style="color: #606060;"> 6:</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="lnum7" style="color: #606060;"> 7:</span> <span style="color: #0000ff;">public</span> Podcast(<span style="color: #0000ff;">string</span> description, DateTime releasedate, Uri link)</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="lnum8" style="color: #606060;"> 8:</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="lnum9" style="color: #606060;"> 9:</span> Description = description;</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="lnum10" style="color: #606060;"> 10:</span> ReleaseDate = releasedate;</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="lnum11" style="color: #606060;"> 11:</span> Link = link;</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="lnum12" style="color: #606060;"> 12:</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="lnum13" style="color: #606060;"> 13:</span> }</pre> <!--CRLF--></div> </div> <p>Let’s switch back over to the MainPage.xaml.cs and add the following code:</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;">public</span> MainPage()</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> InitializeComponent();</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> Loaded += <span style="color: #0000ff;">new</span> RoutedEventHandler(MainPage_Loaded);</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> }</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="lnum6" style="color: #606060;"> 6:</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="lnum7" style="color: #606060;"> 7:</span> <span style="color: #0000ff;">void</span> MainPage_Loaded(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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="lnum8" style="color: #606060;"> 8:</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="lnum9" style="color: #606060;"> 9:</span> <span style="color: #0000ff;">this</span>.DataContext =</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="lnum10" style="color: #606060;"> 10:</span> <span style="color: #0000ff;">new</span> Podcast(<span style="color: #006080;">"This Developer's Life - Criticism"</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="lnum11" style="color: #606060;"> 11:</span> <span style="color: #0000ff;">new</span> DateTime(2011, 4, 21),</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="lnum12" style="color: #606060;"> 12:</span> <span style="color: #0000ff;">new</span> Uri(<span style="color: #006080;">"http://thisdeveloperslife.com/post/2-0-1-criticism"</span>, UriKind.Absolute)</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="lnum13" style="color: #606060;"> 13:</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="lnum14" style="color: #606060;"> 14:</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="lnum15" style="color: #606060;"> 15:</span> }</pre> <!--CRLF--></div> </div> <p>Switch back over to the MainPage.xaml and add in the following code replacing the current Grid:</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;">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 id="lnum2" style="color: #606060;"> 2:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">StackPanel</span> <span style="color: #ff0000;">Orientation</span><span style="color: #0000ff;">="Vertical"</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;">TextBlock</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">="{Binding Description}"</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="lnum4" style="color: #606060;"> 4:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">TextBlock</span> <span style="color: #ff0000;">Name</span><span style="color: #0000ff;">="txtReleaseDate"</span> <span style="color: #ff0000;">Text</span><span style="color: #0000ff;">="{Binding ReleaseDate}"</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="lnum5" style="color: #606060;"> 5:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">HyperlinkButton</span> <span style="color: #ff0000;">Content</span><span style="color: #0000ff;">="Listen to this Episode"</span> <span style="color: #ff0000;">NavigateUri</span><span style="color: #0000ff;">="{Binding Lik}"</span> <span style="color: #ff0000;">TargetName</span><span style="color: #0000ff;">="_blank"</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="lnum6" style="color: #606060;"> 6:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">StackPanel</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="lnum7" style="color: #606060;"> 7:</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">Grid</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>While here, go ahead and put a break point on the “Hyperlink" button line, which you can do by clicking outside its margin as shown below:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/_______1_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="1" alt="1" src="http://www.silverlightshow.net/Storage/Users/mbcrump/_______1_thumb.png" width="596" height="199" /></a></p> <p>Notice the Red Circle and the highlighted “<strong>Binding</strong>” word? The Visual Studio 2010 debugger will stop once the XAML parser hits that line. </p> <p><em>Please note that if you try to put a breakpoint on any line outside of the “Binding” keyword, then you will get a message saying, “This is not a valid location for a breakpoint” at the bottom of your screen:</em></p> <p>We are now ready to begin debugging, so, press “F5” on your keyboard to begin. You will notice that the Binding breakpoint was hit. If you examine your <strong>Locals window</strong> then you will see the following: </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/_________2_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="2" alt="2" src="http://www.silverlightshow.net/Storage/Users/mbcrump/_________2_thumb.png" width="655" height="167" /></a></p> <p>It looks like we have an error in our Binding statement that is telling us the property <strong>‘Lik’</strong> does not exist on the class called Podcast. If you continue running the application then you will quickly notice that the webpage launches but the “Listen to this Episode” hyperlink does not work. </p> <p>If we take a quick look at our <strong>Podcast</strong> class then we will notice that the property is actually called <strong>Link</strong>. If we go back to our MainPage.xaml and change </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;">HyperlinkButton</span> <span style="color: #ff0000;">Content</span><span style="color: #0000ff;">="Listen to this Episode"</span> <span style="color: #ff0000;">NavigateUri</span><span style="color: #0000ff;">="{Binding Lik}"</span> <span style="color: #ff0000;">TargetName</span><span style="color: #0000ff;">="_blank"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--></div> </div> <p>to</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;">HyperlinkButton</span> <span style="color: #ff0000;">Content</span><span style="color: #0000ff;">="Listen to this Episode"</span> <span style="color: #ff0000;">NavigateUri</span><span style="color: #0000ff;">="{Binding Link}"</span> <span style="color: #ff0000;">TargetName</span><span style="color: #0000ff;">="_blank"</span> <span style="color: #0000ff;">/></span></pre> <!--CRLF--></div> </div> and run our application again it will work properly. <p>It is very easy to debug Binding expressions now with that feature. Another undocumented feature is that if you have Silverlight 5 installed then you can also<span style="text-decoration: underline;"> debug your</span> <span style="text-decoration: underline;">Silverlight 4 binding statements</span>! Sweet!</p> <h3>Productivity and Performance Improvements</h3> <br /> Silverlight 5 contains many additional performance improvements that you may not be aware of. I have decided to create a short list here: <br /> <br /> <ul> <li>Reduced network latency by using a background thread for networking. </li> <li>Hardware acceleration is enabled in windowless mode with Internet Explorer 9. </li> <li>XAML parser improvements that speed up startup and runtime performance. </li> <li>Support for 64-bit operating systems as discussed in part 7 of this series. </li> <li>Multi-core JIT for improved startup time. </li> <li>Increased performance of hardware decoding and presentation of H.264 media for lower-power devices. </li> <li>Text layout performance improvements </li> </ul> <p>As you can see the Silverlight Team has been hard at work not only adding additional features to Silverlight 5 but improving performance all around.</p> <h3>Conclusion</h3> <p>At this point, we have seen how you would debug binding statements using Silverlight 5’s built-in XAML debugger. We also looked at several productivity and performance improvements in Silverlight 5. In the next part of the series, I am going to take a look at several new controls/features shipping with Silverlight 5 including : Double and Triple click support, PivotViewer and ComboBox Type-Ahead.  Again, thanks for reading and please come back for the next part.</p> <p>To contact me directly please visit my blog at <a href="http://michaelcrump.net/">http://michaelcrump.net/</a> or through twitter at <a href="http://twitter.com/mbcrump">http://twitter.com/mbcrump</a>.</p> http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-8-of-10.aspx editorial@silverlightshow.net (Michael Crump ) http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-8-of-10.aspx#comments http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-8-of-10.aspx Tue, 29 Nov 2011 12:18:00 GMT Silverlight and Sharepoint working together: a Silverlight menu for Sharepoint - Part 2 <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-a-Silverlight-menu-for-Sharepoint-Part-2.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/Silverlight-and-Sharepoint-working-together-a-Silverlight-menu-for-Sharepoint-Part-2.aspx" data-count="horizontal" data-text="Reading article: Silverlight & Sharepoint working together: Silverlight menu for Sharepoint Part 2" data-url="http://slshow.net/sgzpki">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-a-Silverlight-menu-for-Sharepoint-Part-2.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <p style="text-align: justify;">In the first part of the article I introduced the matter, i.e. adding a Silverlight menu in Sharepoint. The first solution presented, defined as “the client approach”, has a major defect: it cannot be used for anonymous-enabled sites. In this second part we will see another way (that I called the “server approach”) in order to build a Silverlight menu for Sharepoint that can be used also by anonymous users. To make this new approach clearer I will introduce another few general concepts regarding the Sharepoint platform. As previously, they will be marked with a specific icon and Sharepoint developers can skip these parts.</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/Discover-Sharepoint-with-Silverlight.aspx">The article series: Discover Sharepoint with Silverlight</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-the-Silverlight-SharePoint-Web-Parts-part-1.aspx">The article series: Silverlight and Sharepoint working together</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/ebooks/sharepoint.aspx">Ebook: Discover Sharepoint with Silverlight (also in MOBI and EPUB):</a> </li> </ul> <p style="padding-bottom: 5px; text-align: center;"><a href="http://www.silverlightshow.net/ebooks/sharepoint.aspx"><img style="border:0px solid;" alt="Discover Sharepoint with Silverlight Ebook" src="http://www.silverlightshow.net/Storage/sharepoint_sml.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> <h3>The server approach</h3> <p>An alternative solution for the anonymous – enabled menu is illustrated in the picture below:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/ServerApproach_2.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; width: 369px; height: 300px; border-width: 0px;border-style: solid;" title="ServerApproach" alt="ServerApproach" src="http://www.silverlightshow.net/Storage/Users/walterf/ServerApproach_thumb.png" /></a></p> <p> </p> <p style="text-align: justify;">Why calling it “server approach”? Because the phase of retrieving the hierarchy of our Sharepoint site is made by code which is running on the server. And who is the owner of this code portion? The answer is: the web part hosting the Silverlight application. Let me take a while to recap some basic concepts I explained in my first article on this series <a href="http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-the-Silverlight-SharePoint-Web-Parts-part-2.aspx"><em>Sharepoint and Silverlight working together</em></a>. In that article we sectioned the structure of the Silverlight custom web part we are using here to inject the Silverlight application into a Sharepoint page. We have seen that it is a specialized Visual Studio template which helps us create a web part capable of hosting a Silverlight application. The Silverlight application itself is embedded in a <div> tag inside the custom control which represents the web part. This web part is defined as “sandboxed visual web part” i.e. a “Sharepoint 2010 Visual Web Part” with limited power.</p> <p style="text-align: justify;"> </p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/_sharepoint_2010_icon_2.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;border-style: solid;" title="sharepoint_2010_icon" alt="sharepoint_2010_icon" src="http://www.silverlightshow.net/Storage/Users/walterf/_sharepoint_2010_icon_thumb.jpg" width="64" height="63" /></a></p> <p style="text-align: justify;"><em>A Silverlight developer could feel a bit bewildered when hearing about visual, sandboxed web parts. In the Sharepoint context, a Web Part is conceptually nothing other than an ASP.NET Web Part. It is an ASP.NET user control which acts as a black box that you can place in one of the zones allowed in the UI layout of a page. Although there is a specific namespace (Microsoft.WebPartPages.WebPart) for the web parts, it is used in rare cases. As usual you can build your own Web Part deriving from System.Web.Ui.WebControls.WebPart. Sharepoint 2010 introduced a few new project templates for Visual Studio 2010, one of these is called “Visual Web Part”. This template creates a ready-to-deploy Web Part with a built-in user control. Editing the user control in design mode or via code behind you can enrich your pages with new features. </em></p> <p style="text-align: justify;"><em>The term “sandboxed” is used in Sharepoint 2010 to describe a restricted environment. A “sandboxed solution” is something that can have access only to a subset of the Sharepoint server object model and of the .NET 3.5 assemblies (btw Sharepoint 2010 does not use .NET 4.0) and that runs in a restricted code access security policy. Furthermore, server farm admins can regulate resource usage limits for these solutions. A Visual Web Part is <span style="text-decoration: underline;">not</span> a sandboxed solution. That’s probably why in the Visual Studio Sharepoint Power Tools add-on a new project template called “Sandboxed Visual Web Part” has been added. A “Silverlight Custom Web Part” is a “Sandboxed Visual Web Part” hosting a Silverlight application, nothing more than that.</em></p> <p style="text-align: justify;">Coming back to the picture above, I put the retrieval of the hierarchy under the Sharepoint side because we will do it by invoking the Server Object Model in a code running on server side. After the hierarchy has been provided it is then put into a custom List (the basic data container of Sharepoint) using a nice technique called “Modified Preorder Tree Traversal” that we will see later. Finally, the custom List containing the menu hierarchy can be read by the Silverlight application using the Client Object model every time the cache expires. Why using a custom list? Because we can set anonymous access to this list. This allows a Silverlight application to read the List also in the case in which we are not logged in. Don’t forget that the Silverlight app uses the default credentials when it queries the server.</p> <p style="text-align: justify;"> </p> <h3>Retrieving the hierarchy of the site</h3> <p style="text-align: justify;">There is more than one way to get the hierarchy of a Sharepoint site collection. You can use an existing Site Map provider or create your own or, as in this case, use a built-in Sharepoint control, i.e. the <em>SPHierarchyDataSourceControl</em> which provides hierarchical views of Sharepoint sites, lists, and folders. It is the same control used for the “tree view” navigation system mentioned in the first part of this article. Extracting the hierarchy from this control is a simple undertaking.</p> <p style="text-align: justify;">As shown in the code snippet below it is a matter of instantiating a new <em>SPHierarchyDataSourceControl</em>, setting some properties in order to define which categories of nodes to retrieve, obtaining a <em>HierarchicalDataSourceView</em> and performing a Select() over the view to finally have a <em>IHierarchicalEnumerable </em>collection of menu nodes.</p> <p style="text-align: justify;"> </p> <div 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;" id="codeSnippetWrapper"> <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;" id="codeSnippet"><span style="color: #0000ff;">private</span> IHierarchicalEnumerable sitemapNodes;<br />…<br />SPHierarchyDataSourceControl HierarchyDataSC = <span style="color: #0000ff;">new</span> SPHierarchyDataSourceControl();<br /><br />HierarchyDataSC.IncludeDiscussionFolders = <span style="color: #0000ff;">true</span>;<br />HierarchyDataSC.ShowDocLibChildren = <span style="color: #0000ff;">true</span>;<br />HierarchyDataSC.ShowFolderChildren = <span style="color: #0000ff;">true</span>;<br />HierarchyDataSC.ShowListChildren = <span style="color: #0000ff;">true</span>;<br />HierarchyDataSC.ShowWebChildren = <span style="color: #0000ff;">true</span>;<br /><br />HierarchyDataSC.RootContextObject = <span style="color: #006080;">"Web"</span>;<br />HierarchicalDataSourceView view = HierarchyDataSC.GetHierarchicalViewPublic(<span style="color: #006080;">""</span>);<br /><br />sitemapNodes = view.Select();</pre> <br /> </div> <p> </p> <p style="text-align: justify;">If you try to include the code above in your Silverlight Custom Web Part unfortunately it won’t compile. Why? Because as clarified in the previous paragraph the Web Part is a sandboxed We Part and this prevents you from using some assemblies, amongst them the one needed for the code above. You have two options to get out from the mud: one is to abandon the Silverlight Custom Web Part and use a normal Visual Web Part in the way I described in one of my previous articles entitled “<a href="http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-2010-a-step-forward-how-to-build-a-small-Silverlight-4-utility-to-upload-files-in-a-List-or-Library-of-Sharepoint.aspx">Silverlight and Sharepoint 2010 a step forward: how to build a small Silverlight 4 utility to upload files in a List or Library of Sharepoint</a>”, precisely in paragraph “Deploy the Silverlight application using a Visual WebPart”. The other is to modify the settings of the Silverlight Custom Web Part in an “unconventional” way, i.e. by making it become a not-sandboxed solution.</p> <p style="text-align: justify;"> </p> <h3 style="text-align: justify;">Deploy a Silverlight Custom Web Part as a not-sandboxed solution: a dirty trick</h3> <p>By default when using a Silverlight Custom Web Part, the property “Sandboxed Solution” of the project is set to true as in the picture below:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/SandboxedSolution_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="SandboxedSolution" alt="SandboxedSolution" src="http://www.silverlightshow.net/Storage/Users/walterf/SandboxedSolution_thumb.png" width="279" height="536" /></a></p> <p> </p> <p>If you try to set this property to false and then to include the code above to retrieve the hierarchy, you will be able to build the solution but not to deploy it. The error message that will appear is the following:</p> <p> </p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/SandboxedSolution2_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="SandboxedSolution2" alt="SandboxedSolution2" src="http://www.silverlightshow.net/Storage/Users/walterf/SandboxedSolution2_thumb.png" width="947" height="117" /></a></p> <p> </p> <p style="text-align: justify;">where “MenuSCWP” is the name I used to replace the default name “SilverlightcustomWebPart1”. As you can see in the second-last picture this project item is in charge of transporting a “MasterpageGallery” module in Sharepoint. This module contains the xap file of our Silverlight application. If you open the file “Elements.xml” nested in the module you can confirm this statement:</p> <div 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;" id="codeSnippetWrapper"> <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;" id="codeSnippet"><?xml version=<span style="color: #006080;">"1.0"</span> encoding=<span style="color: #006080;">"utf-8"</span>?><br /><Elements xmlns=<span style="color: #006080;">"http://schemas.microsoft.com/sharepoint/"</span>><br /> <Module Name=<span style="color: #006080;">"Menu4U"</span> Url=<span style="color: #006080;">"_catalogs/masterpage/ClientBin/$SharePoint.Package.Name$"</span>><br /> <File Path=<span style="color: #006080;">"Menu4U\Menu4UForSP.xap"</span> Url=<span style="color: #006080;">"Menu4UForSP.xap"</span> /><br /> </Module><br /></Elements></pre> <br /> </div> <p style="text-align: justify;"> </p> <p style="text-align: justify;">And now comes the trick to remove this obstacle, and I would like to warn you: it is a very dirty trick.</p> <p style="text-align: justify;">In Visual Studio right-click on the Silverlight custom Web Part item (I renamed it “MenuSCWP) as in the picture below:</p> <p style="text-align: justify;"> </p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/Trick1_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="Trick1" alt="Trick1" src="http://www.silverlightshow.net/Storage/Users/walterf/Trick1_thumb_1.png" width="529" height="485" /></a></p> <p style="text-align: justify;"> </p> <p>Click on “Open Folder in windows Explorer” to open the folder. You should see a couple of subdirectories and a file named “SharePointProjectItem.spdata” as in the picture below:</p> <p> </p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/Trick2_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="Trick2" alt="Trick2" src="http://www.silverlightshow.net/Storage/Users/walterf/Trick2_thumb_1.png" width="371" height="104" /></a></p> <p> </p> <p>Open the file. It should have a content similar to this one:</p> <p> </p> <div 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;" id="codeSnippetWrapper"> <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;" id="codeSnippet"><?xml version=<span style="color: #006080;">"1.0"</span> encoding=<span style="color: #006080;">"utf-8"</span>?><br /><ProjectItem Type=<span style="color: #006080;">"MicrosoftSilverlightCustomWebPart"</span> SupportedTrustLevels=<span style="color: #006080;">"Sandboxed"</span> SupportedDeploymentScopes=<span style="color: #006080;">"Site"</span> xmlns=<span style="color: #006080;">"http://schemas.microsoft.com/VisualStudio/2010/SharePointTools/SharePointProjectItemModel"</span>><br /> <Files /><br /></ProjectItem></pre> <br /> </div> <p> </p> <p style="text-align: justify;">Take a look at the “SupportedTrustLevels” attribute of the projectitem node: actually it is set as “Sandboxed”. Now write “FullTrust” instead, and save the file. Come back to Visual Studio and try to deploy the solution. If all the steps have been followed correctly, the solution will be deployed. Pay attention to the fact that when you close the solution and open it again in Visual Studio, the file is overwritten and you have to set the attribute again. It is not so annoying if you make a batch file or a vbscript that performs the replacement for you. You can also launch the execution of the script from the pre-build event.</p> <p> </p> <h3>Saving the hierarchy in a Sharepoint custom list: the modified preorder traversal tree</h3> <p style="text-align: justify;">In the previous paragraph I explained the reason why I want to put the hierarchy into a Custom Sharepoint List: it can be read also by anonymous users. The problem is that a List in Sharepoint is basically a table with rows and columns, while the <em>IHierarchicalEnumerable </em>object that we have obtained represents a tree hierarchy. How to save a tree-hierarchy in a table then? After a moment of despair I recalled an old article entitled <a href="http://www.sitepoint.com/article/hierarchical-data-database">Storing Hierarchical Data in a Database</a> that illustrated an algorithm called <strong>Modified Preorder Tree Traversal</strong>. The principal assumption of the algorithm is that each node in the hierarchy tree must have a left value and a right value. Then the tree is traversed assigning opportune values for left and right according to the rules shown in the flowchart below:</p> <p style="text-align: justify;"> </p> <p style="text-align: justify;"><a href="http://www.silverlightshow.net/Storage/Users/walterf/FlowChart_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="FlowChart" alt="FlowChart" src="http://www.silverlightshow.net/Storage/Users/walterf/FlowChart_thumb.png" width="644" height="397" /></a></p> <p style="text-align: justify;"> </p> <p style="text-align: justify;">At a first glance it may look a bit complicated but if you try to put on paper a simple tree and assign the left and right values following the flowchart above, it will be a fun exercise. The following picture shows a hierarchy tree, a tree already numbered with the indication of the direction of traversing:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/walterf/TreeNumbered_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="TreeNumbered" alt="TreeNumbered" src="http://www.silverlightshow.net/Storage/Users/walterf/TreeNumbered_thumb.png" width="606" height="484" /></a></p> <p> </p> <p style="text-align: justify;">The nice thing of this approach is that after the hierarchy is put into a table you can retrieve nodes with simple queries. With reference to the picture above, if you want to retrieve the subtree starting from the node title “SITE AA” you can launch this query:</p> <p style="text-align: justify;"><em>“SELECT * FROM tree_table WHERE left BETWEEN 3 AND 8 ORDER BY left ASC;</em></p> <p style="text-align: justify;">If you want all the tree simply write:</p> <p style="text-align: justify;"><em>“SELECT * FROM tree_table WHERE left BETWEEN 1 AND 22 ORDER BY left ASC;</em></p> <p style="text-align: justify;">As for the code implementation, I created a class “MpttItem” representing a single node as below:</p> <p style="text-align: justify;"> </p> <div 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;" id="codeSnippetWrapper"> <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;" id="codeSnippet"><span style="color: #0000ff;">class</span> MpttItem<br />{<br /> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">string</span> title;<br /> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> Title<br /> {<br /> get { <span style="color: #0000ff;">return</span> title; }<br /> set { title = <span style="color: #0000ff;">value</span>; }<br /> }<br /><br /> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">string</span> type;<br /> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> Type<br /> {<br /> get { <span style="color: #0000ff;">return</span> type; }<br /> set { type = <span style="color: #0000ff;">value</span>; }<br /> }<br /><br /> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">string</span> imageUrl;<br /> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> ImageUrl<br /> {<br /> get { <span style="color: #0000ff;">return</span> imageUrl; }<br /> set { imageUrl = <span style="color: #0000ff;">value</span>; }<br /> }<br /><br /><br /> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">string</span> serverRelativeUrl;<br /> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> ServerRelativeUrl<br /> {<br /> get { <span style="color: #0000ff;">return</span> serverRelativeUrl; }<br /> set { serverRelativeUrl = <span style="color: #0000ff;">value</span>; }<br /> }<br /><br /> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">string</span> navigateUrl;<br /> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">string</span> NavigateUrl<br /> {<br /> get { <span style="color: #0000ff;">return</span> navigateUrl; }<br /> set { navigateUrl = <span style="color: #0000ff;">value</span>; }<br /> }<br /><br /><br /><br /> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> left = 0;<br /> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> Left<br /> {<br /> get { <span style="color: #0000ff;">return</span> left; }<br /> set { left = <span style="color: #0000ff;">value</span>; }<br /> }<br /><br /> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> right = 0;<br /> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> Right<br /> {<br /> get { <span style="color: #0000ff;">return</span> right; }<br /> set { right = <span style="color: #0000ff;">value</span>; }<br /> }<br /><br /> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> id;<br /> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> ID<br /> {<br /> get { <span style="color: #0000ff;">return</span> id; }<br /> set { id = <span style="color: #0000ff;">value</span>; }<br /> }<br /><br /> <span style="color: #0000ff;">protected</span> MpttItem parent;<br /> <span style="color: #0000ff;">public</span> MpttItem Parent<br /> {<br /> get { <span style="color: #0000ff;">return</span> parent; }<br /> set { parent = <span style="color: #0000ff;">value</span>; }<br /> }<br /><br /> <span style="color: #0000ff;">protected</span> IHierarchyData iHierarchyItem;<br /> <span style="color: #0000ff;">public</span> IHierarchyData IHierarchyItem<br /> {<br /> get { <span style="color: #0000ff;">return</span> iHierarchyItem; }<br /> set { iHierarchyItem = <span style="color: #0000ff;">value</span>; }<br /> }<br /><br /> <br />}</pre> <br /> </div> <p> </p> <p>And then in the code behind the sandboxed (not-sandboxed) Web Part I stored each node in a List of MpttItem using a recursive function as below:</p> <div 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;" id="codeSnippetWrapper"> <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;" id="codeSnippet">List<MpttItem> menuRows;<br /><br />[…]<br /><br />menuRows = <span style="color: #0000ff;">new</span> List<MpttItem>();<br /> <br />MpttItem mpttRootItem = <span style="color: #0000ff;">new</span> MpttItem()<br />{<br /> Parent = <span style="color: #0000ff;">null</span>,<br /> IHierarchyItem = <span style="color: #0000ff;">null</span>,<br /> Title = <span style="color: #006080;">"root"</span>,<br /> Left = 1,<br /> Right = 0,<br /><br />};<br />menuRows.Add(mpttRootItem);<br /><br /><br /><span style="color: #0000ff;">foreach</span> (<span style="color: #0000ff;">object</span> item <span style="color: #0000ff;">in</span> sitemapNodes)<br />{<br /> IHierarchyData menuNode = (IHierarchyData)sitemapNodes.GetHierarchyData(item);<br /> <span style="color: #0000ff;">if</span> (menuRows.Count == 1)<br /> {<br /> AddMenuRowsRecursive(<span style="color: #0000ff;">null</span>, menuNode, 2, 2);<br /> }<br /> <span style="color: #0000ff;">else</span><br /> {<br /> <span style="color: #0000ff;">int</span> startIndex = menuRows[menuRows.Count - 1].Right + 1;<br /> AddMenuRowsRecursive(<span style="color: #0000ff;">null</span>, menuNode, startIndex, startIndex);<br /> }<br />}<br /><br />menuRows.Sort(<br /> <span style="color: #0000ff;">delegate</span>(MpttItem p1, MpttItem p2)<br /> {<br /> <span style="color: #0000ff;">return</span> p1.Right.CompareTo(p2.Right);<br /> }<br />);<br />menuRows[0].Right = menuRows[menuRows.Count - 1].Right + 1;<br />menuRows.Sort(<br /> <span style="color: #0000ff;">delegate</span>(MpttItem p1, MpttItem p2)<br /> {<br /> <span style="color: #0000ff;">return</span> p1.Left.CompareTo(p2.Left);<br /> }<br />);<br /><br /><br />AddToSPList();</pre> <br /> </div> <p> </p> <p>The recursive function is the following:</p> <div 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;" id="codeSnippetWrapper"> <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;" id="codeSnippet"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> AddMenuRowsRecursive(MpttItem mpttParent, IHierarchyData currHIData, <span style="color: #0000ff;">int</span> leftIndex, <span style="color: #0000ff;">int</span> rootIndex)<br />{<br /> <span style="color: #0000ff;">if</span> (mpttParent == <span style="color: #0000ff;">null</span> && leftIndex > rootIndex)<br /> <span style="color: #0000ff;">return</span> 0; <span style="color: #008000;">// elaboration completed</span><br /><br /> <span style="color: #0000ff;">string</span> title = GetPropertyDescriptorValue(currHIData, <span style="color: #006080;">"Name"</span>);<br /><br /> Microsoft.SharePoint.Navigation.ISPHierarchyData currHIOtherData = (Microsoft.SharePoint.Navigation.ISPHierarchyData)currHIData.Item;<br /> <br /> <span style="color: #008000;">// look if the current mpttItem was already elaborated</span><br /> MpttItem elaboratedItem = menuRows.Find(i => ( (i.IHierarchyItem == <span style="color: #0000ff;">null</span> || currHIData == <span style="color: #0000ff;">null</span>) ? <span style="color: #0000ff;">false</span> : i.IHierarchyItem.GetHashCode() == currHIData.GetHashCode()));<br /><br /> IHierarchyData childHiData = GetFirstAvailableChild(currHIData);<br /> <span style="color: #0000ff;">if</span> (childHiData == <span style="color: #0000ff;">null</span>)<br /> {<br /> <span style="color: #0000ff;">if</span> (leftIndex > rootIndex && elaboratedItem == <span style="color: #0000ff;">null</span> <span style="color: #008000;">/* && leftIndex < mpttParent.Left + 2*/</span>)<br /> {<br /> <span style="color: #008000;">// then it is a leaf</span><br /> MpttItem mpttItem = <span style="color: #0000ff;">new</span> MpttItem()<br /> {<br /> Parent = mpttParent,<br /> IHierarchyItem = currHIData,<br /> Title = title,<br /> Type = currHIData.Type,<br /> ServerRelativeUrl = currHIOtherData.ServerRelativeUrl,<br /> NavigateUrl = SPContext.Current.Web.Site.Url + currHIOtherData.ServerRelativeUrl,<span style="color: #008000;">//currHIOtherData.NavigateUrl,</span><br /> ImageUrl = currHIOtherData.ImageUrl,<br /> Left = leftIndex,<br /> Right = leftIndex + 1<br /> };<br /> menuRows.Add(mpttItem);<br /><br /> AddMenuRowsRecursive(mpttItem.Parent, mpttItem.Parent.IHierarchyItem, mpttItem.Right + 1, rootIndex);<br /> <span style="color: #0000ff;">return</span> 0;<br /> }<br /> <span style="color: #0000ff;">else</span><br /> {<br /> <span style="color: #0000ff;">if</span> (mpttParent == <span style="color: #0000ff;">null</span>) <br /> <span style="color: #0000ff;">return</span> 0;<br /><br /> mpttParent.Right = leftIndex;<br /><br /> <span style="color: #0000ff;">if</span> (mpttParent.Parent == <span style="color: #0000ff;">null</span>)<br /> <span style="color: #0000ff;">return</span> 0;<br /> AddMenuRowsRecursive(mpttParent.Parent, mpttParent.Parent.IHierarchyItem, mpttParent.Right + 1, rootIndex);<br /> <span style="color: #0000ff;">return</span> 0;<br /> }<br /><br /> }<br /> <span style="color: #0000ff;">else</span><br /> {<br /> <span style="color: #008000;">// it is a branch</span><br /><br /> <span style="color: #0000ff;">if</span> (elaboratedItem == <span style="color: #0000ff;">null</span>)<br /> {<br /> MpttItem mpttItem = <span style="color: #0000ff;">new</span> MpttItem()<br /> {<br /> Parent = mpttParent,<br /> IHierarchyItem = currHIData,<br /> Title = title,<br /> Left = leftIndex,<br /> Type = currHIData.Type,<br /> ServerRelativeUrl = currHIOtherData.ServerRelativeUrl,<br /> NavigateUrl = SPContext.Current.Web.Site.Url + currHIOtherData.ServerRelativeUrl,<span style="color: #008000;">//currHIOtherData.NavigateUrl,</span><br /> ImageUrl = currHIOtherData.ImageUrl,<br /> };<br /> menuRows.Add(mpttItem);<br /> AddMenuRowsRecursive(mpttItem, childHiData, mpttItem.Left + 1, rootIndex);<br /> <span style="color: #0000ff;">return</span> 0;<br /> }<br /> AddMenuRowsRecursive(elaboratedItem, childHiData, leftIndex, rootIndex);<br /> <span style="color: #0000ff;">return</span> 0;<br /> }<br /><br />}</pre> <br /> </div> <p> </p> <p>The AddToSPList() function performs the insertion of the nodes in a Sharepoint custom list which I called “MenuTable”:</p> <div 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;" id="codeSnippetWrapper"> <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;" id="codeSnippet"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> AddToSPList()<br />{<br /> SPWeb mySite = SPContext.Current.Web;<br /> SPListItemCollection listItems = mySite.Lists[<span style="color: #006080;">"MenuTable"</span>].Items;<br /> mySite.AllowUnsafeUpdates = <span style="color: #0000ff;">true</span>;<br /><br /> <span style="color: #008000;">// clean list</span><br /> PurgeList(listItems);<br /><br /> <span style="color: #0000ff;">foreach</span> (MpttItem mpttItem <span style="color: #0000ff;">in</span> menuRows)<br /> {<br /> SPListItem item = listItems.Add();<br /><br /> item[<span style="color: #006080;">"Left"</span>] = mpttItem.Left;<br /> item[<span style="color: #006080;">"Right"</span>] = mpttItem.Right;<br /> item[<span style="color: #006080;">"Title"</span>] = mpttItem.Title;<br /> item[<span style="color: #006080;">"ImageUrl"</span>] = mpttItem.ImageUrl;<br /> item[<span style="color: #006080;">"NavigateUrl"</span>] = mpttItem.NavigateUrl;<br /> item[<span style="color: #006080;">"ServerRelativeUrl"</span>] = mpttItem.ServerRelativeUrl;<br /><br /> <span style="color: #0000ff;">if</span> (mpttItem.Parent != <span style="color: #0000ff;">null</span>)<br /> {<br /> item[<span style="color: #006080;">"ParentLeft"</span>] = mpttItem.Parent.Left;<br /> item[<span style="color: #006080;">"ParentRight"</span>] = mpttItem.Parent.Right;<br /> }<br /> <span style="color: #0000ff;">else</span><br /> {<br /> item[<span style="color: #006080;">"ParentLeft"</span>] = menuRows[0].Left;<br /> item[<span style="color: #006080;">"ParentRight"</span>] =menuRows[0].Right;<br /> }<br /><br /> item.Update();<br /> }<br /><br />}</pre> <br /> </div> <p> </p> <h3>The source code</h3> <p style="text-align: justify;">At this <a href="http://www.snello.it/Samples/SLMenuForSP/SPNavigationSilverlight.zip" target="_blank">link</a> you find the complete solution discussed in this article. It is not an optimized project but a starting point ready to be improved if you want to create your own Silverlight menu for Sharepoint. It does not contain any cache management either from server side or client side. It is left as an exercise for you. In order to put the menu in practice it is recommended to put it in a master page using Sharepoint Designer.</p> <h3>Summary</h3> <p style="text-align: justify;">In this second part we have seen how to implement a Silverlight menu using a so called “server approach” where the retrieval of the hierarchy is made at the server side. We have learned a dirty trick to “un-sandbox” a Silverlight Custom Web Part and a way to retrieve the hierarchy. Then we have explored a fun method to save the hierarchy in a table so that it can be read by the Silverligt menu also in an anonymous context.</p> http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-a-Silverlight-menu-for-Sharepoint-Part-2.aspx editorial@silverlightshow.net (Walter Ferrari ) http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-a-Silverlight-menu-for-Sharepoint-Part-2.aspx#comments http://www.silverlightshow.net/items/Silverlight-and-Sharepoint-working-together-a-Silverlight-menu-for-Sharepoint-Part-2.aspx Mon, 28 Nov 2011 13:56:00 GMT 10 Laps around Silverlight 5 (Part 7 of 10) <table width="20"> <tbody> <tr> <td> <div class="fb-like" data-show-faces="true" data-send="false" data-href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-7-of-10.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/10-Laps-around-Silverlight-5-Part-7-of-10.aspx" data-count="horizontal" data-text="Reading SilverlightShow article '10 Laps around Silverlight 5 (Part 7 of 10)' by @mbcrump #sl5" data-url="http://slshow.net/vuTRyo">Tweet</a></td> <td><g:plusone size="medium" href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-7-of-10.aspx"></g:plusone> </td> <td> </td> </tr> </tbody> </table> <div style="border:1px solid #dddddd;border-image: initial; padding-bottom: 5px; background-color: #f3f3f3; margin-top: 5px; padding-left: 10px; padding-top: 5px; text-align: center;"><em><strong>This article is sponsored by <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=81&Task=Click&Mode=HTML&SiteID=1&PageID=41808" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=81&Task=Get&Mode=HTML&SiteID=1&PageID=41808" width="0" height="0" style="border-width: 0px;border-style: solid;" />Telerik RadControls for Silverlight</a>. For similarly awesome content check out <a href="http://ads.silverlightshow.net/a.aspx?ZoneID=82&Task=Click&Mode=HTML&SiteID=1&PageID=3019" target="_blank"> <img alt="" src="http://ads.silverlightshow.net/a.aspx?ZoneID=82&Task=Get&Mode=HTML&SiteID=1&PageID=3019" width="0" height="0" style="border-width: 0px;border-style: solid;" />Telerik XAMLflix</a>, your step-by-step guide to Telerik Silverlight and WPF controls. Get access to video tutorials, written tutorials, and tons of code! </strong></em></div> <p>To contact me directly please visit my blog at <a href="http://michaelcrump.net/">http://michaelcrump.net/</a> or through twitter at <a href="http://twitter.com/mbcrump">http://twitter.com/mbcrump</a>.</p> <p>This article is Part 7 of the series “10 Laps around Silverlight 5.” If you have missed any other section then please see the Roadmap below. <br /> <br /> </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/news/Free-Silverlight-Show-Webinar-Introduction-to-XAML-Development-on-Windows-8.aspx">Upcoming Webinar on Nov 29th: XAML Development on Windows 8</a> </li> <li style="padding-bottom: 5px;"><a href="http://www.silverlightshow.net/GetStarted.aspx">Get Started with Silverlight 4</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; border-image: initial;" 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></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> To refresh your memory on what Silverlight is: <p>Microsoft Silverlight is an application framework for writing Rich Internet Applications. </p> The run-time environment is available as a plug-in for most web browsers and works on a variety of operating systems including Windows, Mac and Linux. <p>To recap what we learned in the <a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-6-of-10.aspx">previous section</a>:</p> <ul> <li>We spent some time building an application that uses P/Invoke or Platform Invocation to get familiar with Elevated Trust and Out of Browser applications.  We also reviewed that P/Invoke allows managed code to call native code. </li> <li>We then took a look at how to create a Silverlight 5 application that uses multiple windows that are separate from the main Silverlight window. We discussed how that if you close one of the newly spawned windows then it only closes that instance.  </li> <li>We wrapped up with creating an application that uses unrestricted file access to demonstrate creating a folder and placing a file inside of it with some content. </li> </ul> <p>In this article, I am going to discuss a few more operating system integration features in Silverlight 5 including: Default Filename for SaveFileDialog, 64-bit browser support and Power Awareness for Media Applications. Please review the Roadmap for the series before going any further.</p> <h3>The Roadmap for this Series</h3> <p>I’ve included the Roadmap for the series below as you may want to visit other sections as you learn Silverlight 5. I picked the following features as I thought that you may find them useful in your day-to-day work. If you want a specific topic covered then please leave it in the comments below.</p> <p>1) <strong><a href="http://www.silverlightshow.net/items/Silverlight-5-Part-1-of-10.aspx">Introduction to SL5 – This post which provides a brief history of Silverlight and relevant links.</a></strong> </p> <p>2) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-2-of-10.aspx">Binding- Ancestor Relative Source Binding and Implicit Data Templates.</a></strong></p> <p>3) <strong></strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-3.aspx" target="_self"><strong>Graphics</strong> <strong>–XNA 3D API and Improved Graphics Stack</strong>.</a></p> <p>4) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-4-of-10.aspx">Media - Low-Latency Sound using XNA and Remote Control and Media Command (Keys) Support.</a></strong></p> <p>5) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-5-of-10.aspx">Text - Text Tracking and Leading, Linked and Multi-column Text, OpenType Support, Pixel Snapped Text and TextOptions.</a></strong></p> <p>6) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-6-of-10.aspx">Operating System Integration - Part 1 - P/Invoke, Multiple Windows and Unrestricted File System Access in Full Trust.</a></strong></p> <p>7) <strong>Operating System</strong> <strong>Integration [This post]</strong> Part 2 - Default Filename for SaveFileDialog, 64-bit browser support and Power Awareness.</p> <p>8) <strong></strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-8-of-10.aspx"><strong>Productivity and Performance - XAML Binding Debugging, Parser Performance Improvements and Multi-core JIT for improved start-up time.</strong></a></p> <p>9) <strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-9-of-10.aspx">Controls - Double and Triple click support, PivotViewer and ComboBox Type-Ahead.</a></strong></p> <p>10) <strong></strong><a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-10-of-10.aspx" target="_self"><strong>Other items - In-Browser HTML, PostScript and Tasks for TPL.</strong></a></p> <h3></h3> <h3>Default Filename for SaveFileDialog</h3> <p>In previous version of Silverlight, you could not specify the default filename for the SaveFileDialog message. In Silverlight 5 you can very easily. </p> <p>Fire up a new Silverlight 5 project and give it any name that you want. We are going to create a simple application that contains one button and when the user clicks it the SaveFileDialog will appear with a default filename. </p> <p>Switch over to the MainPage.xaml and add in the following code:</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;">StackPanel</span> <span style="color: #ff0000;">HorizontalAlignment</span><span style="color: #0000ff;">="Center"</span> <span style="color: #ff0000;">VerticalAlignment</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 id="lnum2" style="color: #606060;"> 2:</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">Button</span> <span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="btnSaveFile"</span> <span style="color: #ff0000;">Content</span><span style="color: #0000ff;">="Save File Dialog"</span> <span style="color: #ff0000;">Click</span><span style="color: #0000ff;">="btnSaveFile_Click"</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;">StackPanel</span><span style="color: #0000ff;">></span></pre> <!--CRLF--></div> </div> <p>Let’s switch back over to the MainPage.xaml.cs and add the following code to our button event handler:</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> private void btnSaveFile_Click(<span style="color: #0000ff;">object</span> sender, RoutedEventArgs e)</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> <span style="color: #0000ff;">var</span> saveFileDialog1 = new SaveFileDialog</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> Filter = "JPeg Image|*<span style="color: #cc6633;">.jpg</span>|Bitmap Image|*<span style="color: #cc6633;">.bmp</span>|Gif Image|*<span style="color: #cc6633;">.gif</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="lnum6" style="color: #606060;"> 6:</span> DefaultFileName = "YouCanNowHaveADefaultFileName<span style="color: #cc6633;">.jpeg</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="lnum7" style="color: #606060;"> 7:</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="lnum8" style="color: #606060;"> 8:</span> saveFileDialog1<span style="color: #cc6633;">.ShowDialog</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="lnum9" style="color: #606060;"> 9:</span> }</pre> <!--CRLF--></div> </div> <p>If we run the application now, we will see the following prompt.  </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/______1_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="1" alt="1" src="http://www.silverlightshow.net/Storage/Users/mbcrump/______1_thumb.png" width="400" height="172" /></a></p> <p><em>(Note: You could run this application in elevated trust to remove the security warning, see this <a href="http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-6-of-10.aspx">post</a> for details)</em></p> <p>Go ahead and select OK and you will see the following screen:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/________2_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="2" alt="2" src="http://www.silverlightshow.net/Storage/Users/mbcrump/________2_thumb.png" width="494" height="355" /></a></p> <p>You should notice that the File name field is filled in for us with a default save as type as Jpeg. Of course, if you didn’t want the user to see the security warning then you could run this application in elevated trust as mentioned under the image. </p> <h3>64-bit browser support </h3> <p>64-bit browser support is also new to Silverlight 5. If you have installed Windows 7 x64 then you already have a 64-bit version of Internet Explorer. You can find it by going to the “<strong>search program and files</strong>” prompt and typing<strong> Internet Explorer</strong> as shown below. </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/_________3_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="3" alt="3" src="http://www.silverlightshow.net/Storage/Users/mbcrump/_________3_thumb.png" width="383" height="104" /></a></p> <p>If you launch Internet Explorer x64 and visit a site built with Silverlight 5 then you will see the following message:</p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/5_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="5" alt="5" src="http://www.silverlightshow.net/Storage/Users/mbcrump/5_thumb_1.png" width="397" height="343" /></a></p> <p>After you click on the hyperlink then it will take you to a page that says the following: </p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/6_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="6" alt="6" src="http://www.silverlightshow.net/Storage/Users/mbcrump/6_thumb_1.png" width="544" height="319" /></a></p> <p><em>(Please note this message will change after the final version of Silverlight 5 is released.)</em></p> <p>Don’t worry about this prompt, just go ahead and click “<strong>Install for Windows</strong>” and you will now be able to run Silverlight 5 applications inside of a browser running in 64-bit mode. Pretty sweet stuff!</p> <p><a href="http://www.silverlightshow.net/Storage/Users/mbcrump/___7_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="7" alt="7" src="http://www.silverlightshow.net/Storage/Users/mbcrump/___7_thumb.png" width="546" height="431" /></a></p> <h3> <br /> Power Awareness for Media Apps</h3> <p>Silverlight 5 comes with an improved power awareness feature. When you are watching a video in Silverlight 5, the screensaver will be disabled (for example, it will not kick in and distract you from your movie). It also allows the computer to sleep when the video is not playing. This is all accomplished with no additional code! You just have to be using Silverlight 5. </p> <h3>Conclusion</h3> <p>At this point, we have seen how you would use specify a default filename for SaveFileDialog, we looked at 64-bit browser support and power awareness for media applications. We have also discussed a few other features in Silverlight 5. In the next part of the series, I am going to take a look at a few productivity and performance features including : XAML Binding Debugging, Parser Performance Improvements and Multi-core JIT for improved start-up time.  Again, thanks for reading and please come back for the next part.</p> <p>To contact me directly please visit my blog at <a href="http://michaelcrump.net/">http://michaelcrump.net/</a> or through twitter at <a href="http://twitter.com/mbcrump">http://twitter.com/mbcrump</a>.</p> http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-7-of-10.aspx editorial@silverlightshow.net (Michael Crump ) http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-7-of-10.aspx#comments http://www.silverlightshow.net/items/10-Laps-around-Silverlight-5-Part-7-of-10.aspx Tue, 22 Nov 2011 10:53: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