<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Rob's Rhapsody</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/robch/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/robch/feed.xml</link>
    <description>Rob Chambers talks about Speech Recognition, Life at Microsoft inside OSD, and other random thoughts...</description>
    <lastBuildDate>Tue, 16 Apr 2019 05:27:45 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>WP8 Speech – Exploring the MVVM pattern</title>
      <link>https://docs.microsoft.com/archive/blogs/robch/wp8-speech-exploring-the-mvvm-pattern</link>
      <pubDate>Fri, 05 Jul 2013 14:32:36 GMT</pubDate>
      <dc:creator><![CDATA[Rob Chambers]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/robch/2013/07/05/wp8-speech-exploring-the-mvvm-pattern/</guid>
      <description><![CDATA[Today’s post will be the first in a series discussing how I’ve used the MVVM (Model, View, View...]]></description>
      <content:encoded><![CDATA[<p>Today’s post will be the first in a series discussing how I’ve used the MVVM (Model, View, View Model) pattern to build a full blown user experience for the “Search On” application I’ve previously blogged about.</p>  <p>If you haven’t read the earlier posts, you might want to take a few minutes and see where we left off. </p>  <ul>   <li><a href="http://blogs.msdn.com/b/robch/archive/2012/11/06/how-many-lines-of-code-does-it-take-to-build-a-complete-wp8-speech-app.aspx">How many lines of code does it take to build a complete WP8 speech app?</a></li>    <li><a href="http://blogs.msdn.com/b/robch/archive/2012/11/07/wp8-voice-commands-phrase-lists.aspx">WP8: Voice Command Phrase Lists</a></li>    <li><a href="http://blogs.msdn.com/b/robch/archive/2012/11/08/wp8-voice-commands-wildcards.aspx">WP8: Voice Command Wildcards</a></li>    <li><a href="http://blogs.msdn.com/b/robch/archive/2012/11/14/wp8-voice-commands-dynamic-phrase-lists-from-azure.aspx">WP8 Voice Commands: Dynamic Phrase Lists … From Azure!</a></li> </ul>  <p>Since those posts went live, I’ve completely re-written the application with a full blown UX. </p>  <p>And … It’s not just a sample application anymore, either. Its an actual, real, publically available application. </p>  <p><a href="http://www.windowsphone.com/s?appid=2ecf006a-2bc2-4fa5-b518-3bd92c40226f">Go Search On</a> is available in the Windows Phone Store as of today, and … It’s FREE!</p>  <p>Before we dive into the developer details, let’s take a look at the new features I’ve added:</p>  <ul>   <li>Designed to be used with or without speech recognition</li>    <ul>     <li>The main screen has a textbox for the site you’d like to search, and another for what you’d like to search for.</li>      <li>Either textbox can be filled with the soft keyboard or using speech via a buddy microphone icon. </li>      <li>The site to search textbox has autocomplete, based on the same site list that we use to populate the voice command’s phrase lists. </li>   </ul>    <li>Demonstrates the “dialog” and “implicit confirmation” speech UX metaphors</li>    <ul>     <li>After users issue a Go Search On voice command (e.g. “Go Search On Amazon.com”)</li>      <li>… the app prompts and collects the search terms,</li>      <li>… then, the app informs the user (both visually and verbally) what it’s about to do.</li>      <li>… e.g. “Searching on Amazon.com for Legos”</li>      <li>While the “confirmation” prompt is playing, the user can either…</li>      <li>… do nothing, and the search will take place once the prompt is complete, or</li>      <li>… cancel the task by clicking cancel, or by attempting to edit the site name or the search terms</li>   </ul>    <li>Search more “sites”</li>    <ul>     <li>I’ve updated the list of sites available to all users, and added the ability for users to add their own personalized list of sites to search.</li>      <li>I’ve also added the ability to search the Windows Phone App Store as well as Xbox Music Marketplace,</li>      <li>… using the phone’s built in UX.</li>   </ul>    <li>User authentication to allow CRUD (create, read, update, delete) type operations on what sites are available to search on:</li>    <ul>     <li>Authenticated users can add, edit, and delete their own personalized list of sites to search. </li>      <li>The authenticated “Admin” has the ability to update the list of sites that is common for all users.</li>      <li>Authentication is performed via the Windows Live SDK, allowing users to use their Microsoft Account credentials, where … </li>      <li>… the Live Authentication Client Session’s authentication token is used to authenticate with Azure’s Mobile Service.</li>   </ul> </ul>  <p>OK … Now, on the developer aspects of “Go Search On” …</p>  <p>&#160;</p>  <h2>Go Search On – Exploring the MVVM pattern with WP8 and Speech</h2>  <p>The original sample application in the first post was only 100 lines of code. By the time we got to latest post, the app had more than tripled in size, and now … it’s much, much larger. That’s expected, though. Right? I mean, come on! Did you see that list of enhancements above?! :-)</p>  <p>So … To make the act of describing what’s going on in the new app more understandable and manageable, I’ve broken it down into the following pieces:</p>  <ul>   <li>The basics – MVVM and Go Search On in it’s most simplistic high level form</li>    <ul>     <li>The Model, View, and the View Model</li>      <li>XAML binding, Property change notifications, and Commands</li>      <li>Three different app interactions, with the same end result</li>   </ul>    <li>And the rest …</li>    <ul>     <li>Dictation into a textbox using MVVM Commanding – I’ve created a handy helper class you should be able to re-use in your own apps.</li>      <li>XAML Value Converters – what are they, why use them, and a few helper classes I’ve created.</li>      <li>Implicit Confirmation UX – what is it, and how I’ve done it in an MVVM manner.</li>      <li> Authentication – Using Windows Live, integrated with the Azure Mobile Service, demonstrating connections into the MVVM world.</li>      <li>Autocomplete – Demonstrating how I’ve done it in an MVVM manner, sharing the underlying models.</li>      <li>Site Lists – Exposing the site lists for All Users and the Current User using MVVM.</li>      <li>CRUD in MVVM – Implications for a basic MVVM based UX managing data in the cloud.</li>   </ul> </ul>  <p>Today, we’ll tackle the basics, and I’ll try to tackle the rest of the topics in future posts.</p>  <h2>Go Search On and MVVM Basics</h2>  <p>If you’ve already built a few Windows Phone applications, you probably have seen or at least been exposed a bit to the MVVM concept. Many of the samples on MSDN, and the Visual Studio templates are built using XAML and MVVM. If you have absolutely zero MVVM exposure, I’d recommend watching a recent post/video on the Windows Phone Dev Blog, <a href="http://blogs.windows.com/windows_phone/b/wpdev/archive/2013/05/23/inside-windows-phone-practical-mvvm-for-windows-phone.aspx">here</a>. </p>  <p>Here’s my take on MVVM … </p>  <h4>The View</h4>  <p>In a Windows Phone MVVM application, the View is the collection of all XAML UIElements in a page, along with all associated code behind. </p>  <p>Once I got the hang of MVVM myself, I started to see that the code behind file got smaller and smaller over time. In fact, in my personal projects, I typically try to reduce the code behind file to almost nothing, other than the standard boilerplate code automatically generated by Visual Studio.</p>  <p>In Go Search On, the MainPage class in MainPage.xaml and MainPage.xaml.cs represent the view used when searching a site for a string of text.</p>  <p>The View has 3 UI elements we’ll discuss in today’s post: </p>  <ul>   <li>The “[what site?] AutoCompleteTextBox, </li>    <li>The “[what?] TextBox, and </li>    <li>The “Go!” Button.</li> </ul>  <blockquote>   <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/7026.3---Main-Screen---logged-in_7843DEB1.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/7026.3_2D002D002D00_Main_2D00_Screen_2D002D002D00_logged_2D00_in_5F00_7843DEB1.png"><img title="3 - Main Screen - logged in" style="margin: 0px; display: inline; background-image: none;" border="0" alt="3 - Main Screen - logged in" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/4863.3---Main-Screen---logged-in_thumb_17F2B87A.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/4863.3_2D002D002D00_Main_2D00_Screen_2D002D002D00_logged_2D00_in_5F00_thumb_5F00_17F2B87A.png" width="148" height="244" /></a></p> </blockquote>  <h4><strong>The Model</strong></h4>  <p>The Model consists of the data structures and all related classes, properties, and methods that operate independently from the View and/or the View Model. This independence is important for multiple reasons, most notably, sharing code between different platforms. The Model will likely be the most portable aspect of your entire project. </p>  <p>For my TiVo Command application I’ve mentioned before, I use the TivoCommand model in my WP app I’ve published in the store, in my W8 modern app I’m developing, and in my 64-bit console app running on Win7 (the utility that started it all). The Model is shared, 100%, between all three projects, even though, they have very different user interfaces (WP, Windows 8, character mode console app).</p>  <p>In Go Search On, the SearchOnModel class in Models\SearchOnModel.cs is the model that we’ll use when searching a site for a string of text. If you look through the SearchOnModel class, you’ll see a lot of familiar code from earlier posts. </p>  <p>There’s also a new public function called CreateNewSearchTask that takes a site name and a string of text to find on that site. I’ve restructured the earlier code to ensure all entries thru the “view” flow thru the same code path. You can think of this CreateNewSearchTask method as that funnel point. No matter how the user expresses their interest to search a particular site for something, the code flow will go thru this function. </p>  <blockquote>   <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/8105.image_0CC92E30.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/8105.image_5F00_0CC92E30.png"><img title="image" style="border: 0px currentcolor; display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/7610.image_thumb_53B2512D.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/7610.image_5F00_thumb_5F00_53B2512D.png" width="400" height="318" /></a></p> </blockquote>  <h4>The View Model</h4>  <p>The View Model is where we tie together the View and the Model. You can think of the View Model as the UI-less version of the UI, that uses the underlying Model to do the heavy lifting. Essentially, the View Model represents everything that’s in the UI, in an object model that maps nicely to the UI, but with no actual UI code. </p>  <p>In Go Search On, the SearchOnViewModel class in Models\SearchOnViewModel.cs will help us do that “tying” together. The Model’s new function, CreateNewSearchTask, accepts two strings, whereas, on the View Model has two public string properties, SearchSiteName and SearchForWhat, which individually correspond to the two text boxes in our View. You’ll also find a public property called SearchNowCommand of type ICommand, that corresponds to the “Go!” button in the View (more on ICommand in a moment). </p>  <blockquote>   <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/3817.image_33974470.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/3817.image_5F00_33974470.png"><img title="image" style="border: 0px currentcolor; display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/3312.image_thumb_137C37B3.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/3312.image_5F00_thumb_5F00_137C37B3.png" width="400" height="345" /></a></p> </blockquote>  <h4>XAML Binding</h4>  <p>Using Windows Phone’s Silverlight implementation of XAML Binding, we can tie together the View and the View Model using a special declarative syntax in our XAML markup. You can read more about Windows Phone’s XAML Binding and the Binding syntax <a href="http://msdn.microsoft.com/en-us/library/windowsphone/develop/cc278072(v=vs.105).aspx">here</a>. </p>  <p>We want the public SearchOnViewModel’s SearchSiteName string property to be updated whenever someone updates the “[what site?]” AutoCompleteTextBox, and similarly, we’d like to keep the control up to date if we change the SearchSiteName programmatically. </p>  <p>We can achieve both of those goals by setting the Text attribute on the AutoCompleteTextBox XML element as follows:</p>  <blockquote>   <pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">AutoCompleteTextBox </span><span class="attr">Text</span><span class="kwrd">=&quot;{Binding SearchSiteName, Mode=TwoWay}&quot; <span class="attr">...<font color="#0000ff"> </font></span><span class="kwrd">/&gt;</span></span></pre>
  </blockquote>


<p>Similarly, we can bind the SearchForWhat property on the View Model to the other TextBox in the View by setting the Text attribute on its XML element:</p>

<blockquote>
  <pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">TextBox</span> <span class="attr">Text</span><span class="kwrd">=&quot;{Binding SearchForWhat, Mode=TwoWay}&quot; <span class="attr">...<font color="#0000ff"> </font></span><span class="kwrd">/&gt;</span></span></pre>
</blockquote>

<p>Now, let’s hook up the “Go!” Button:</p>

<blockquote>
  <pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Button</span> <span class="attr">Command</span><span class="kwrd">=&quot;{Binding SearchNowCommand, Mode=OneWay}&quot;</span> <span class="attr">Content</span><span class="kwrd">=&quot;GO! &quot;</span> <span class="attr">...<font color="#0000ff"> </font></span><span class="kwrd">/&gt;</span></pre>
</blockquote>

<p>For the preceding three bindings to work, we also have to have set the DataContext for each control, or set it on a parent control, like this:</p>


<blockquote>
  <pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span> <span class="attr">DataContext</span><span class="kwrd">=&quot;{StaticResource _model}&quot;</span><span class="kwrd">&gt;</span>
  </pre>
</blockquote>

<p>Just as you’d expect, that “_model” is of type SearchOnViewModel, declared in the Resources section of our XAML page like this:</p>

<blockquote>
  <pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">so:SearchOnViewModel</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;_model&quot;</span><span class="kwrd">/&gt;</span>
  </pre>
</blockquote>


<p>That’s all we need as far as the XAML file is concerned for today’s post. </p>

<p>Now anytime a user updates the Text property on either the TextBox or the AutoCompleteTextBox, the View Model will be updated accordingly. Similarly, if we set the SearchSiteName or SearchForWhat string properties on the model programmatically, the UI controls will be updated appropriately. That’s what the “TwoWay” Binding Mode indicates. It goes both ways. </p>

<p>Once the user is happy with the text she sees in both controls, she can click the “Go!” button, and our SearchNowCommand will be invoked. That will eventually result in a call to the CreateNewSearchTask function on the Model, with the SearchSiteName and the SearchForWhat string properties as the arguments. </p>

<blockquote>
  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/2335.diag4_73612AF5.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/2335.diag4_5F00_73612AF5.png"><img title="diag4" style="border: 0px currentcolor; display: inline; background-image: none;" border="0" alt="diag4" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/0272.diag4_thumb_6C41EE7D.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/0272.diag4_5F00_thumb_5F00_6C41EE7D.png" width="600" height="338" /></a></p>
</blockquote>

<p>But wait… how does all that actually work? How do the controls get updated when the string properties are changed? How does that ICommand thingy work?</p>

<p>Good questions … </p>

<h4>INotifyPropertyChanged</h4>

<p>For binding to work properly in both directions, the public string properties can’t just be naked string properties. </p>

<p>Instead, you’ll need to implement both a setter and a getter, where the setter can notify subscribers when the property changes, via the INotifyPropertyChanged interface. When we use binding in the XAML, WP’s XAML implementation subscribes to the PropertyChanged event on INotifyPropertyChanged, and when we update the value, we’ll fire the PropertyChanged event. </p>

<p>Here’s what that looks like for our View Model:</p>

<blockquote>
  <div class="csharpcode">
    <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">string</span> SearchSiteName</pre>

    <pre><span class="lnum">   2:  </span>{</pre>

    <pre class="alt"><span class="lnum">   3:  </span>    set { SetSearchSite(<span class="kwrd">value</span>); }</pre>

    <pre><span class="lnum">   4:  </span>    get { <span class="kwrd">return</span> GetSearchSite(); }</pre>

    <pre class="alt"><span class="lnum">   5:  </span>}</pre>

    <pre><span class="lnum">   6:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">   7:  </span><span class="kwrd">public</span> <span class="kwrd">string</span> SearchForWhat</pre>

    <pre><span class="lnum">   8:  </span>{</pre>

    <pre class="alt"><span class="lnum">   9:  </span>    set { SetSearchForWhat(<span class="kwrd">value</span>); }</pre>

    <pre><span class="lnum">  10:  </span>    get { <span class="kwrd">return</span> GetSearchForWhat(); }</pre>

    <pre class="alt"><span class="lnum">  11:  </span>}</pre>

    <pre><span class="lnum">  12:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  13:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> GetSearchSite()</pre>

    <pre><span class="lnum">  14:  </span>{</pre>

    <pre class="alt"><span class="lnum">  15:  </span>    <span class="kwrd">return</span> _searchSite;</pre>

    <pre><span class="lnum">  16:  </span>}</pre>

    <pre class="alt"><span class="lnum">  17:  </span>&#160;</pre>

    <pre><span class="lnum">  18:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> SetSearchSite(<span class="kwrd">string</span> siteName)</pre>

    <pre class="alt"><span class="lnum">  19:  </span>{</pre>

    <pre><span class="lnum">  20:  </span>    _notifyHelper.UpdateValue(<span class="kwrd">this</span>, <span class="kwrd">ref</span> _searchSite, siteName, <span class="str">&quot;SearchSiteName&quot;</span>);</pre>

    <pre class="alt"><span class="lnum">  21:  </span>}</pre>

    <pre><span class="lnum">  22:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  23:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> GetSearchForWhat()</pre>

    <pre><span class="lnum">  24:  </span>{</pre>

    <pre class="alt"><span class="lnum">  25:  </span>    <span class="kwrd">return</span> _searchForWhat;</pre>

    <pre><span class="lnum">  26:  </span>}</pre>

    <pre class="alt"><span class="lnum">  27:  </span>&#160;</pre>

    <pre><span class="lnum">  28:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> SetSearchForWhat(<span class="kwrd">string</span> s)</pre>

    <pre class="alt"><span class="lnum">  29:  </span>{</pre>

    <pre><span class="lnum">  30:  </span>    _notifyHelper.UpdateValue(<span class="kwrd">this</span>, <span class="kwrd">ref</span> _searchForWhat, s, <span class="str">&quot;SearchForWhat&quot;</span>);</pre>

    <pre class="alt"><span class="lnum">  31:  </span>}</pre>

    <pre><span class="lnum">  32:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  33:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> _searchSite = <span class="str">&quot;[what site?]&quot;</span>;</pre>

    <pre><span class="lnum">  34:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> _searchForWhat = <span class="str">&quot;[what?]&quot;</span>;</pre>
  </div>
</blockquote>

<p>Now, you can see that I’m using a helper class to do the string updates, and the notifications. It’s very handy helper, and I’ve written it such that you should be able to use it for all your INotifyPropertyChanged implementations. I do… Here it is in it’s entirety:</p>

<blockquote>
  <div class="csharpcode">
    <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">class</span> NotifyPropertyChangedHelper</pre>

    <pre><span class="lnum">   2:  </span>{</pre>

    <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">public</span> <span class="kwrd">event</span> PropertyChangedEventHandler PropertyChanged;</pre>

    <pre><span class="lnum">   4:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">   5:  </span>    <span class="preproc">#region</span> <span class="kwrd">value</span> setters</pre>

    <pre><span class="lnum">   6:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">   7:  </span>    <span class="kwrd">public</span> <span class="kwrd">void</span> SetValue&lt;T&gt;(<span class="kwrd">object</span> sender, <span class="kwrd">ref</span> T <span class="kwrd">value</span>, T newValue, <span class="kwrd">params</span> <span class="kwrd">string</span>[] propertyNames)</pre>

    <pre><span class="lnum">   8:  </span>    {</pre>

    <pre class="alt"><span class="lnum">   9:  </span>        <span class="kwrd">value</span> = newValue;</pre>

    <pre><span class="lnum">  10:  </span>        NotifyPropertyChanged(sender, propertyNames);</pre>

    <pre class="alt"><span class="lnum">  11:  </span>    }</pre>

    <pre><span class="lnum">  12:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  13:  </span>    <span class="kwrd">public</span> <span class="kwrd">bool</span> UpdateValue&lt;T&gt;(<span class="kwrd">object</span> sender, <span class="kwrd">ref</span> T <span class="kwrd">value</span>, T newValue, <span class="kwrd">params</span> <span class="kwrd">string</span>[] propertyNames) <span class="kwrd">where</span> T : System.IComparable&lt;T&gt;</pre>

    <pre><span class="lnum">  14:  </span>    {</pre>

    <pre class="alt"><span class="lnum">  15:  </span>        <span class="kwrd">bool</span> fChanged = <span class="kwrd">false</span>;</pre>

    <pre><span class="lnum">  16:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  17:  </span>        <span class="kwrd">if</span> (<span class="kwrd">value</span> == <span class="kwrd">null</span> || <span class="kwrd">value</span>.CompareTo(newValue) != 0)</pre>

    <pre><span class="lnum">  18:  </span>        {</pre>

    <pre class="alt"><span class="lnum">  19:  </span>            fChanged = <span class="kwrd">true</span>;</pre>

    <pre><span class="lnum">  20:  </span>            <span class="kwrd">value</span> = newValue;</pre>

    <pre class="alt"><span class="lnum">  21:  </span>            NotifyPropertyChanged(sender, propertyNames);</pre>

    <pre><span class="lnum">  22:  </span>        }</pre>

    <pre class="alt"><span class="lnum">  23:  </span>&#160;</pre>

    <pre><span class="lnum">  24:  </span>        <span class="kwrd">return</span> fChanged;</pre>

    <pre class="alt"><span class="lnum">  25:  </span>    }</pre>

    <pre><span class="lnum">  26:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  27:  </span>    <span class="preproc">#endregion</span></pre>

    <pre><span class="lnum">  28:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  29:  </span>    <span class="preproc">#region</span> notify helpers</pre>

    <pre><span class="lnum">  30:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  31:  </span>    <span class="kwrd">public</span> <span class="kwrd">void</span> NotifyPropertyChanged(<span class="kwrd">object</span> sender, <span class="kwrd">params</span> String[] propertyNames)</pre>

    <pre><span class="lnum">  32:  </span>    {</pre>

    <pre class="alt"><span class="lnum">  33:  </span>        <span class="kwrd">foreach</span> (<span class="kwrd">string</span> propertyName <span class="kwrd">in</span> propertyNames)</pre>

    <pre><span class="lnum">  34:  </span>        {</pre>

    <pre class="alt"><span class="lnum">  35:  </span>            NotifyPropertyChanged(sender, propertyName);</pre>

    <pre><span class="lnum">  36:  </span>        }</pre>

    <pre class="alt"><span class="lnum">  37:  </span>    }</pre>

    <pre><span class="lnum">  38:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  39:  </span>    <span class="kwrd">public</span> <span class="kwrd">void</span> NotifyPropertyChanged(<span class="kwrd">object</span> sender, String propertyName)</pre>

    <pre><span class="lnum">  40:  </span>    {</pre>

    <pre class="alt"><span class="lnum">  41:  </span>        PropertyChangedEventHandler handler = PropertyChanged;</pre>

    <pre><span class="lnum">  42:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  43:  </span>        <span class="kwrd">if</span> (<span class="kwrd">null</span> != handler)</pre>

    <pre><span class="lnum">  44:  </span>        {</pre>

    <pre class="alt"><span class="lnum">  45:  </span>            handler(sender, <span class="kwrd">new</span> PropertyChangedEventArgs(propertyName));</pre>

    <pre><span class="lnum">  46:  </span>        }</pre>

    <pre class="alt"><span class="lnum">  47:  </span>    }</pre>

    <pre><span class="lnum">  48:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  49:  </span>    <span class="preproc">#endregion</span></pre>

    <pre><span class="lnum">  50:  </span>}</pre>
  </div>
  </blockquote>

<p>You’ll also have to hook it up in your View Model’s class, like this:</p>

<blockquote>
  <div class="csharpcode">
    <pre class="alt"><span class="lnum">   1:  </span><span class="preproc">#region</span> Common INotifyPropertyChanged properties and data</pre>

    <pre><span class="lnum">   2:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">public</span> <span class="kwrd">event</span> PropertyChangedEventHandler PropertyChanged</pre>

    <pre><span class="lnum">   4:  </span>{</pre>

    <pre class="alt"><span class="lnum">   5:  </span>    add</pre>

    <pre><span class="lnum">   6:  </span>    {</pre>

    <pre class="alt"><span class="lnum">   7:  </span>        _notifyHelper.PropertyChanged += <span class="kwrd">value</span>;</pre>

    <pre><span class="lnum">   8:  </span>    }</pre>

    <pre class="alt"><span class="lnum">   9:  </span>    remove</pre>

    <pre><span class="lnum">  10:  </span>    {</pre>

    <pre class="alt"><span class="lnum">  11:  </span>        _notifyHelper.PropertyChanged -= <span class="kwrd">value</span>;</pre>

    <pre><span class="lnum">  12:  </span>    }</pre>

    <pre class="alt"><span class="lnum">  13:  </span>}</pre>

    <pre><span class="lnum">  14:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  15:  </span><span class="kwrd">private</span> NotifyPropertyChangedHelper _notifyHelper = <span class="kwrd">new</span> NotifyPropertyChangedHelper();</pre>

    <pre><span class="lnum">  16:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  17:  </span><span class="preproc">#endregion</span></pre>
  </div>
</blockquote>

<p>&#160;</p>

<h4>ICommand</h4>

<p>When a XAML Button has an object bound to it’s Command property, and that object implements the ICommand interface, the underlying XAML implementation will not only fire the Click event when the button is pressed, it will also call ICommand’s Execute method. </p>

<p>Sounds like it’s time for another helper class, yes? I’ve got you covered with a new helper called Command, which implements ICommand for you.</p>

<p>When the SearchOnViewModel is constructed, I create a instance of that new helper class, specifying that when ICommand.Execute is called, I’d like the SearchNowCommand_Execute local class method to be called.</p>

<p>Basically, I just cache away the delegates passed in the constructor, and use them from the ICommand method implementations. Here’s what that looks like:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> InitCommands()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    _commandSearchNow = <span class="kwrd">new</span> Command(</pre>

  <pre><span class="lnum">   4:  </span>        <span class="str">&quot;Search Now&quot;</span>, (<span class="kwrd">object</span> param) =&gt; { <span class="kwrd">return</span> <span class="kwrd">true</span>; }, </pre>

  <pre class="alt"><span class="lnum">   5:  </span>        (<span class="kwrd">object</span> param) =&gt; { SearchNowCommand_Execute(param); });</pre>
</div>

<p>And, for that to work, let’s take a look at the Command helper class, in its entirety: </p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">class</span> Command : ICommand</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">public</span> Command(Command command)</pre>

  <pre><span class="lnum">   4:  </span>    {</pre>

  <pre class="alt"><span class="lnum">   5:  </span>        _execute = command.Execute;</pre>

  <pre><span class="lnum">   6:  </span>        _canExecute = command.CanExecute;</pre>

  <pre class="alt"><span class="lnum">   7:  </span>        _name = command.Name;</pre>

  <pre><span class="lnum">   8:  </span>    }</pre>

  <pre class="alt"><span class="lnum">   9:  </span>&#160;</pre>

  <pre><span class="lnum">  10:  </span>    <span class="kwrd">public</span> Command(<span class="kwrd">string</span> name, CanExecuteStart canExecute, ExecuteStart execute)</pre>

  <pre class="alt"><span class="lnum">  11:  </span>    {</pre>

  <pre><span class="lnum">  12:  </span>        _execute = execute;</pre>

  <pre class="alt"><span class="lnum">  13:  </span>        _canExecute = canExecute;</pre>

  <pre><span class="lnum">  14:  </span>        _name = name;</pre>

  <pre class="alt"><span class="lnum">  15:  </span>    }</pre>

  <pre><span class="lnum">  16:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  17:  </span>    <span class="kwrd">public</span> <span class="kwrd">string</span> Name { get { <span class="kwrd">return</span> _name; } }</pre>

  <pre><span class="lnum">  18:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  19:  </span>    <span class="preproc">#region</span> ICommand <span class="kwrd">interface</span> implementation</pre>

  <pre><span class="lnum">  20:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  21:  </span>    <span class="kwrd">public</span> <span class="kwrd">event</span> EventHandler CanExecuteChanged;</pre>

  <pre><span class="lnum">  22:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  23:  </span>    <span class="kwrd">public</span> <span class="kwrd">bool</span> CanExecute(<span class="kwrd">object</span> parameter)</pre>

  <pre><span class="lnum">  24:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  25:  </span>        <span class="kwrd">return</span> _canExecute(parameter);</pre>

  <pre><span class="lnum">  26:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  27:  </span>&#160;</pre>

  <pre><span class="lnum">  28:  </span>    <span class="kwrd">public</span> <span class="kwrd">void</span> Execute(<span class="kwrd">object</span> parameter)</pre>

  <pre class="alt"><span class="lnum">  29:  </span>    {</pre>

  <pre><span class="lnum">  30:  </span>        _execute(parameter);</pre>

  <pre class="alt"><span class="lnum">  31:  </span>    }</pre>

  <pre><span class="lnum">  32:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  33:  </span>    <span class="preproc">#endregion</span></pre>

  <pre><span class="lnum">  34:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  35:  </span>    <span class="preproc">#region</span> delegates</pre>

  <pre><span class="lnum">  36:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  37:  </span>    <span class="kwrd">public</span> <span class="kwrd">delegate</span> <span class="kwrd">bool</span> CanExecuteStart(<span class="kwrd">object</span> parameter);</pre>

  <pre><span class="lnum">  38:  </span>    <span class="kwrd">public</span> <span class="kwrd">delegate</span> <span class="kwrd">void</span> ExecuteStart(<span class="kwrd">object</span> parameter);</pre>

  <pre class="alt"><span class="lnum">  39:  </span>&#160;</pre>

  <pre><span class="lnum">  40:  </span>    <span class="preproc">#endregion</span></pre>

  <pre class="alt"><span class="lnum">  41:  </span>&#160;</pre>

  <pre><span class="lnum">  42:  </span>    <span class="preproc">#region</span> <span class="kwrd">private</span> data</pre>

  <pre class="alt"><span class="lnum">  43:  </span>&#160;</pre>

  <pre><span class="lnum">  44:  </span>    <span class="kwrd">private</span> <span class="kwrd">string</span> _name;</pre>

  <pre class="alt"><span class="lnum">  45:  </span>    <span class="kwrd">private</span> CanExecuteStart _canExecute;</pre>

  <pre><span class="lnum">  46:  </span>    <span class="kwrd">private</span> ExecuteStart _execute;</pre>

  <pre class="alt"><span class="lnum">  47:  </span>&#160;</pre>

  <pre><span class="lnum">  48:  </span>    <span class="preproc">#endregion</span></pre>

  <pre class="alt"><span class="lnum">  49:  </span>}</pre>
</div>

<p>Again, I’ve tried to implement the Command helper class in Common\Command.cs in a way that you should be able to use it for most of your ICommand needs. </p>

<p>OK … Back to Go Search On … </p>

<p>Now that SearchNowCommand’s ICommand.Execute implementation calls thru to SearchNowCommand_Execute, I’ll need to make sure that we have a valid SearchSiteName, and a valid SearchForWhat. If we do, I’ll call off to another private method, SearchSiteForTextNow, passing the SearchSiteName and the SearchForWhat string properties. </p>

<p>If we don’t have a valid SearchSiteName, though, I'll use a Model method to get the search site via speech recognition (this is similar to what happened in previous posts when the wildcard/garbage rule was recognized in a voice command). Similarly, I’ll do the same for the SearchForWhat string property, if it’s still the default or if it’s empty.</p>

<p>Don’t worry about the method calls that set the visibility of some other controls, we’ll dig into those in a future post, although, it’s probably obvious what they’re trying to accomplish, maybe not just how they’ll accomplish it. </p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">async void</span> SearchNowCommand_Execute(<span class="kwrd">object</span> param)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    SetSearchNowCommandIsVisible(<span class="kwrd">false</span>);</pre>

  <pre><span class="lnum">   4:  </span>    SetCancelSearchNowCommandIsVisible(<span class="kwrd">true</span>);</pre>

  <pre class="alt"><span class="lnum">   5:  </span>&#160;</pre>

  <pre><span class="lnum">   6:  </span>    <span class="kwrd">if</span> (IsSearchSiteDefaultOrEmpty())</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    {</pre>

  <pre><span class="lnum">   8:  </span>        SetSearchSite(<span class="kwrd">await </span>_model.GetSearchSiteViaSpeech(<span class="kwrd">true</span>));</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    }</pre>

  <pre><span class="lnum">  10:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  11:  </span>    <span class="kwrd">if</span> (!IsSearchSiteDefaultOrEmpty() &amp;&amp; IsSearchForWhatDefaultOrEmpty())</pre>

  <pre><span class="lnum">  12:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  13:  </span>        SetSearchForWhat(<span class="kwrd">await </span>_model.GetSearchForWhatViaSpeech(GetSearchSite(), <span class="kwrd">true</span>));</pre>

  <pre><span class="lnum">  14:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  15:  </span>&#160;</pre>

  <pre><span class="lnum">  16:  </span>    <span class="kwrd">if</span> (!IsSearchSiteDefaultOrEmpty() &amp;&amp; !IsSearchForWhatDefaultOrEmpty())</pre>

  <pre class="alt"><span class="lnum">  17:  </span>    {</pre>

  <pre><span class="lnum">  18:  </span>        <span class="kwrd">await </span>SearchSiteForTextNow(GetSearchSite(), GetSearchForWhat());</pre>

  <pre class="alt"><span class="lnum">  19:  </span>    }</pre>

  <pre><span class="lnum">  20:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  21:  </span>    SetSearchNowCommandIsVisible(<span class="kwrd">true</span>);</pre>

  <pre><span class="lnum">  22:  </span>}</pre>
</div>

<p>Now, finally, inside SearchSiteForTextNow, we call the CreateNewSearchTask method on the underlying Model. </p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">async </span><span class="kwrd">Task </span>SearchSiteForTextNow(<span class="kwrd">string</span> siteName, <span class="kwrd">string</span> findText)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    SetSearchNowCommandIsVisible(<span class="kwrd">false</span>);</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">try</span></pre>

  <pre><span class="lnum">   6:  </span>    {</pre>

  <pre class="alt"><span class="lnum">   7:  </span>        _model.CreateNewSearchTask(siteName, findText);</pre>
</div>

<p>&#160;</p>

<h2>3 user scenarios, 1 view model, 1 model implementation</h2>

<p>Now, you might be wondering, why is it good to use MVVM. “This is a lot of code, Rob!!” Yes, you’re right!</p>

<p>To&#160; help understand why MVVM is a good thing, I’ll show you three different interaction flows the user may use to perform the same task:</p>

<ol>
  <li>User invokes app, fills in each field, clicks Go button</li>

  <li>User invokes app, clicks Go button right away</li>

  <li>User uses a voice command to invoke app (e.g. “Go Search On Amazon.com”)</li>
</ol>

<p>Each one of these scenarios eventually wind up in the same location, and each of them always keeps the user interface up to date along the way. </p>

<p>In addition, in future posts I’ll cover several other aspects of MVVM in this app. After reading each of those, I hope the beauty of MVVM starts to become more clear. I can’t imagine not using MVVM for all the applications I build for WP from now on, except, perhaps, for the most trivial. </p>

<p>OK .. On to the scenarios…</p>

<h4>User invokes app…</h4>

<p>In all three scenarios, the flow starts with the user invoking the application. </p>

<p>The app invocation could be have been by a voice command, or normally. </p>

<p>From the earlier posts, you’ll probably recall that we tapped into the NavigationContext.QueryString from within the MainPage.OnNavigatedTo method to determine if the invocation was via voice command or not, and when it was not a voice command, we make sure that the Voice Commands were already installed. We’ll do the same type of thing in our new version of the app, like this:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">base</span>.OnNavigatedTo(e);</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New &amp;&amp; NavigationContext.QueryString.ContainsKey(<span class="str">&quot;voiceCommandName&quot;</span>))</pre>

  <pre><span class="lnum">   6:  </span>    {</pre>

  <pre class="alt"><span class="lnum">   7:  </span>        HandleVoiceCommand(NavigationContext.QueryString);</pre>

  <pre><span class="lnum">   8:  </span>    }</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New)</pre>

  <pre><span class="lnum">  10:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  11:  </span>        HandleNonVoiceCommandInvocation();</pre>

  <pre><span class="lnum">  12:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  13:  </span>}</pre>
</div>

<p>Now, for all the non-voice command invocations, we’ll call off to the View Model from the View’s code to ensure that our application’s Voice Commands have been installed, and that the corresponding PhraseLists are all up to date. Like this:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> HandleNonVoiceCommandInvocation()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    _model.EnsureVoiceCommandsInstalled();</pre>

  <pre><span class="lnum">   4:  </span>}</pre>

  <pre class="alt"><span class="lnum">   5:  </span>&#160;</pre>
</div>

<p>Then, in the View Model, we’ll chain off to the underlying Model itself, where the real meat of the work takes place:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">void</span> EnsureVoiceCommandsInstalled()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    _model.EnsureVoiceCommandsInstalledAsync(<span class="kwrd">new</span> Uri(<span class="str">&quot;ms-appx:///vcd.xml&quot;</span>), <span class="kwrd">false</span>).Wait(0);</pre>

  <pre><span class="lnum">   4:  </span>}</pre>
</div>

<p>From there, it’s pretty similar to the code from before for installing the Voice Command Definitions, and making sure the PhraseLists are up to date. </p>

<p>Now … onto the specifics for the 3 scenarios…</p>

<h4>User invokes app, fills in each field, clicks Go button</h4>

<p>Here’s the basic flow of the app in this scenario:</p>

<ol>
  <li>Application starts, initializing the View (aka MainPage)</li>

  <ul>
    <li>The View ensures that the View Model has been created</li>

    <li>The View Model ensures that the Model has been created</li>
  </ul>

  <li>MainPage.OnNavigated is called</li>

  <ul>
    <li>App could have been invoked by a voice command, or normally</li>

    <li>MainPage.OnNavigated determines invocation is not a voice command invocation</li>

    <li>… Calls the View’s HandleNonVoiceCommandInvocation</li>

    <li>… … calls the View Model’s EnsureVoiceCommandsInstalled</li>

    <li>… … … calls _Model’s EnsureVoiceCommandsInstalledAsync</li>

    <li>The Model ensures that the voice commands have been installed, and the Phrase Lists are all up to date (similar to previous post)</li>
  </ul>

  <li>MainPage is Loaded</li>

  <ul>
    <li>XAML binding updates …</li>

    <li>… AutoCompleteTextBox.Text property from </li>

    <li>… … View Model’s SearchSiteName string value (which defaultly is “[what site?]”</li>

    <li>… TextBox.Text property from </li>

    <li>… … View Model’s SearchForWhat string value (which defaultly is “[what?]”</li>
  </ul>

  <li>User types in site name, clicks back to dismiss keyboard</li>

  <ul>
    <li>AutoCompleteTextBox.Text property is updated</li>

    <li>… XAML binding updates …</li>

    <li>… … View Model’s SearchSiteName string value</li>
  </ul>

  <li>User types in &quot;for what&quot; text, clicks back to dismiss keyboard</li>

  <ul>
    <li>TextBox.Text property is updated</li>

    <li>… XAML binding updates …</li>

    <li>… … View Model’s SearchForWhat string value</li>
  </ul>

  <li>User clicks on Go button&#160;&#160;&#160; </li>

  <ul>
    <li>XAML Button click logic calls ICommand.Execute</li>

    <li>… Calls the View Model’s SearchNowCommand_Execute method</li>

    <li>… … calls the View Model’s SearchSiteForTextNow passing SearchSiteName and SearchForWhat</li>

    <li>… … … calls the Model’s CreateNewSearchTask with passed SearchSiteName and SearchForWhat</li>
  </ul>
</ol>

<h4>User invokes app, clicks Go button right away</h4>

<p>Now, what if the user just clicks Go right away instead of taking the time to fill the fields out? </p>

<p>Its very similar to the previous flow, except, we’ll make sure that the SearchSiteName and SearchForWhat properties are not empty and aren’t the defaults (see step 3 below). If they are blank or the default (see step 4), we’ll use the Model to ask the user via the WP8 speech APIs.</p>

<ol>
  <li>Application starts, initializing the View (aka MainPage)</li>

  <ul>
    <li>The View ensures that the View Model has been created</li>

    <li>The View Model ensures that the Model has been created</li>
  </ul>

  <li>MainPage.OnNavigated is called</li>

  <ul>
    <li>App could have been invoked by a voice command, or normally</li>

    <li>MainPage.OnNavigated determines invocation is not a voice command invocation</li>

    <li>… Calls the View’s HandleNonVoiceCommandInvocation</li>

    <li>… … calls the View Model’s EnsureVoiceCommandsInstalled</li>

    <li>… … … calls _Model’s EnsureVoiceCommandsInstalledAsync</li>

    <li>The Model ensures that the voice commands have been installed, and the Phrase Lists are all up to date (similar to previous post)</li>
  </ul>

  <li>MainPage is Loaded</li>

  <ul>
    <li>Binding updates …</li>

    <li>… AutoCompleteTextBox.Text property from </li>

    <li>… … View Model’s SearchSiteName string value (which defaultly is “[what site?]”</li>

    <li>… TextBox.Text property from </li>

    <li>… … View Model’s SearchForWhat string value (which defaultly is “[what?]”</li>
  </ul>

  <li>User clicks on Go button&#160;&#160;&#160; </li>

  <ul>
    <li>XAML Button click logic calls ICommand.Execute</li>

    <li>… Calls the View Model’s SearchNowCommand_Execute method, which</li>

    <li>… … calls the Model’s _GetSearchSiteViaSpeech method and updates the SearchSiteName property</li>

    <li>… … … which notifies the XAML binding, updating the AutoCompleteTextBox.Text property</li>

    <li>… … calls the Model’s GetSearchForWhatViaSpeech method, and updates the SearchForWhat property</li>

    <li>… … … which notifies the XAML binding, updating the TextBox.Text property<!--EndFragment--></li>

    <li>… … and finally … </li>

    <li>… … calls the View Model’s SearchSiteForTextNow passing SearchSiteName and SearchForWhat</li>

    <li>… … … which calls the Model’s CreateNewSearchTask with passed SearchSiteName and SearchForWhat</li>
  </ul>
</ol>

<p>As you can see in step 4, simply because we set the View Model’s SearchSiteName and SearchForWhat properties with the speech recognition text results, the UI magically updated, without us having to care or remember. </p>

<h4>User uses a voice command to invoke the app (e.g. “Go Search On Amazon.com” )</h4>

<p>Now, conceptually, I consider a voice command as defined in the Voice Command Definitions file (e.g. vcd.xml) to be part of the View. There’s an underlying system that “renders” it, and does what’s needed, just like a Button. </p>

<p>Similarly, a command is a user’s request to perform some action, either via a XAML Button, or via a Voice Command. Now, with Voice Commands, as you’ve learned in earlier posts, we might need to pass query parameters that contain what voice command was recognized, and what items a user might have said from related PhraseLists. If only there were a way to pass a parameter to commands… Oh wait… There is … ;-)</p>

<p>ICommand.Execute receives a parameter of type object upon invocation, which can be null. For a Button, the parameter passed is the object that’s set or bound to the Button.CommandParameter property either via XAML or programmatically at runtime. </p>

<p>We’ll take advantage of that facility to make our Voice Commands look like Button Commands, passing the query string as the single parameter. </p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> HandleVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    _model.VoiceCommand.Execute(queryString);</pre>

  <pre><span class="lnum">   4:  </span>}</pre>
</div>

<p>Then, in the View Model, we’ll funnel the voice command invocation down to the SearchSiteVoiceCommand_Execute method, similarly to how the Button click winds its way down into the SearchNowCommand_Execute method:</p>

<blockquote>
  <div class="csharpcode">
    <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> VoiceCommandServiceCommand_Execute(<span class="kwrd">object</span> param)</pre>

    <pre><span class="lnum">   2:  </span>{</pre>

    <pre class="alt"><span class="lnum">   3:  </span>    IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString = param <span class="kwrd">as</span> IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt;;</pre>

    <pre><span class="lnum">   4:  </span>    <span class="kwrd">if</span> (queryString != <span class="kwrd">null</span>)</pre>

    <pre class="alt"><span class="lnum">   5:  </span>    {</pre>

    <pre><span class="lnum">   6:  </span>        VoiceCommandServiceCommand_Execute(queryString);</pre>

    <pre class="alt"><span class="lnum">   7:  </span>    }</pre>

    <pre><span class="lnum">   8:  </span>}</pre>

    <pre class="alt"><span class="lnum">   9:  </span>&#160;</pre>

    <pre><span class="lnum">  10:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> VoiceCommandServiceCommand_Execute(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

    <pre class="alt"><span class="lnum">  11:  </span>{</pre>

    <pre><span class="lnum">  12:  </span>    <span class="kwrd">switch</span> (queryString[<span class="str">&quot;voiceCommandName&quot;</span>])</pre>

    <pre class="alt"><span class="lnum">  13:  </span>    {</pre>

    <pre><span class="lnum">  14:  </span>        <span class="kwrd">case</span> <span class="str">&quot;searchSite&quot;</span>:</pre>

    <pre class="alt"><span class="lnum">  15:  </span>        <span class="kwrd">case</span> <span class="str">&quot;searchSiteCatchAll&quot;</span>:</pre>

    <pre><span class="lnum">  16:  </span>        <span class="kwrd">case</span> <span class="str">&quot;searchSiteCatchAll2&quot;</span>:</pre>

    <pre class="alt"><span class="lnum">  17:  </span>        <span class="kwrd">case</span> <span class="str">&quot;searchSiteCatchAll3&quot;</span>:</pre>

    <pre><span class="lnum">  18:  </span>        <span class="kwrd">case</span> <span class="str">&quot;searchSiteCatchAll4&quot;</span>:</pre>

    <pre class="alt"><span class="lnum">  19:  </span>        <span class="kwrd">case</span> <span class="str">&quot;searchSiteCatchAll5&quot;</span>:</pre>

    <pre><span class="lnum">  20:  </span>        <span class="kwrd">case</span> <span class="str">&quot;searchSiteCatchAll6&quot;</span>:</pre>

    <pre class="alt"><span class="lnum">  21:  </span>        <span class="kwrd">case</span> <span class="str">&quot;searchSiteCatchAll7&quot;</span>:</pre>

    <pre><span class="lnum">  22:  </span>            SearchSiteVoiceCommand_Execute(queryString);</pre>

    <pre class="alt"><span class="lnum">  23:  </span>            <span class="kwrd">break</span>;</pre>

    <pre><span class="lnum">  24:  </span>    }</pre>

    <pre class="alt"><span class="lnum">  25:  </span>}</pre>

    <pre><span class="lnum">  26:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  27:  </span><span class="kwrd">private</span> <span class="kwrd">async void </span>SearchSiteVoiceCommand_Execute(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

    <pre><span class="lnum">  28:  </span>{</pre>

    <pre class="alt"><span class="lnum">  29:  </span>    SetSearchNowCommandIsVisible(<span class="kwrd">false</span>);</pre>

    <pre><span class="lnum">  30:  </span>    SetCancelSearchNowCommandIsVisible(<span class="kwrd">true</span>);</pre>

    <pre class="alt"><span class="lnum">  31:  </span>&#160;</pre>

    <pre><span class="lnum">  32:  </span>    SetSearchSite(</pre>

    <pre class="alt"><span class="lnum">  33:  </span>        queryString.ContainsKey(<span class="str">&quot;siteToSearch&quot;</span>)</pre>

    <pre><span class="lnum">  34:  </span>            ? queryString[<span class="str">&quot;siteToSearch&quot;</span>]</pre>

    <pre class="alt"><span class="lnum">  35:  </span>            : <span class="kwrd">await </span>_model.GetSearchSiteViaSpeech(<span class="kwrd">false</span>));</pre>

    <pre><span class="lnum">  36:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  37:  </span>    <span class="kwrd">if</span> (!IsSearchSiteDefaultOrEmpty())</pre>

    <pre><span class="lnum">  38:  </span>    {</pre>

    <pre class="alt"><span class="lnum">  39:  </span>        <span class="kwrd">bool</span> fVoiceCommandServiceAlreadyPrompted = queryString.ContainsKey(<span class="str">&quot;siteToSearch&quot;</span>);</pre>

    <pre><span class="lnum">  40:  </span>        SetSearchForWhat(<span class="kwrd">await </span>_model.GetSearchForWhatViaSpeech(GetSearchSite(), !fVoiceCommandServiceAlreadyPrompted));</pre>

    <pre class="alt"><span class="lnum">  41:  </span>    }</pre>

    <pre><span class="lnum">  42:  </span>&#160;</pre>

    <pre class="alt"><span class="lnum">  43:  </span>    <span class="kwrd">if</span> (!IsSearchSiteDefaultOrEmpty() &amp;&amp; !IsSearchForWhatDefaultOrEmpty())</pre>

    <pre><span class="lnum">  44:  </span>    {</pre>

    <pre class="alt"><span class="lnum">  45:  </span>        <span class="kwrd">await </span>SearchSiteForTextNow(GetSearchSite(), GetSearchForWhat());</pre>

    <pre><span class="lnum">  46:  </span>    }</pre>

    <pre class="alt"><span class="lnum">  47:  </span>&#160;</pre>

    <pre><span class="lnum">  48:  </span>    SetSearchNowCommandIsVisible(<span class="kwrd">true</span>);</pre>

    <pre class="alt"><span class="lnum">  49:  </span>}</pre>
  </div>
</blockquote>

<p>Even though the SearchSiteVoiceCommand_Execute method is very similar to the SearchNowCommand_Execute, there are a couple key differences:</p>

<ol>
  <li>We need to set the SearchSiteName based on the Voice Command query string parameter named “siteToSearch”.</li>

  <ul>
    <li>If we don’t have one of those, we’ll use Speech to get one, just like the 2nd scenario</li>
  </ul>

  <li>When we try and get the SearchForWhat via Speech, we might not want to prompt.</li>

  <ul>
    <li>If we hit the wildcard voice command case, </li>

    <li>… we’ll collect the SearchSiteName, after the VCD TextFeedback prompted the user for that.</li>

    <li>Then, we’ll have to prompt the user directly, ourselves, for the SearchForWhat text, </li>

    <li>… with a prompt like “Search Amazon.com for what?”</li>
  </ul>
</ol>

<p>OK. Now with that, let’s look at the entire app flow for this 3rd scenario:</p>

<ol>
  <li>Application starts, initializing the View (aka MainPage)</li>

  <ul>
    <li>The View ensures that the View Model has been created</li>

    <li>The View Model ensures that the Model has been created</li>
  </ul>

  <li>MainPage.OnNavigated is called</li>

  <ul>
    <li>App could have been invoked by a voice command, or normally</li>

    <li>MainPage.OnNavigated determines invocation is a voice command invocation</li>

    <li>… Calls the View’s HandleVoiceCommandInvocation</li>

    <li>… … calls the ICommand.Execute for the ICommand obtained from SearchOnViewModel.VoiceCommand</li>

    <li>… … … calls the View Model’s VoiceCommandServiceCommand_Execute method</li>

    <li>… … … … calls the View Model’s SearchSiteVoiceCommand_Execute method</li>
  </ul>

  <li>Meanwhile, MainPage is Loaded</li>

  <ul>
    <li>Binding updates …</li>

    <li>… AutoCompleteTextBox.Text property from </li>

    <li>… … View Model’s SearchSiteName string value (which defaultly is “[what site?]”</li>

    <li>… TextBox.Text property from </li>

    <li>… … View Model’s SearchForWhat string value (which defaultly is “[what?]”</li>
  </ul>

  <li>SearchSiteVoiceCommand_Execute continues</li>

  <ul>
    <li>… … calls the Model’s GetSearchSiteViaSpeech method and updates the SearchSiteName property</li>

    <li>… … … which notifies the XAML binding, updating the AutoCompleteTextBox.Text property</li>

    <li>… … calls the Model’s GetSearchForWhatViaSpeech method, and updates the SearchForWhat property</li>

    <li>… … … which notifies the XAML binding, updating the TextBox.Text property</li>

    <li>… … and finally … </li>

    <li>… … calls the View Model’s SearchSiteForTextNow passing SearchSiteName and SearchForWhat</li>

    <li>… … … which calls the Model’s CreateNewSearchTask with passed SearchSiteName and SearchForWhat</li>
  </ul>
</ol>

<h2>The End!</h2>

<p>Hopefully you now have a better idea how you can use MVVM with your WP8 application, and how you can hook up voice commands in this brave new MVVM world. You can download the full source for the project <a href="http://files.wsrguy.com/wp8/searchon/SearchOn.zip">here</a>. It will build, but won’t work without my secret keys for Azure and for Windows Live, but I can’t really share those, now can I? </p>

<p>And … You can download the app from the Windows Phone Marketplace <strong><a href="http://www.windowsphone.com/s?appid=2ecf006a-2bc2-4fa5-b518-3bd92c40226f">here</a></strong>, as well. </p>

<p>I hope you find the app, the source, and the blog post useful. ;-)</p>]]></content:encoded>
    </item>
    <item>
      <title>WP8 Voice Commands: Dynamic Phrase Lists … From Azure!</title>
      <link>https://docs.microsoft.com/archive/blogs/robch/wp8-voice-commands-dynamic-phrase-lists-from-azure</link>
      <pubDate>Wed, 14 Nov 2012 17:02:21 GMT</pubDate>
      <dc:creator><![CDATA[Rob Chambers]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/robch/2012/11/14/wp8-voice-commands-dynamic-phrase-lists-from-azure/</guid>
      <description><![CDATA[Over the last couple weeks, I’ve been demonstrating various features of the new speech platform...]]></description>
      <content:encoded><![CDATA[<p>Over the last couple weeks, I’ve been demonstrating various features of the new speech platform included in Windows Phone 8.0. So far, we’ve covered the following topic areas:</p>  <ul>   <li><a href="http://blogs.msdn.com/b/robch/archive/2012/11/01/windows-phone-8-is-here-start-speech-enabling-your-apps.aspx">Start Speech Enabling your apps!</a> … where I consolidated a bunch of resources, and uploaded a video of a “real world” Windows Phone application that I’ve “speech enabled” myself, called Tivo Command.</li>    <li><a href="http://blogs.msdn.com/b/robch/archive/2012/11/06/how-many-lines-of-code-does-it-take-to-build-a-complete-wp8-speech-app.aspx">How many lines of code does it take to build a complete WP8 speech app?</a> … where we found the answer to be a very small number. Especially considering the fact that our first version of our “Search On” sample app used Voice Commands, Speech Recognition, and Speech Synthesis.</li>    <li><a href="http://blogs.msdn.com/b/robch/archive/2012/11/07/wp8-voice-commands-phrase-lists.aspx">WP8: Voice Command Phrase Lists</a> … building upon our “Search On” sample app, we saw how we could extend the voice commands our users can use, simply by using &lt;PhraseList&gt; elements inside our Voice Command Definition (VCD) xml file.</li>    <li><a href="http://blogs.msdn.com/b/robch/archive/2012/11/08/wp8-voice-commands-wildcards.aspx">WP8: Voice Command Wildcards</a> … we extended our app to deal with the cases when a user said something unexpected, by using a handy Voice Command Service feature, we call wildcards (we also sometimes call it a garbage rule, or garbage model)</li> </ul>  <p>Today, I’m going to pick up where we left off with our “Search On” application, and demonstrate how you as “the developer” behind the app, can update the phrases that users can say to your app, from the server side of the system. </p>  <p>The “speech part” of this is actually quite simple. In fact, if we had a list of strings (List&lt;string&gt;) just laying around inside our app, it would only takes a few lines of code to update our Phrase List contained inside our VCD that’s loaded into the Voice Command Service. The harder part, truly, is getting that list from a server, hosting the list on said server, and dealing with other changes that result from the list being server side. </p>  <p>Since this is a predominantly “speech” blog posting, I thought I’d lead with the “speech” part of the code. If you’re one of those types that likes spoilers, feel free to scan ahead to take a look at the full solution, but I’ll try to make it worth your while to hold off until we get there. :-)</p>  <p>&#160;</p>  <h1>The “Speech” Part</h1>  <p>OK. The “speech” part of updating phrase lists is pretty straight forward, like I said. Let’s look at the code…</p>  <div class="csharpcode">   <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> async Task UpdatePhraseListsAsync()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">foreach</span> (VoiceCommandSet cs <span class="kwrd">in</span> VoiceCommandService.InstalledCommandSets.Values)</pre>

  <pre><span class="lnum">   4:  </span>    {</pre>

  <pre class="alt"><span class="lnum">   5:  </span>        List&lt;<span class="kwrd">string</span>&gt; updatedListOfPhrases = GetPhrasesForUpdatedSiteToSearchPhraseList(cs.Language.ToLower());</pre>

  <pre><span class="lnum">   6:  </span>        await cs.UpdatePhraseListAsync(<span class="str">&quot;siteToSearch&quot;</span>, updatedListOfPhrases);</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    }</pre>

  <pre><span class="lnum">   8:  </span>}</pre>
</div>


<p>If you recall, a VCD file can have one or more &lt;CommandSet&gt; elements, representing different “languages” or “dialects”. Our VCD file only has one, for “en-US” at the moment. I’ll probably post an update to our “Search On” sample app in the future, enabling voice commands in more than one language, and thus containing more than one &lt;CommandSet&gt;. But for now, we just have one. Having said that, I’m going to go ahead and write the code for updating the phrase lists in a language neutral way, such that it should just work once that future post actually gets written. </p>

<p>To update the phrase list, as you can see, I’ve created a new method, called UpdatePhraseListsAsync, which simply iterates through all the installed Command Sets, gets a list of strings (the phrases users can say), and then calls UpdatePhraseListAsync on the VoiceCommandSet object we got from the VoiceCommandService. </p>

<p>One caveat I want to warn you about, though. Even if you’ve successfully installed your Command Sets in the VoiceCommandService, the InstalledCommandSets collection may be empty. That happens if you didn’t include a “Name” on the &lt;CommandSet&gt; in your VCD file. We did this because the collection is actually a Dictionary, and thus, you have to have a “key” to look up the “value”. No key, No value. Thus, we have to update our VCD as follows:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   6:  </span><span class="kwrd">&lt;</span><span class="html">CommandSet</span> <span class="attr">xml:lang</span><span class="kwrd">=&quot;en-US&quot;</span> <span class="attr">Name</span><span class="kwrd">=&quot;commands-en-us&quot;</span><span class="kwrd">&gt;</span></pre>
</div>


<p>Great. The speech part is done. Let’s run it! … Wait. We have a lot of other changes. Like, getting the phrases for the siteToSearch phrase list. Let’s take a look at that method by method.</p>

<p>First up, GetPhrasesForUpdatedSiteToSearchPhraseList:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> List&lt;<span class="kwrd">string</span>&gt; GetPhrasesForUpdatedSiteToSearchPhraseList(<span class="kwrd">string</span> language)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    List&lt;<span class="kwrd">string</span>&gt; phrasesBuiltIn = GetPhrasesForUpdatedSiteToSearchPhraseListFromBuiltInList();</pre>

  <pre><span class="lnum">   4:  </span>    List&lt;<span class="kwrd">string</span>&gt; phrasesFromAzure = GetPhrasesForUpdatedSiteToSearchPhraseListFromAzure(language);</pre>

  <pre class="alt"><span class="lnum">   5:  </span>&#160;</pre>

  <pre><span class="lnum">   6:  </span>    <span class="kwrd">return</span> phrasesFromAzure.Union(phrasesBuiltIn).ToList();</pre>

  <pre class="alt"><span class="lnum">   7:  </span>}</pre>
</div>

<p>First, we get a list of phrases rom the built in list, then a list of phrases from Azure, and then we returned the combined list. Neat, eh?</p>

<p>Wait… Did I just say from Azure? Yeah. I did. </p>

<h1>The “Hosting in Azure” Part</h1>

<p>While I was considering where to store my list, I remembered that some of my friends over in the Azure team just released a really cool new feature called Azure Mobile Services. You can read about it <a href="http://weblogs.asp.net/scottgu/archive/2012/08/28/announcing-windows-azure-mobile-services.aspx">here</a> from the original announcement in August on ScottGu’s blog, or <a href="http://blogs.msdn.com/b/windowsazure/archive/2012/11/01/building-out-mobile-services-support-to-windows-phone-8.aspx">here</a> from the Build announcement / blog post a couple weeks ago. </p>

<p>There are many things I love about Azure Mobile Services. But I’ll only list a couple here: They have a <a href="https://www.windowsazure.com/en-us/pricing/free-trial/">free 90 day trial</a>; the <a href="https://www.windowsazure.com/en-us/develop/mobile/tutorials/get-started-wp8/">To Do sample app on their quick start</a> page makes it brain dead easy to build your first app with data hosted in azure; there are APIs for Windows 8, Windows Phone 8, and <a href="http://msdn.microsoft.com/en-us/library/windowsazure/jj710104.aspx">REST based APIs</a> as well. </p>

<p>OK. You can either follow along here and use my Azure Mobile Service, (hosted here), or you can sign up for your own free trial, and have your own server side solution for your version of our “Search On” sample application. </p>

<h2>Setting up your Azure Mobile Service</h2>

<p>To set up my Azure Mobile Service. Here’s what I did, step by step (you can do the same, once you have an account):</p>

<p>Log in to the Azure portal <a href="https://manage.windowsazure.com/">here</a>.</p>

<p>Click on the Mobile Services tab:</p>

<blockquote>
  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/5430.image_1F909E98.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/5430.image_5F00_1F909E98.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/0068.image_thumb_6CC09823.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/0068.image_5F00_thumb_5F00_6CC09823.png" width="404" height="229" /></a></p>
</blockquote>

<p>Click “New” to create a new Mobile Service.</p>

<blockquote>
  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/6320.image_1EB838AE.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/6320.image_5F00_1EB838AE.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/3276.image_thumb_5E821F33.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/3276.image_5F00_thumb_5F00_5E821F33.png" width="404" height="229" /></a></p>
</blockquote>

<p>Click “Compute”, “Mobile Service”, and then “Create”. That should land you here:</p>

<blockquote>
  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/0640.image_3E671276.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/0640.image_5F00_3E671276.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/3782.image_thumb_0C033EF7.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/3782.image_5F00_thumb_5F00_0C033EF7.png" width="404" height="229" /></a></p>
</blockquote>

<p>Pick a URL (I picked robchblogsamples), select “Create a new database”, and pick your subscription. Then click the “Next” arrow. </p>

<blockquote>
  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/6428.image_3DFADF81.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/6428.image_5F00_3DFADF81.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/4375.image_thumb_64C8F5C1.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/4375.image_5F00_thumb_5F00_64C8F5C1.png" width="404" height="229" /></a></p>
</blockquote>



<p>Confirm the name of your new database, and then fill in the credentials you want to use for your new sql database. When you’re done, click the “Complete” check mark in the lower right hand corner.</p>

<p>That’s it! You now have your very own Azure Mobile Service. </p>

<blockquote>
  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/6332.image_44ADE904.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/6332.image_5F00_44ADE904.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/7802.image_thumb_0477CF8A.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/7802.image_5F00_thumb_5F00_0477CF8A.png" width="404" height="229" /></a></p>
</blockquote>

<p>I’d suggest you play with the WP8 To Do application for a few minutes, by clicking on the “Create a new Windows Phone 8” application link on the quick start tab you’re already sitting on … Once you’ve played around with that, come back here… </p>

<p>OK… Was that fun? Seems like you were only gone for a few seconds. :-)</p>

<p>Now, without going into a lot of details today, here’s the quick version of what I did to populate my Azure Mobile Service with a table filled with “rows” of data, that represent different “sites” that the user can search using our “Search On” application:</p>

<ul>
  <li>Create a new table, called SiteToSearchItem</li>

  <li>Set the permissions on that table such that “Everyone” has read permission</li>

  <li>Modify the WP8 To Do app you just played with, to add “sites” instead of To Do items</li>

  <li>And finally … use that app to add some sites.</li>
</ul>

<p>Make sense? OK … Let’s do that step by step:</p>

<h2>Creating the table, setting the permissions</h2>

<p>Create the new table, called SiteToSearchItem, by first, clicking on the “Data” tab… Then click the “Create” button at the bottom, and fill out the fields appropriately:</p>

<blockquote>
  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/6320.image_4F6B4059.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/6320.image_5F00_4F6B4059.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/2627.image_thumb_0F3526DF.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/2627.image_5F00_thumb_5F00_0F3526DF.png" width="404" height="229" /></a></p>
</blockquote>

<p>After clicking the “Complete” check mark in the lower right hand corner, your table will be created. It’ll just take a few seconds.</p>

<p>Now click your new “SiteToSearchItem” table. No data! Well … that makes sense. We haven’t added any yet. Let’s do that now.</p>

<h2>Modify the WP8 app to add “sites”</h2>

<p>Now, we’re going to modify the WP8 To Do app from the quick start tab in your new Azure Mobile Service, to add “sites” instead of “to do” items. At the highest level, here’s what I did to change that app in that way:</p>

<p><u>In MainPage.xaml.cs:</u></p>

<ul>
  <li>Renamed the ToDoItem class into a new SiteToSearchItem class.</li>

  <li>Removed the two existing “To Do” data members from that class that were “To Do” specific.</li>

  <li>Added public get/set properties for SiteName, Domain, SearchUrlTemplate, and Language.</li>

  <ul>
    <li>Examples for those values would be:</li>

    <li>SiteName = “Bing”, Domain = “www.bing.com”, SearchUrlTemplate = “http://www.bing.com/search?q={0}”, and Language = “en-US”</li>
  </ul>
</ul>

<p><u>In MainPage.xaml:</u></p>

<ul>
  <li>Removed Checkbox, and To Do Textbox</li>

  <li>Added Textboxes for SiteName, Domain, SearchUrlTemplate, and Language</li>

  <li>Added a ScrollViewer, and Reformatted to make more usable</li>
</ul>

<p>Here’s what that ended up looking like, in MainPage.xaml.cs:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">using</span> System;</pre>

  <pre><span class="lnum">   2:  </span><span class="kwrd">using</span> System.Collections.Generic;</pre>

  <pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">using</span> System.Linq;</pre>

  <pre><span class="lnum">   4:  </span><span class="kwrd">using</span> System.Net;</pre>

  <pre class="alt"><span class="lnum">   5:  </span><span class="kwrd">using</span> System.Runtime.Serialization;</pre>

  <pre><span class="lnum">   6:  </span><span class="kwrd">using</span> System.Windows;</pre>

  <pre class="alt"><span class="lnum">   7:  </span><span class="kwrd">using</span> System.Windows.Controls;</pre>

  <pre><span class="lnum">   8:  </span><span class="kwrd">using</span> System.Windows.Navigation;</pre>

  <pre class="alt"><span class="lnum">   9:  </span><span class="kwrd">using</span> Microsoft.Phone.Controls;</pre>

  <pre><span class="lnum">  10:  </span><span class="kwrd">using</span> Microsoft.Phone.Shell;</pre>

  <pre class="alt"><span class="lnum">  11:  </span><span class="kwrd">using</span> robchblogsamples.Resources;</pre>

  <pre><span class="lnum">  12:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  13:  </span><span class="kwrd">using</span> Microsoft.WindowsAzure.MobileServices;</pre>

  <pre><span class="lnum">  14:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  15:  </span><span class="kwrd">namespace</span> robchblogsamples</pre>

  <pre><span class="lnum">  16:  </span>{</pre>

  <pre class="alt"><span class="lnum">  17:  </span>    <span class="kwrd">public</span> <span class="kwrd">class</span> SiteToSearchItem</pre>

  <pre><span class="lnum">  18:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  19:  </span>        <span class="kwrd">public</span> <span class="kwrd">int</span> Id { get; set; }</pre>

  <pre><span class="lnum">  20:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  21:  </span>        [DataMember(Name = <span class="str">&quot;SiteName&quot;</span>)]</pre>

  <pre><span class="lnum">  22:  </span>        <span class="kwrd">public</span> <span class="kwrd">string</span> SiteName { get; set; }</pre>

  <pre class="alt"><span class="lnum">  23:  </span>&#160;</pre>

  <pre><span class="lnum">  24:  </span>        [DataMember(Name = <span class="str">&quot;Language&quot;</span>)]</pre>

  <pre class="alt"><span class="lnum">  25:  </span>        <span class="kwrd">public</span> <span class="kwrd">string</span> Language{ get; set; }</pre>

  <pre><span class="lnum">  26:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  27:  </span>        [DataMember(Name = <span class="str">&quot;Domain&quot;</span>)]</pre>

  <pre><span class="lnum">  28:  </span>        <span class="kwrd">public</span> <span class="kwrd">string</span> Domain { get; set; }</pre>

  <pre class="alt"><span class="lnum">  29:  </span>&#160;</pre>

  <pre><span class="lnum">  30:  </span>        [DataMember(Name = <span class="str">&quot;SearchUrlTemplate&quot;</span>)]</pre>

  <pre class="alt"><span class="lnum">  31:  </span>        <span class="kwrd">public</span> <span class="kwrd">string</span> SearchUrlTemplate { get; set; }</pre>

  <pre><span class="lnum">  32:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  33:  </span>&#160;</pre>

  <pre><span class="lnum">  34:  </span>    <span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> MainPage : PhoneApplicationPage</pre>

  <pre class="alt"><span class="lnum">  35:  </span>    {</pre>

  <pre><span class="lnum">  36:  </span>        <span class="kwrd">private</span> MobileServiceCollectionView&lt;SiteToSearchItem&gt; items;</pre>

  <pre class="alt"><span class="lnum">  37:  </span>&#160;</pre>

  <pre><span class="lnum">  38:  </span>        <span class="kwrd">private</span> IMobileServiceTable&lt;SiteToSearchItem&gt; _table = App.MobileService.GetTable&lt;SiteToSearchItem&gt;();</pre>

  <pre class="alt"><span class="lnum">  39:  </span>&#160;</pre>

  <pre><span class="lnum">  40:  </span>        <span class="kwrd">public</span> MainPage()</pre>

  <pre class="alt"><span class="lnum">  41:  </span>        {</pre>

  <pre><span class="lnum">  42:  </span>            InitializeComponent();</pre>

  <pre class="alt"><span class="lnum">  43:  </span>        }</pre>

  <pre><span class="lnum">  44:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  45:  </span>        <span class="kwrd">private</span> async <span class="kwrd">void</span> InsertItem(SiteToSearchItem item)</pre>

  <pre><span class="lnum">  46:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  47:  </span>            await _table.InsertAsync(item);</pre>

  <pre><span class="lnum">  48:  </span>            items.Add(item);</pre>

  <pre class="alt"><span class="lnum">  49:  </span>        }</pre>

  <pre><span class="lnum">  50:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  51:  </span>        <span class="kwrd">private</span> <span class="kwrd">void</span> RefreshItems()</pre>

  <pre><span class="lnum">  52:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  53:  </span>            items = _table</pre>

  <pre><span class="lnum">  54:  </span>                .Where(item =&gt; item.Language == <span class="str">&quot;en-us&quot;</span>)</pre>

  <pre class="alt"><span class="lnum">  55:  </span>                .ToCollectionView();</pre>

  <pre><span class="lnum">  56:  </span>            ListItems.ItemsSource = items;</pre>

  <pre class="alt"><span class="lnum">  57:  </span>        }</pre>

  <pre><span class="lnum">  58:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  59:  </span>        <span class="kwrd">private</span> async <span class="kwrd">void</span> UpdateItem(SiteToSearchItem item)</pre>

  <pre><span class="lnum">  60:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  61:  </span>            await _table.UpdateAsync(item);</pre>

  <pre><span class="lnum">  62:  </span>            items.Remove(item);</pre>

  <pre class="alt"><span class="lnum">  63:  </span>        }</pre>

  <pre><span class="lnum">  64:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  65:  </span>        <span class="kwrd">private</span> <span class="kwrd">void</span> ButtonRefresh_Click(<span class="kwrd">object</span> sender, RoutedEventArgs e)</pre>

  <pre><span class="lnum">  66:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  67:  </span>            RefreshItems();</pre>

  <pre><span class="lnum">  68:  </span>        }</pre>

  <pre class="alt"><span class="lnum">  69:  </span>&#160;</pre>

  <pre><span class="lnum">  70:  </span>        <span class="kwrd">private</span> <span class="kwrd">void</span> ButtonSave_Click(<span class="kwrd">object</span> sender, RoutedEventArgs e)</pre>

  <pre class="alt"><span class="lnum">  71:  </span>        {</pre>

  <pre><span class="lnum">  72:  </span>            var item = <span class="kwrd">new</span> SiteToSearchItem </pre>

  <pre class="alt"><span class="lnum">  73:  </span>            { </pre>

  <pre><span class="lnum">  74:  </span>                SiteName = _textboxSiteName.Text, </pre>

  <pre class="alt"><span class="lnum">  75:  </span>                Language = _textboxLanguage.Text,</pre>

  <pre><span class="lnum">  76:  </span>                Domain = _textblockDomain.Text,</pre>

  <pre class="alt"><span class="lnum">  77:  </span>                SearchUrlTemplate = _textboxUrlTemplate.Text</pre>

  <pre><span class="lnum">  78:  </span>            };</pre>

  <pre class="alt"><span class="lnum">  79:  </span>&#160;</pre>

  <pre><span class="lnum">  80:  </span>            InsertItem(item);</pre>

  <pre class="alt"><span class="lnum">  81:  </span>        }</pre>

  <pre><span class="lnum">  82:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  83:  </span>        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)</pre>

  <pre><span class="lnum">  84:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  85:  </span>            RefreshItems();</pre>

  <pre><span class="lnum">  86:  </span>        }</pre>

  <pre class="alt"><span class="lnum">  87:  </span>    }</pre>

  <pre><span class="lnum">  88:  </span>}</pre>
</div>

<p>…. and this in MainPage.xaml:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">&lt;</span><span class="html">phone:PhoneApplicationPage</span></pre>

  <pre><span class="lnum">   2:  </span>    <span class="attr">x:Class</span><span class="kwrd">=&quot;robchblogsamples.MainPage&quot;</span></pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></pre>

  <pre><span class="lnum">   4:  </span>    <span class="attr">xmlns:x</span><span class="kwrd">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span></pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="attr">xmlns:phone</span><span class="kwrd">=&quot;clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone&quot;</span></pre>

  <pre><span class="lnum">   6:  </span>    <span class="attr">xmlns:shell</span><span class="kwrd">=&quot;clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone&quot;</span></pre>

  <pre class="alt"><span class="lnum">   7:  </span>    <span class="attr">xmlns:d</span><span class="kwrd">=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;</span></pre>

  <pre><span class="lnum">   8:  </span>    <span class="attr">xmlns:mc</span><span class="kwrd">=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;</span></pre>

  <pre class="alt"><span class="lnum">   9:  </span>    <span class="attr">mc:Ignorable</span><span class="kwrd">=&quot;d&quot;</span></pre>

  <pre><span class="lnum">  10:  </span>    <span class="attr">FontFamily</span><span class="kwrd">=&quot;{StaticResource PhoneFontFamilyNormal}&quot;</span></pre>

  <pre class="alt"><span class="lnum">  11:  </span>    <span class="attr">FontSize</span><span class="kwrd">=&quot;{StaticResource PhoneFontSizeNormal}&quot;</span></pre>

  <pre><span class="lnum">  12:  </span>    <span class="attr">Foreground</span><span class="kwrd">=&quot;{StaticResource PhoneForegroundBrush}&quot;</span></pre>

  <pre class="alt"><span class="lnum">  13:  </span>    <span class="attr">SupportedOrientations</span><span class="kwrd">=&quot;Portrait&quot;</span> <span class="attr">Orientation</span><span class="kwrd">=&quot;Portrait&quot;</span></pre>

  <pre><span class="lnum">  14:  </span>    <span class="attr">shell:SystemTray</span>.<span class="attr">IsVisible</span><span class="kwrd">=&quot;True&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  15:  </span>&#160;</pre>

  <pre><span class="lnum">  16:  </span>    <span class="rem">&lt;!--LayoutRoot is the root grid where all page content is placed--&gt;</span></pre>

  <pre class="alt"><span class="lnum">  17:  </span>    <span class="kwrd">&lt;</span><span class="html">Grid</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;LayoutRoot&quot;</span> <span class="attr">Background</span><span class="kwrd">=&quot;Transparent&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  18:  </span>        <span class="kwrd">&lt;</span><span class="html">Grid.RowDefinitions</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  19:  </span>            <span class="kwrd">&lt;</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">=&quot;Auto&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  20:  </span>            <span class="kwrd">&lt;</span><span class="html">RowDefinition</span> <span class="attr">Height</span><span class="kwrd">=&quot;*&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre class="alt"><span class="lnum">  21:  </span>        <span class="kwrd">&lt;/</span><span class="html">Grid.RowDefinitions</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  22:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  23:  </span>        <span class="rem">&lt;!--TitlePanel contains the name of the application and page title--&gt;</span></pre>

  <pre><span class="lnum">  24:  </span>        <span class="kwrd">&lt;</span><span class="html">StackPanel</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;TitlePanel&quot;</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">=&quot;0&quot;</span> <span class="attr">Margin</span><span class="kwrd">=&quot;12,17,0,28&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  25:  </span>            <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">=&quot;robchblogsamples&quot;</span> <span class="attr">Style</span><span class="kwrd">=&quot;{StaticResource PhoneTextNormalStyle}&quot;</span> <span class="attr">Margin</span><span class="kwrd">=&quot;12,0&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  26:  </span>        <span class="kwrd">&lt;/</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  27:  </span>        <span class="kwrd">&lt;</span><span class="html">ScrollViewer</span> <span class="attr">Grid</span>.<span class="attr">Row</span><span class="kwrd">=&quot;1&quot;</span> <span class="attr">Margin</span><span class="kwrd">=&quot;12,0,12,0&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  28:  </span>            <span class="kwrd">&lt;</span><span class="html">StackPanel</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;ContentPanel&quot;</span> <span class="attr">Width</span><span class="kwrd">=&quot;456&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  29:  </span>                <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">=&quot;Enter some text below and click Save to insert a new SiteToSearchItem into your database&quot;</span> <span class="attr">TextWrapping</span><span class="kwrd">=&quot;Wrap&quot;</span> <span class="attr">Margin</span><span class="kwrd">=&quot;12,0&quot;</span> <span class="attr">Height</span><span class="kwrd">=&quot;54&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  30:  </span>                <span class="kwrd">&lt;</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  31:  </span>                    <span class="kwrd">&lt;</span><span class="html">StackPanel</span> <span class="attr">Orientation</span><span class="kwrd">=&quot;Horizontal&quot;</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">=&quot;Right&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  32:  </span>                        <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">TextWrapping</span><span class="kwrd">=&quot;Wrap&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;Site Name:&quot;</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">=&quot;Center&quot;</span> <span class="attr">VerticalAlignment</span><span class="kwrd">=&quot;Center&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;21.333&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre class="alt"><span class="lnum">  33:  </span>                        <span class="kwrd">&lt;</span><span class="html">TextBox</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;_textboxSiteName&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;&quot;</span> <span class="attr">Width</span><span class="kwrd">=&quot;300&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  34:  </span>                    <span class="kwrd">&lt;/</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  35:  </span>                    <span class="kwrd">&lt;</span><span class="html">StackPanel</span> <span class="attr">Orientation</span><span class="kwrd">=&quot;Horizontal&quot;</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">=&quot;Right&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  36:  </span>                        <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">TextWrapping</span><span class="kwrd">=&quot;Wrap&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;Language:&quot;</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">=&quot;Center&quot;</span> <span class="attr">VerticalAlignment</span><span class="kwrd">=&quot;Center&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;21.333&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre class="alt"><span class="lnum">  37:  </span>                        <span class="kwrd">&lt;</span><span class="html">TextBox</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;_textboxLanguage&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;&quot;</span> <span class="attr">Width</span><span class="kwrd">=&quot;300&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  38:  </span>                    <span class="kwrd">&lt;/</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  39:  </span>                    <span class="kwrd">&lt;</span><span class="html">StackPanel</span> <span class="attr">Orientation</span><span class="kwrd">=&quot;Horizontal&quot;</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">=&quot;Right&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  40:  </span>                        <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">TextWrapping</span><span class="kwrd">=&quot;Wrap&quot;</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">=&quot;Center&quot;</span> <span class="attr">VerticalAlignment</span><span class="kwrd">=&quot;Center&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;21.333&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;Domain:&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre class="alt"><span class="lnum">  41:  </span>                        <span class="kwrd">&lt;</span><span class="html">TextBox</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;_textblockDomain&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;&quot;</span> <span class="attr">Width</span><span class="kwrd">=&quot;300&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  42:  </span>                    <span class="kwrd">&lt;/</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  43:  </span>                    <span class="kwrd">&lt;</span><span class="html">StackPanel</span> <span class="attr">Orientation</span><span class="kwrd">=&quot;Horizontal&quot;</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">=&quot;Right&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  44:  </span>                        <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">TextWrapping</span><span class="kwrd">=&quot;Wrap&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;Url Template:&quot;</span> <span class="attr">HorizontalAlignment</span><span class="kwrd">=&quot;Center&quot;</span> <span class="attr">VerticalAlignment</span><span class="kwrd">=&quot;Center&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;21.333&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre class="alt"><span class="lnum">  45:  </span>                        <span class="kwrd">&lt;</span><span class="html">TextBox</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;_textboxUrlTemplate&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;&quot;</span> <span class="attr">Width</span><span class="kwrd">=&quot;300&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  46:  </span>                    <span class="kwrd">&lt;/</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  47:  </span>                <span class="kwrd">&lt;/</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  48:  </span>                <span class="kwrd">&lt;</span><span class="html">Button</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;ButtonSave&quot;</span> <span class="attr">Click</span><span class="kwrd">=&quot;ButtonSave_Click&quot;</span> <span class="attr">Content</span><span class="kwrd">=&quot;Save&quot;</span> <span class="attr">Margin</span><span class="kwrd">=&quot;0&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre class="alt"><span class="lnum">  49:  </span>                <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">Text</span><span class="kwrd">=&quot;Click refresh below to load the unfinished TodoItems from your database. Use the checkbox to complete and update your TodoItems&quot;</span> <span class="attr">TextWrapping</span><span class="kwrd">=&quot;Wrap&quot;</span> <span class="attr">Margin</span><span class="kwrd">=&quot;12,36,12,0&quot;</span> <span class="attr">Height</span><span class="kwrd">=&quot;107&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  50:  </span>                <span class="kwrd">&lt;</span><span class="html">Button</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;ButtonRefresh&quot;</span> <span class="attr">Click</span><span class="kwrd">=&quot;ButtonRefresh_Click&quot;</span> <span class="attr">Content</span><span class="kwrd">=&quot;Refresh&quot;</span> <span class="attr">Height</span><span class="kwrd">=&quot;72&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre class="alt"><span class="lnum">  51:  </span>                <span class="kwrd">&lt;</span><span class="html">phone:LongListSelector</span> <span class="attr">x:Name</span><span class="kwrd">=&quot;ListItems&quot;</span> <span class="attr">Height</span><span class="kwrd">=&quot;400&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  52:  </span>                    <span class="kwrd">&lt;</span><span class="html">phone:LongListSelector.ItemTemplate</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  53:  </span>                        <span class="kwrd">&lt;</span><span class="html">DataTemplate</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  54:  </span>                            <span class="kwrd">&lt;</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  55:  </span>                                <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">TextWrapping</span><span class="kwrd">=&quot;Wrap&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;{Binding SiteName, FallbackValue=[SiteName]}&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;32&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  56:  </span>                                <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">TextWrapping</span><span class="kwrd">=&quot;Wrap&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;{Binding Language, FallbackValue=[Language]}&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;16&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre class="alt"><span class="lnum">  57:  </span>                                <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">TextWrapping</span><span class="kwrd">=&quot;Wrap&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;{Binding Domain, FallbackValue=[Domain]}&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;16&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  58:  </span>                                <span class="kwrd">&lt;</span><span class="html">TextBlock</span> <span class="attr">TextWrapping</span><span class="kwrd">=&quot;Wrap&quot;</span> <span class="attr">Text</span><span class="kwrd">=&quot;{Binding SearchUrlTemplate, FallbackValue=[SearchUrlTemplate]}&quot;</span> <span class="attr">FontSize</span><span class="kwrd">=&quot;16&quot;</span><span class="kwrd">/&gt;</span></pre>

  <pre class="alt"><span class="lnum">  59:  </span>                            <span class="kwrd">&lt;/</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  60:  </span>                        <span class="kwrd">&lt;/</span><span class="html">DataTemplate</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  61:  </span>                    <span class="kwrd">&lt;/</span><span class="html">phone:LongListSelector.ItemTemplate</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  62:  </span>                <span class="kwrd">&lt;/</span><span class="html">phone:LongListSelector</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  63:  </span>            <span class="kwrd">&lt;/</span><span class="html">StackPanel</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  64:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  65:  </span>        <span class="kwrd">&lt;/</span><span class="html">ScrollViewer</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  66:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  67:  </span>        <span class="rem">&lt;!--ContentPanel - place additional content here--&gt;</span></pre>

  <pre><span class="lnum">  68:  </span>    <span class="kwrd">&lt;/</span><span class="html">Grid</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  69:  </span><span class="kwrd">&lt;/</span><span class="html">phone:PhoneApplicationPage</span><span class="kwrd">&gt;</span></pre>
</div>

<p>&#160;</p>

<h2>Add some sites</h2>

<p>Press F5, and add some sites. :-)</p>

<p>Remember … It’s a very simplistic “Admin UI”… For example, there is no delete. If you need to delete something, you can either:</p>

<ul>
  <li>Add that feature yourself, or</li>

  <li>Use the Azure Portal to delete your SiteToSearchItem table, re-add the table, and then re-add the sites from our “Admin UI”</li>
</ul>

<p>&#160;</p>

<h1>The “Other” part…</h1>

<p>OK. Got that Azure part all done … </p>

<p>Back to our “Search On” application... </p>

<p>Now it’s time to pull the data down from Azure, in our new GetPhrasesForUpdatedSiteToSearchPhraseListFromAzure method. Basically, this method delegates to another method, called GetItemsFromAzureMobileService, to download the list of “SiteToSearchItem” entries. Once we have our list of sites in a structured class, we’ll use LINQ to populate a List of strings for our phrase list, by adding all the Site Name’s (e.g. “Bing”) via the “SiteName” property from all the “SiteToSearchItem” items in the list of items from Azure.</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> List&lt;<span class="kwrd">string</span>&gt; GetPhrasesForUpdatedSiteToSearchPhraseListFromAzure(<span class="kwrd">string</span> language)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    List&lt;SiteToSearchItem&gt; itemsFromAzure =</pre>

  <pre><span class="lnum">   4:  </span>        GetItemsFromAzureMobileService&lt;SiteToSearchItem&gt;(</pre>

  <pre class="alt"><span class="lnum">   5:  </span>            <span class="kwrd">string</span>.Format(_siteToSearchAzureMobileServicesTableUrlTemplate, language),</pre>

  <pre><span class="lnum">   6:  </span>            _downloadTimeout);</pre>

  <pre class="alt"><span class="lnum">   7:  </span>&#160;</pre>

  <pre><span class="lnum">   8:  </span>    List&lt;<span class="kwrd">string</span>&gt; phrasesFromAzure = <span class="kwrd">new</span> List&lt;<span class="kwrd">string</span>&gt;(</pre>

  <pre class="alt"><span class="lnum">   9:  </span>        from item <span class="kwrd">in</span> itemsFromAzure</pre>

  <pre><span class="lnum">  10:  </span>        select item.SiteName);</pre>

  <pre class="alt"><span class="lnum">  11:  </span>&#160;</pre>

  <pre><span class="lnum">  12:  </span>    <span class="kwrd">return</span> phrasesFromAzure;</pre>

  <pre class="alt"><span class="lnum">  13:  </span>}</pre>
</div>

<p>Here’s what our SiteToSearchItem looks like:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">class</span> SiteToSearchItem</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">public</span> <span class="kwrd">int</span> Id { get; set; }</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">public</span> <span class="kwrd">string</span> Domain { get; set; }</pre>

  <pre><span class="lnum">   6:  </span>    <span class="kwrd">public</span> <span class="kwrd">string</span> SiteName { get; set; }</pre>

  <pre class="alt"><span class="lnum">   7:  </span>&#160;</pre>

  <pre><span class="lnum">   8:  </span>    <span class="kwrd">public</span> <span class="kwrd">string</span> SearchUrlTemplate { get; set; }</pre>

  <pre class="alt"><span class="lnum">   9:  </span>&#160;</pre>

  <pre><span class="lnum">  10:  </span>    <span class="kwrd">public</span> <span class="kwrd">string</span> Language { get; set; }</pre>

  <pre class="alt"><span class="lnum">  11:  </span>}</pre>
</div>

<p>Now, since we have a data structure to keep our sites in, instead of a dictionary of strings, let’s use that for our built-in list of sites to search:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> List&lt;SiteToSearchItem&gt; _sitesToSearchBuiltInList = <span class="kwrd">new</span> List&lt;SiteToSearchItem&gt;()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">   4:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">   5:  </span>            SiteName = <span class="str">&quot;Amazon&quot;</span>, </pre>

  <pre><span class="lnum">   6:  </span>            Domain = <span class="str">&quot;www.amazon.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">   7:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.amazon.com/gp/aw/s/ref=is_box_?k={0}&quot;</span> } },</pre>

  <pre><span class="lnum">   8:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  10:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  11:  </span>            SiteName = <span class="str">&quot;Bing&quot;</span>, </pre>

  <pre><span class="lnum">  12:  </span>            Domain = <span class="str">&quot;www.bing.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  13:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.bing.com/?q={0}&quot;</span> } },</pre>

  <pre><span class="lnum">  14:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  15:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  16:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  17:  </span>            SiteName = <span class="str">&quot;CNN&quot;</span>, </pre>

  <pre><span class="lnum">  18:  </span>            Domain = <span class="str">&quot;www.CNN.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  19:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.cnn.com/search/?query={0}&quot;</span> } },</pre>

  <pre><span class="lnum">  20:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  21:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  22:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  23:  </span>            SiteName = <span class="str">&quot;zzzz&quot;</span>, </pre>

  <pre><span class="lnum">  24:  </span>            Domain = <span class="str">&quot;www.zzzz.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  25:  </span>            SearchUrlTemplate = <span class="str">&quot;zzzz&quot;</span> } },</pre>

  <pre><span class="lnum">  26:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  27:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  28:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  29:  </span>            SiteName = <span class="str">&quot;Dictionary.com&quot;</span>, </pre>

  <pre><span class="lnum">  30:  </span>            Domain = <span class="str">&quot;www.dictionary.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  31:  </span>            SearchUrlTemplate = <span class="str">&quot;http://dictionary.reference.com/browse/{0}&quot;</span> } },</pre>

  <pre><span class="lnum">  32:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  33:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  34:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  35:  </span>            SiteName = <span class="str">&quot;Ebay&quot;</span>, </pre>

  <pre><span class="lnum">  36:  </span>            Domain = <span class="str">&quot;www.ebay.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  37:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.ebay.com/sch/i.html?_nkw={0}&quot;</span> } }, </pre>

  <pre><span class="lnum">  38:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  39:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  40:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  41:  </span>            SiteName = <span class="str">&quot;Facebook&quot;</span>, </pre>

  <pre><span class="lnum">  42:  </span>            Domain = <span class="str">&quot;www.facebook.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  43:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.facebook.com/search/results.php?q={0}&quot;</span> } },</pre>

  <pre><span class="lnum">  44:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  45:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  46:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  47:  </span>            SiteName = <span class="str">&quot;Google&quot;</span>, </pre>

  <pre><span class="lnum">  48:  </span>            Domain = <span class="str">&quot;www.google.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  49:  </span>            SearchUrlTemplate = <span class="str">&quot;https://www.google.com/search?hl=en&amp;q={0}&quot;</span> } },</pre>

  <pre><span class="lnum">  50:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  51:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  52:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  53:  </span>            SiteName = <span class="str">&quot;Hulu&quot;</span>, </pre>

  <pre><span class="lnum">  54:  </span>            Domain = <span class="str">&quot;www.hulu.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  55:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.hulu.com/#!search?q={0}&quot;</span> } },</pre>

  <pre><span class="lnum">  56:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  57:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  58:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  59:  </span>            SiteName = <span class="str">&quot;IMDB&quot;</span>, </pre>

  <pre><span class="lnum">  60:  </span>            Domain = <span class="str">&quot;www.imdb.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  61:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.imdb.com/find?s=all&amp;q={0}&quot;</span> } },</pre>

  <pre><span class="lnum">  62:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  63:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  64:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  65:  </span>            SiteName = <span class="str">&quot;Linked In&quot;</span>, </pre>

  <pre><span class="lnum">  66:  </span>            Domain = <span class="str">&quot;www.linkedin.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  67:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.linkedin.com/search/fpsearch?keywords={0}&quot;</span> } },</pre>

  <pre><span class="lnum">  68:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  69:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  70:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  71:  </span>            SiteName = <span class="str">&quot;MSN&quot;</span>, </pre>

  <pre><span class="lnum">  72:  </span>            Domain = <span class="str">&quot;www.msn.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  73:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.bing.com/search?scope=msn&amp;q={0}&quot;</span> } },</pre>

  <pre><span class="lnum">  74:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  75:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  76:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  77:  </span>            SiteName = <span class="str">&quot;Twitter&quot;</span>, </pre>

  <pre><span class="lnum">  78:  </span>            Domain = <span class="str">&quot;www.twitter.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  79:  </span>            SearchUrlTemplate = <span class="str">&quot;https://twitter.com/search/{0}&quot;</span> } },</pre>

  <pre><span class="lnum">  80:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  81:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  82:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  83:  </span>            SiteName = <span class="str">&quot;Weather.com&quot;</span>, </pre>

  <pre><span class="lnum">  84:  </span>            Domain = <span class="str">&quot;www.weather.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  85:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.weather.com/info/sitesearch?q={0}&quot;</span> } },</pre>

  <pre><span class="lnum">  86:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  87:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  88:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  89:  </span>            SiteName = <span class="str">&quot;You Tube&quot;</span>, </pre>

  <pre><span class="lnum">  90:  </span>            Domain = <span class="str">&quot;www.youtube.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  91:  </span>            SearchUrlTemplate = <span class="str">&quot;https://www.youtube.com/results?search_query={0}&quot;</span> } },</pre>

  <pre><span class="lnum">  92:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  93:  </span>    { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre><span class="lnum">  94:  </span>        {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre class="alt"><span class="lnum">  95:  </span>            SiteName = <span class="str">&quot;Zillow&quot;</span>, </pre>

  <pre><span class="lnum">  96:  </span>            Domain = <span class="str">&quot;www.zillow.com&quot;</span>, </pre>

  <pre class="alt"><span class="lnum">  97:  </span>            SearchUrlTemplate = <span class="str">&quot;http://www.zillow.com/homes/{0}/&quot;</span> } }</pre>

  <pre><span class="lnum">  98:  </span>};</pre>
</div>

<p>Similar to the GetPhrasesForUpdatedSiteToSearchPhraseListFromAzure method, we’ll use the same LINQ technique to populate our list of phrases for the built-in sites, that we’ve just defined.</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> List&lt;<span class="kwrd">string</span>&gt; GetPhrasesForUpdatedSiteToSearchPhraseListFromBuiltInList()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">return</span> <span class="kwrd">new</span> List&lt;<span class="kwrd">string</span>&gt;(</pre>

  <pre><span class="lnum">   4:  </span>        from item <span class="kwrd">in</span> _sitesToSearchBuiltInList</pre>

  <pre class="alt"><span class="lnum">   5:  </span>        select item.SiteName);</pre>

  <pre><span class="lnum">   6:  </span>}</pre>
</div>

<p>On to the GetItemsFromAzureMobileService method… </p>

<p>There are several ways we can do this. For example, we could use the Azure Mobile Services client library, just like the To Do List (which we turned into our fancy Admin UI app). Or … we could use the REST end points that expose all the data in our tables as an OData end point.</p>

<p>Let’s use the REST-ful approach. I picked this method, because you might not end up using Azure Mobile Services, and you can get more out of copying this code if you go another route. You could download your data from anywhere you can host a JSON list.</p>

<p>Just download the data from the endpoint and convert it to a List of SiteToSearchItem instances.</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> List&lt;T&gt; GetItemsFromAzureMobileService&lt;T&gt;(<span class="kwrd">string</span> url, <span class="kwrd">int</span> downloadTimeout)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">string</span> json = DownloadString(url, downloadTimeout);</pre>

  <pre><span class="lnum">   4:  </span>    List&lt;T&gt; itemsFromJson = FromJSON&lt;List&lt;T&gt;&gt;(json != <span class="kwrd">null</span> ? json : <span class="str">&quot;[]&quot;</span>);</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">return</span> itemsFromJson;</pre>

  <pre><span class="lnum">   6:  </span>}</pre>
</div>

<p>Now, let’s add the two new functions that’ll make that work, DownloadString, and FromJSON:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> DownloadString(<span class="kwrd">string</span> uri, <span class="kwrd">int</span> timeoutInMilliseconds)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">string</span> result = <span class="kwrd">null</span>;</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    ManualResetEvent webrequestCompleted = <span class="kwrd">new</span> ManualResetEvent(<span class="kwrd">false</span>);</pre>

  <pre><span class="lnum">   6:  </span>    AsyncCallback ac = <span class="kwrd">new</span> AsyncCallback((IAsyncResult iar) =&gt;</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    {</pre>

  <pre><span class="lnum">   8:  </span>        <span class="kwrd">try</span></pre>

  <pre class="alt"><span class="lnum">   9:  </span>        {</pre>

  <pre><span class="lnum">  10:  </span>            HttpWebRequest request = (HttpWebRequest)iar.AsyncState;</pre>

  <pre class="alt"><span class="lnum">  11:  </span>            HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(iar);</pre>

  <pre><span class="lnum">  12:  </span>            <span class="kwrd">using</span> (StreamReader sr = <span class="kwrd">new</span> StreamReader(response.GetResponseStream()))</pre>

  <pre class="alt"><span class="lnum">  13:  </span>            {</pre>

  <pre><span class="lnum">  14:  </span>                result = sr.ReadToEnd();</pre>

  <pre class="alt"><span class="lnum">  15:  </span>            }</pre>

  <pre><span class="lnum">  16:  </span>            response.Close();</pre>

  <pre class="alt"><span class="lnum">  17:  </span>        }</pre>

  <pre><span class="lnum">  18:  </span>        <span class="kwrd">catch</span> (Exception)</pre>

  <pre class="alt"><span class="lnum">  19:  </span>        {</pre>

  <pre><span class="lnum">  20:  </span>        }</pre>

  <pre class="alt"><span class="lnum">  21:  </span>        <span class="kwrd">finally</span></pre>

  <pre><span class="lnum">  22:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  23:  </span>            webrequestCompleted.Set();</pre>

  <pre><span class="lnum">  24:  </span>        }</pre>

  <pre class="alt"><span class="lnum">  25:  </span>    });</pre>

  <pre><span class="lnum">  26:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  27:  </span>    HttpWebRequest webrequest = (HttpWebRequest)HttpWebRequest.Create(<span class="kwrd">new</span> Uri(uri));</pre>

  <pre><span class="lnum">  28:  </span>    IAsyncResult ar = webrequest.BeginGetResponse(ac, webrequest);</pre>

  <pre class="alt"><span class="lnum">  29:  </span>    <span class="kwrd">if</span> (ar.CompletedSynchronously)</pre>

  <pre><span class="lnum">  30:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  31:  </span>        ac.Invoke(ar);</pre>

  <pre><span class="lnum">  32:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  33:  </span>&#160;</pre>

  <pre><span class="lnum">  34:  </span>    <span class="kwrd">if</span> (webrequestCompleted.WaitOne(timeoutInMilliseconds))</pre>

  <pre class="alt"><span class="lnum">  35:  </span>    {</pre>

  <pre><span class="lnum">  36:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  37:  </span>&#160;</pre>

  <pre><span class="lnum">  38:  </span>    <span class="kwrd">return</span> result;</pre>

  <pre class="alt"><span class="lnum">  39:  </span>}</pre>

  <pre><span class="lnum">  40:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  41:  </span><span class="kwrd">private</span> <span class="kwrd">static</span> T FromJSON&lt;T&gt;(<span class="kwrd">string</span> json)</pre>

  <pre><span class="lnum">  42:  </span>{</pre>

  <pre class="alt"><span class="lnum">  43:  </span>    <span class="kwrd">using</span> (MemoryStream ms = <span class="kwrd">new</span> MemoryStream(Encoding.UTF8.GetBytes(json)))</pre>

  <pre><span class="lnum">  44:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  45:  </span>        DataContractJsonSerializer serializer = <span class="kwrd">new</span> DataContractJsonSerializer(<span class="kwrd">typeof</span>(T));</pre>

  <pre><span class="lnum">  46:  </span>        <span class="kwrd">return</span> (T)serializer.ReadObject(ms);</pre>

  <pre class="alt"><span class="lnum">  47:  </span>    }</pre>

  <pre><span class="lnum">  48:  </span>}</pre>
</div>

<p>Since we’re getting our data from the server, we also have to change how we find the URL template given a site name. Here’s how we’re going to do that now:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForSiteName(<span class="kwrd">string</span> siteName, <span class="kwrd">string</span> language)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">string</span> url;</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">if</span> (<span class="kwrd">null</span> == (url = GetUrlTemplateForSiteNameFromBuiltInList(siteName, language)) &amp;&amp;</pre>

  <pre><span class="lnum">   6:  </span>        <span class="kwrd">null</span> == (url = GetUrlTemplateForSiteNameFromAzure(siteName, language)))</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    {</pre>

  <pre><span class="lnum">   8:  </span>        url = GetUrlTemplateForUnknownSite(siteName);</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    }</pre>

  <pre><span class="lnum">  10:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  11:  </span>    <span class="kwrd">return</span> url;</pre>

  <pre><span class="lnum">  12:  </span>}</pre>

  <pre class="alt"><span class="lnum">  13:  </span>&#160;</pre>

  <pre><span class="lnum">  14:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForSiteNameFromBuiltInList(<span class="kwrd">string</span> siteName, <span class="kwrd">string</span> language)</pre>

  <pre class="alt"><span class="lnum">  15:  </span>{</pre>

  <pre><span class="lnum">  16:  </span>    <span class="kwrd">return</span> GetUrlTemplateForSiteNameFromList(siteName, language, _sitesToSearchBuiltInList);</pre>

  <pre class="alt"><span class="lnum">  17:  </span>}</pre>

  <pre><span class="lnum">  18:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  19:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForSiteNameFromAzure(<span class="kwrd">string</span> siteName, <span class="kwrd">string</span> language)</pre>

  <pre><span class="lnum">  20:  </span>{</pre>

  <pre class="alt"><span class="lnum">  21:  </span>    List&lt;SiteToSearchItem&gt; itemsFromAzure =</pre>

  <pre><span class="lnum">  22:  </span>        GetItemsFromAzureMobileService&lt;SiteToSearchItem&gt;(</pre>

  <pre class="alt"><span class="lnum">  23:  </span>            <span class="kwrd">string</span>.Format(_siteToSearchAzureMobileServicesTableUrlTemplate, language),</pre>

  <pre><span class="lnum">  24:  </span>            _downloadTimeout);</pre>

  <pre class="alt"><span class="lnum">  25:  </span>&#160;</pre>

  <pre><span class="lnum">  26:  </span>    <span class="kwrd">return</span> GetUrlTemplateForSiteNameFromList(siteName, language, itemsFromAzure);</pre>

  <pre class="alt"><span class="lnum">  27:  </span>}</pre>

  <pre><span class="lnum">  28:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  29:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForSiteNameFromList(<span class="kwrd">string</span> siteName, <span class="kwrd">string</span> language, List&lt;SiteToSearchItem&gt; items)</pre>

  <pre><span class="lnum">  30:  </span>{</pre>

  <pre class="alt"><span class="lnum">  31:  </span>    List&lt;SiteToSearchItem&gt; matchingItems = <span class="kwrd">new</span> List&lt;SiteToSearchItem&gt;(</pre>

  <pre><span class="lnum">  32:  </span>        from item <span class="kwrd">in</span> items</pre>

  <pre class="alt"><span class="lnum">  33:  </span>        <span class="kwrd">where</span> item.SiteName.ToLower() == siteName.ToLower() &amp;&amp; item.Language == language</pre>

  <pre><span class="lnum">  34:  </span>        select item);</pre>

  <pre class="alt"><span class="lnum">  35:  </span>&#160;</pre>

  <pre><span class="lnum">  36:  </span>    <span class="kwrd">return</span> matchingItems.Count &gt; 0</pre>

  <pre class="alt"><span class="lnum">  37:  </span>        ? GetUrlTemplateForSiteToSearch(matchingItems.First())</pre>

  <pre><span class="lnum">  38:  </span>        : <span class="kwrd">null</span>;</pre>

  <pre class="alt"><span class="lnum">  39:  </span>}</pre>

  <pre><span class="lnum">  40:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  41:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForSiteToSearch(SiteToSearchItem item)</pre>

  <pre><span class="lnum">  42:  </span>{</pre>

  <pre class="alt"><span class="lnum">  43:  </span>    <span class="kwrd">return</span> <span class="kwrd">string</span>.IsNullOrWhiteSpace(item.SearchUrlTemplate) </pre>

  <pre><span class="lnum">  44:  </span>        ? GetUrlTemplateForUnknownSite(item.Domain)</pre>

  <pre class="alt"><span class="lnum">  45:  </span>        : item.SearchUrlTemplate;</pre>

  <pre><span class="lnum">  46:  </span>}</pre>

  <pre class="alt"><span class="lnum">  47:  </span>&#160;</pre>

  <pre><span class="lnum">  48:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForUnknownSite(<span class="kwrd">string</span> siteName)</pre>

  <pre class="alt"><span class="lnum">  49:  </span>{</pre>

  <pre><span class="lnum">  50:  </span>    <span class="kwrd">return</span> siteName.Length &gt; 4 &amp;&amp; siteName[siteName.Length - 4] != <span class="str">'.'</span></pre>

  <pre class="alt"><span class="lnum">  51:  </span>        ? <span class="kwrd">string</span>.Format(_defaultUrlTemplateForUnknownSites, siteName + <span class="str">&quot;%20{0}&quot;</span>)</pre>

  <pre><span class="lnum">  52:  </span>        : <span class="kwrd">string</span>.Format(_defaultUrlTemplateForUnknownSites, <span class="str">&quot;site:&quot;</span> + siteName + <span class="str">&quot;%20{0}&quot;</span>);</pre>

  <pre class="alt"><span class="lnum">  53:  </span>}</pre>
</div>

<p>As a performance optimization, since getting the URL template actually blocks on a network operation now (to fetch the data from Azure), let’s start that operation prior to letting the user know that we’re about to do the search. Like this (check out lines 8, 10, and 12):</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> async <span class="kwrd">void</span> SearchSiteVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">string</span> siteName, findText;</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">if</span> (<span class="kwrd">null</span> != (siteName = await GetSiteName(queryString)) &amp;&amp;</pre>

  <pre><span class="lnum">   6:  </span>        <span class="kwrd">null</span> != (findText = await GetTextToFindOnSite(queryString, siteName)))</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    {</pre>

  <pre><span class="lnum">   8:  </span>        Task&lt;<span class="kwrd">string</span>&gt; asyncGetUrlTemplate = Task.Run&lt;<span class="kwrd">string</span>&gt;(() =&gt; </pre>

  <pre>                   { <span class="kwrd">return</span> GetUrlTemplateForSiteName(siteName, GetSpeechRecognitionLanguage()); });</pre>

  <pre class="alt"><span class="lnum">   9:  </span>&#160;</pre>

  <pre><span class="lnum">  10:  </span>        await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Searching {0} for {1}&quot;</span>, siteName, findText));</pre>

  <pre class="alt"><span class="lnum">  11:  </span>&#160;</pre>

  <pre><span class="lnum">  12:  </span>        <span class="kwrd">string</span> siteUrlTemplate = await asyncGetUrlTemplate; </pre>

  <pre class="alt"><span class="lnum">  13:  </span>        NavigateToUrl(<span class="kwrd">string</span>.Format(siteUrlTemplate, findText, siteName));</pre>

  <pre><span class="lnum">  14:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  15:  </span>}</pre>
</div>

<p>We’re almost ready to try it out … Almost. Just a few more changes…</p>

<p>Now, you might be wondering, who actually calls UpdatePhraseListsAsync? Great question. Copy this code into place, and you’ll know the answer:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> EnsureInitVoiceCommandsOnBackgroundThread()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    Task.Run(() =&gt; EnsureInitVoiceCommands());</pre>

  <pre><span class="lnum">   4:  </span>}</pre>

  <pre class="alt"><span class="lnum">   5:  </span>&#160;</pre>

  <pre><span class="lnum">   6:  </span><span class="kwrd">private</span> async <span class="kwrd">void</span> EnsureInitVoiceCommands()</pre>

  <pre class="alt"><span class="lnum">   7:  </span>{</pre>

  <pre><span class="lnum">   8:  </span>    await VoiceCommandService.InstallCommandSetsFromFileAsync(<span class="kwrd">new</span> Uri(<span class="str">&quot;ms-appx:///vcd.xml&quot;</span>));</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    await UpdatePhraseListsAsync();</pre>

  <pre><span class="lnum">  10:  </span>}</pre>

  <pre class="alt"><span class="lnum">  11:  </span>&#160;</pre>
</div>

<p>But, didn’t we already install the command sets from the vcd file in the MainPage constructor? Yep, we used to. But now, we’ll be doing that from the HandleNonVoiceCommandInvocation method for now.</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> async <span class="kwrd">void</span> HandleNonVoiceCommandInvocation()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    EnsureInitVoiceCommandsOnBackgroundThread();</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    await Speak(<span class="str">&quot;What site would you like to search?&quot;</span>);</pre>

  <pre><span class="lnum">   6:  </span>    SearchSiteVoiceCommand(<span class="kwrd">new</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt;());</pre>

  <pre class="alt"><span class="lnum">   7:  </span>}</pre>
</div>

<p>That’ll work, because, the first run of the app will go thru this method. Ideally, we’d really do something like this from a Background agent, PeriodTask like implementation, but, we’ll save that for another day.</p>

<p>Now we’re ready to try it out. Go for it. F5!!</p>

<p>Did it work? Put a breakpoint on the UpdatePhraseListsAsync method, and step thru…</p>

<p>Here’s the full listing for Search On…</p>

<p><strong>MainPage.xaml.cs:</strong></p>

<div class="csharpcode">
  <pre class="alt"><span class="kwrd">using</span> System;</pre>

  <pre><span class="kwrd">using</span> System.Collections.Generic;</pre>

  <pre class="alt"><span class="kwrd">using</span> System.Net;</pre>

  <pre><span class="kwrd">using</span> System.Windows;</pre>

  <pre class="alt"><span class="kwrd">using</span> System.Windows.Navigation;</pre>

  <pre><span class="kwrd">using</span> Microsoft.Phone.Controls;</pre>

  <pre class="alt"><span class="kwrd">using</span> Windows.Phone.Speech.VoiceCommands;</pre>

  <pre><span class="kwrd">using</span> Windows.Phone.Speech.Recognition;</pre>

  <pre class="alt"><span class="kwrd">using</span> Windows.Phone.Speech.Synthesis;</pre>

  <pre><span class="kwrd">using</span> System.Threading.Tasks;</pre>

  <pre class="alt"><span class="kwrd">using</span> Microsoft.Phone.Tasks;</pre>

  <pre><span class="kwrd">using</span> System.Text.RegularExpressions;</pre>

  <pre class="alt"><span class="kwrd">using</span> System.Threading;</pre>

  <pre><span class="kwrd">using</span> System.Text;</pre>

  <pre class="alt"><span class="kwrd">using</span> System.Linq;</pre>

  <pre><span class="kwrd">using</span> System.Runtime.Serialization.Json;</pre>

  <pre class="alt"><span class="kwrd">using</span> System.IO;</pre>

  <pre>&#160;</pre>

  <pre class="alt"><span class="kwrd">namespace</span> SearchOn</pre>

  <pre>{</pre>

  <pre class="alt">    <span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> MainPage : PhoneApplicationPage</pre>

  <pre>    {</pre>

  <pre class="alt">        <span class="kwrd">public</span> MainPage()</pre>

  <pre>        {</pre>

  <pre class="alt">            InitializeComponent();</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">base</span>.OnNavigatedTo(e);</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New &amp;&amp; NavigationContext.QueryString.ContainsKey(<span class="str">&quot;voiceCommandName&quot;</span>))</pre>

  <pre class="alt">            {</pre>

  <pre>                HandleVoiceCommand(NavigationContext.QueryString);</pre>

  <pre class="alt">            }</pre>

  <pre>            <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New)</pre>

  <pre class="alt">            {</pre>

  <pre>                HandleNonVoiceCommandInvocation();</pre>

  <pre class="alt">            }</pre>

  <pre>            <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.Back &amp;&amp; !System.Diagnostics.Debugger.IsAttached)</pre>

  <pre class="alt">            {</pre>

  <pre>                NavigationService.GoBack();</pre>

  <pre class="alt">            }</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> async <span class="kwrd">void</span> HandleNonVoiceCommandInvocation()</pre>

  <pre class="alt">        {</pre>

  <pre>            EnsureInitVoiceCommandsOnBackgroundThread();</pre>

  <pre class="alt">&#160;</pre>

  <pre>            await Speak(<span class="str">&quot;What site would you like to search?&quot;</span>);</pre>

  <pre class="alt">            SearchSiteVoiceCommand(<span class="kwrd">new</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt;());</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> <span class="kwrd">void</span> HandleVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">switch</span> (queryString[<span class="str">&quot;voiceCommandName&quot;</span>])</pre>

  <pre class="alt">            {</pre>

  <pre>                <span class="kwrd">case</span> <span class="str">&quot;searchSite&quot;</span>:</pre>

  <pre class="alt">                <span class="kwrd">case</span> <span class="str">&quot;searchSiteCatchAll&quot;</span>:</pre>

  <pre>                    SearchSiteVoiceCommand(queryString);</pre>

  <pre class="alt">                    <span class="kwrd">break</span>;</pre>

  <pre>            }</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> async <span class="kwrd">void</span> SearchSiteVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">string</span> siteName, findText;</pre>

  <pre>&#160;</pre>

  <pre class="alt">            <span class="kwrd">if</span> (<span class="kwrd">null</span> != (siteName = await GetSiteName(queryString)) &amp;&amp;</pre>

  <pre>                <span class="kwrd">null</span> != (findText = await GetTextToFindOnSite(queryString, siteName)))</pre>

  <pre class="alt">            {</pre>

  <pre>                Task&lt;<span class="kwrd">string</span>&gt; asyncGetUrlTemplate = Task.Run&lt;<span class="kwrd">string</span>&gt;(() =&gt; { <span class="kwrd">return</span> GetUrlTemplateForSiteName(siteName, GetSpeechRecognitionLanguage()); });</pre>

  <pre class="alt">&#160;</pre>

  <pre>                await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Searching {0} for {1}&quot;</span>, siteName, findText));</pre>

  <pre class="alt">&#160;</pre>

  <pre>                <span class="kwrd">string</span> siteUrlTemplate = await asyncGetUrlTemplate; </pre>

  <pre class="alt">                NavigateToUrl(<span class="kwrd">string</span>.Format(siteUrlTemplate, findText, siteName));</pre>

  <pre>            }</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; GetSiteName(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">return</span> queryString.ContainsKey(<span class="str">&quot;siteToSearch&quot;</span>)</pre>

  <pre>                ? queryString[<span class="str">&quot;siteToSearch&quot;</span>]</pre>

  <pre class="alt">                : NormalizeDotComSuffixes(</pre>

  <pre>                        await RecognizeTextFromWebSearchGrammar(<span class="str">&quot;Ex. \&quot;msdn blogs\&quot;&quot;</span>));</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; GetTextToFindOnSite(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString, <span class="kwrd">string</span> siteName)</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">if</span> (!queryString.ContainsKey(<span class="str">&quot;siteToSearch&quot;</span>))</pre>

  <pre>            {</pre>

  <pre class="alt">                await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Search {0} for what?&quot;</span>, siteName));</pre>

  <pre>            }</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">return</span> await RecognizeTextFromWebSearchGrammar(<span class="str">&quot;Ex. \&quot;electronics\&quot;&quot;</span>);</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; RecognizeTextFromWebSearchGrammar(<span class="kwrd">string</span> exampleText)</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">string</span> text = <span class="kwrd">null</span>;</pre>

  <pre>            <span class="kwrd">try</span></pre>

  <pre class="alt">            {</pre>

  <pre>                SpeechRecognizerUI sr = <span class="kwrd">new</span> SpeechRecognizerUI();</pre>

  <pre class="alt">                sr.Recognizer.Grammars.AddGrammarFromPredefinedType(<span class="str">&quot;web&quot;</span>, SpeechPredefinedGrammar.WebSearch);</pre>

  <pre>                sr.Settings.ListenText = <span class="str">&quot;Listening...&quot;</span>;</pre>

  <pre class="alt">                sr.Settings.ExampleText = exampleText;</pre>

  <pre>                sr.Settings.ReadoutEnabled = <span class="kwrd">false</span>;</pre>

  <pre class="alt">                sr.Settings.ShowConfirmation = <span class="kwrd">false</span>;</pre>

  <pre>&#160;</pre>

  <pre class="alt">&#160;</pre>

  <pre>                SpeechRecognitionUIResult result = await sr.RecognizeWithUIAsync();</pre>

  <pre class="alt">                <span class="kwrd">if</span> (result != <span class="kwrd">null</span> &amp;&amp; </pre>

  <pre>                    result.ResultStatus == SpeechRecognitionUIStatus.Succeeded &amp;&amp;</pre>

  <pre class="alt">                    result.RecognitionResult != <span class="kwrd">null</span> &amp;&amp;</pre>

  <pre>                    result.RecognitionResult.TextConfidence != SpeechRecognitionConfidence.Rejected)</pre>

  <pre class="alt">                {</pre>

  <pre>                    text = result.RecognitionResult.Text;</pre>

  <pre class="alt">                }</pre>

  <pre>            }</pre>

  <pre class="alt">            <span class="kwrd">catch</span> </pre>

  <pre>            {</pre>

  <pre class="alt">            }</pre>

  <pre>            <span class="kwrd">return</span> text;</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">string</span> GetSpeechRecognitionLanguage()</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">return</span> InstalledSpeechRecognizers.Default.Language.ToLower();</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> async Task Speak(<span class="kwrd">string</span> text)</pre>

  <pre class="alt">        {</pre>

  <pre>            SpeechSynthesizer tts = <span class="kwrd">new</span> SpeechSynthesizer();</pre>

  <pre class="alt">            await tts.SpeakTextAsync(text);</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> <span class="kwrd">void</span> NavigateToUrl(<span class="kwrd">string</span> url)</pre>

  <pre class="alt">        {</pre>

  <pre>            WebBrowserTask task = <span class="kwrd">new</span> WebBrowserTask();</pre>

  <pre class="alt">            task.Uri = <span class="kwrd">new</span> Uri(url, UriKind.Absolute);</pre>

  <pre>            task.Show();</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForSiteName(<span class="kwrd">string</span> siteName, <span class="kwrd">string</span> language)</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">string</span> url;</pre>

  <pre>&#160;</pre>

  <pre class="alt">            <span class="kwrd">if</span> (<span class="kwrd">null</span> == (url = GetUrlTemplateForSiteNameFromBuiltInList(siteName, language)) &amp;&amp;</pre>

  <pre>                <span class="kwrd">null</span> == (url = GetUrlTemplateForSiteNameFromAzure(siteName, language)))</pre>

  <pre class="alt">            {</pre>

  <pre>                url = GetUrlTemplateForUnknownSite(siteName);</pre>

  <pre class="alt">            }</pre>

  <pre>&#160;</pre>

  <pre class="alt">            <span class="kwrd">return</span> url;</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForSiteNameFromBuiltInList(<span class="kwrd">string</span> siteName, <span class="kwrd">string</span> language)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">return</span> GetUrlTemplateForSiteNameFromList(siteName, language, _sitesToSearchBuiltInList);</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForSiteNameFromAzure(<span class="kwrd">string</span> siteName, <span class="kwrd">string</span> language)</pre>

  <pre>        {</pre>

  <pre class="alt">            List&lt;SiteToSearchItem&gt; itemsFromAzure =</pre>

  <pre>                GetItemsFromAzureMobileService&lt;SiteToSearchItem&gt;(</pre>

  <pre class="alt">                    <span class="kwrd">string</span>.Format(_siteToSearchAzureMobileServicesTableUrlTemplate, language),</pre>

  <pre>                    _downloadTimeout);</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">return</span> GetUrlTemplateForSiteNameFromList(siteName, language, itemsFromAzure);</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForSiteNameFromList(<span class="kwrd">string</span> siteName, <span class="kwrd">string</span> language, List&lt;SiteToSearchItem&gt; items)</pre>

  <pre>        {</pre>

  <pre class="alt">            List&lt;SiteToSearchItem&gt; matchingItems = <span class="kwrd">new</span> List&lt;SiteToSearchItem&gt;(</pre>

  <pre>                from item <span class="kwrd">in</span> items</pre>

  <pre class="alt">                <span class="kwrd">where</span> item.SiteName.ToLower() == siteName.ToLower() &amp;&amp; item.Language == language</pre>

  <pre>                select item);</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">return</span> matchingItems.Count &gt; 0</pre>

  <pre class="alt">                ? GetUrlTemplateForSiteToSearch(matchingItems.First())</pre>

  <pre>                : <span class="kwrd">null</span>;</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForSiteToSearch(SiteToSearchItem item)</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">return</span> <span class="kwrd">string</span>.IsNullOrWhiteSpace(item.SearchUrlTemplate) </pre>

  <pre>                ? GetUrlTemplateForUnknownSite(item.Domain)</pre>

  <pre class="alt">                : item.SearchUrlTemplate;</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateForUnknownSite(<span class="kwrd">string</span> siteName)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">return</span> siteName.Length &gt; 4 &amp;&amp; siteName[siteName.Length - 4] != <span class="str">'.'</span></pre>

  <pre class="alt">                ? <span class="kwrd">string</span>.Format(_defaultUrlTemplateForUnknownSites, siteName + <span class="str">&quot;%20{0}&quot;</span>)</pre>

  <pre>                : <span class="kwrd">string</span>.Format(_defaultUrlTemplateForUnknownSites, <span class="str">&quot;site:&quot;</span> + siteName + <span class="str">&quot;%20{0}&quot;</span>);</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">string</span> NormalizeDotComSuffixes(<span class="kwrd">string</span> input)</pre>

  <pre>        {</pre>

  <pre class="alt">            Regex re1 = <span class="kwrd">new</span> Regex(<span class="str">@&quot;\s+dot\s+(?&lt;suffix&gt;(com|net|org|gov))\z&quot;</span>);</pre>

  <pre>            <span class="kwrd">if</span> (input != <span class="kwrd">null</span> &amp;&amp; re1.IsMatch(input))</pre>

  <pre class="alt">            {</pre>

  <pre>                input = re1.Replace(input, <span class="str">@&quot;.${suffix}&quot;</span>).Replace(<span class="str">&quot; &quot;</span>, <span class="str">&quot;&quot;</span>);</pre>

  <pre class="alt">            }</pre>

  <pre>&#160;</pre>

  <pre class="alt">            Regex re2 = <span class="kwrd">new</span> Regex(<span class="str">@&quot;\s+dot\s+(?&lt;l1&gt;[A-Z])[.]\s+(?&lt;l2&gt;[A-Z])[.]\s+(?&lt;l3&gt;[A-Z])[.]\z&quot;</span>);</pre>

  <pre>            <span class="kwrd">if</span> (input != <span class="kwrd">null</span> &amp;&amp; re2.IsMatch(input))</pre>

  <pre class="alt">            {</pre>

  <pre>                input = re2.Replace(input, <span class="str">@&quot;.${l1}${l2}${l3}&quot;</span>).Replace(<span class="str">&quot; &quot;</span>, <span class="str">&quot;&quot;</span>);</pre>

  <pre class="alt">                input = input.Substring(0, input.Length - 4) + input.Substring(input.Length - 4).ToLower();</pre>

  <pre>            }</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">return</span> input;</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">void</span> EnsureInitVoiceCommandsOnBackgroundThread()</pre>

  <pre>        {</pre>

  <pre class="alt">            Task.Run(() =&gt; EnsureInitVoiceCommands());</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> async <span class="kwrd">void</span> EnsureInitVoiceCommands()</pre>

  <pre class="alt">        {</pre>

  <pre>            await VoiceCommandService.InstallCommandSetsFromFileAsync(<span class="kwrd">new</span> Uri(<span class="str">&quot;ms-appx:///vcd.xml&quot;</span>));</pre>

  <pre class="alt">            await UpdatePhraseListsAsync();</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> async Task UpdatePhraseListsAsync()</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">foreach</span> (VoiceCommandSet cs <span class="kwrd">in</span> VoiceCommandService.InstalledCommandSets.Values)</pre>

  <pre class="alt">            {</pre>

  <pre>                List&lt;<span class="kwrd">string</span>&gt; updatedListOfPhrases = GetPhrasesForUpdatedSiteToSearchPhraseList(cs.Language.ToLower());</pre>

  <pre class="alt">                await cs.UpdatePhraseListAsync(<span class="str">&quot;siteToSearch&quot;</span>, updatedListOfPhrases);</pre>

  <pre>            }</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> List&lt;<span class="kwrd">string</span>&gt; GetPhrasesForUpdatedSiteToSearchPhraseList(<span class="kwrd">string</span> language)</pre>

  <pre>        {</pre>

  <pre class="alt">            List&lt;<span class="kwrd">string</span>&gt; phrasesBuiltIn = GetPhrasesForUpdatedSiteToSearchPhraseListFromBuiltInList();</pre>

  <pre>            List&lt;<span class="kwrd">string</span>&gt; phrasesFromAzure = GetPhrasesForUpdatedSiteToSearchPhraseListFromAzure(language);</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">return</span> phrasesFromAzure.Union(phrasesBuiltIn).ToList();</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> List&lt;<span class="kwrd">string</span>&gt; GetPhrasesForUpdatedSiteToSearchPhraseListFromBuiltInList()</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">return</span> <span class="kwrd">new</span> List&lt;<span class="kwrd">string</span>&gt;(</pre>

  <pre>                from item <span class="kwrd">in</span> _sitesToSearchBuiltInList</pre>

  <pre class="alt">                select item.SiteName);</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> List&lt;<span class="kwrd">string</span>&gt; GetPhrasesForUpdatedSiteToSearchPhraseListFromAzure(<span class="kwrd">string</span> language)</pre>

  <pre class="alt">        {</pre>

  <pre>            List&lt;SiteToSearchItem&gt; itemsFromAzure =</pre>

  <pre class="alt">                GetItemsFromAzureMobileService&lt;SiteToSearchItem&gt;(</pre>

  <pre>                    <span class="kwrd">string</span>.Format(_siteToSearchAzureMobileServicesTableUrlTemplate, language),</pre>

  <pre class="alt">                    _downloadTimeout);</pre>

  <pre>&#160;</pre>

  <pre class="alt">            List&lt;<span class="kwrd">string</span>&gt; phrasesFromAzure = <span class="kwrd">new</span> List&lt;<span class="kwrd">string</span>&gt;(</pre>

  <pre>                from item <span class="kwrd">in</span> itemsFromAzure</pre>

  <pre class="alt">                select item.SiteName);</pre>

  <pre>&#160;</pre>

  <pre class="alt">            <span class="kwrd">return</span> phrasesFromAzure;</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> List&lt;T&gt; GetItemsFromAzureMobileService&lt;T&gt;(<span class="kwrd">string</span> url, <span class="kwrd">int</span> downloadTimeout)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">string</span> json = DownloadString(url, downloadTimeout);</pre>

  <pre class="alt">            List&lt;T&gt; itemsFromJson = FromJSON&lt;List&lt;T&gt;&gt;(json != <span class="kwrd">null</span> ? json : <span class="str">&quot;[]&quot;</span>);</pre>

  <pre>            <span class="kwrd">return</span> itemsFromJson;</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">string</span> DownloadString(<span class="kwrd">string</span> uri, <span class="kwrd">int</span> timeoutInMilliseconds)</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">string</span> result = <span class="kwrd">null</span>;</pre>

  <pre>&#160;</pre>

  <pre class="alt">            ManualResetEvent webrequestCompleted = <span class="kwrd">new</span> ManualResetEvent(<span class="kwrd">false</span>);</pre>

  <pre>            AsyncCallback ac = <span class="kwrd">new</span> AsyncCallback((IAsyncResult iar) =&gt;</pre>

  <pre class="alt">            {</pre>

  <pre>                <span class="kwrd">try</span></pre>

  <pre class="alt">                {</pre>

  <pre>                    HttpWebRequest request = (HttpWebRequest)iar.AsyncState;</pre>

  <pre class="alt">                    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(iar);</pre>

  <pre>                    <span class="kwrd">using</span> (StreamReader sr = <span class="kwrd">new</span> StreamReader(response.GetResponseStream()))</pre>

  <pre class="alt">                    {</pre>

  <pre>                        result = sr.ReadToEnd();</pre>

  <pre class="alt">                    }</pre>

  <pre>                    response.Close();</pre>

  <pre class="alt">                }</pre>

  <pre>                <span class="kwrd">catch</span> (Exception)</pre>

  <pre class="alt">                {</pre>

  <pre>                }</pre>

  <pre class="alt">                <span class="kwrd">finally</span></pre>

  <pre>                {</pre>

  <pre class="alt">                    webrequestCompleted.Set();</pre>

  <pre>                }</pre>

  <pre class="alt">            });</pre>

  <pre>&#160;</pre>

  <pre class="alt">            HttpWebRequest webrequest = (HttpWebRequest)HttpWebRequest.Create(<span class="kwrd">new</span> Uri(uri));</pre>

  <pre>            IAsyncResult ar = webrequest.BeginGetResponse(ac, webrequest);</pre>

  <pre class="alt">            <span class="kwrd">if</span> (ar.CompletedSynchronously)</pre>

  <pre>            {</pre>

  <pre class="alt">                ac.Invoke(ar);</pre>

  <pre>            }</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">if</span> (webrequestCompleted.WaitOne(timeoutInMilliseconds))</pre>

  <pre class="alt">            {</pre>

  <pre>            }</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">return</span> result;</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">static</span> T FromJSON&lt;T&gt;(<span class="kwrd">string</span> json)</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">using</span> (MemoryStream ms = <span class="kwrd">new</span> MemoryStream(Encoding.UTF8.GetBytes(json)))</pre>

  <pre>            {</pre>

  <pre class="alt">                DataContractJsonSerializer serializer = <span class="kwrd">new</span> DataContractJsonSerializer(<span class="kwrd">typeof</span>(T));</pre>

  <pre>                <span class="kwrd">return</span> (T)serializer.ReadObject(ms);</pre>

  <pre class="alt">            }</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="preproc">#region</span> <span class="kwrd">private</span> data</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> <span class="kwrd">string</span> _defaultUrlTemplateForUnknownSites = <span class="str">&quot;http://m.bing.com/search?q={0}&quot;</span>;</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> List&lt;SiteToSearchItem&gt; _sitesToSearchBuiltInList = <span class="kwrd">new</span> List&lt;SiteToSearchItem&gt;()</pre>

  <pre class="alt">        {</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Amazon&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.amazon.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.amazon.com/gp/aw/s/ref=is_box_?k={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Bing&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.bing.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.bing.com/?q={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;CNN&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.CNN.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.cnn.com/search/?query={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;zzzz&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.zzzz.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;zzzz&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Dictionary.com&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.dictionary.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://dictionary.reference.com/browse/{0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Ebay&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.ebay.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.ebay.com/sch/i.html?_nkw={0}&quot;</span> } }, </pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Facebook&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.facebook.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.facebook.com/search/results.php?q={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Google&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.google.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;https://www.google.com/search?hl=en&amp;q={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Hulu&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.hulu.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.hulu.com/#!search?q={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;IMDB&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.imdb.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.imdb.com/find?s=all&amp;q={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Linked In&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.linkedin.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.linkedin.com/search/fpsearch?keywords={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;MSN&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.msn.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.bing.com/search?scope=msn&amp;q={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Twitter&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.twitter.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;https://twitter.com/search/{0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Weather.com&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.weather.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.weather.com/info/sitesearch?q={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;You Tube&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.youtube.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;https://www.youtube.com/results?search_query={0}&quot;</span> } },</pre>

  <pre class="alt">&#160;</pre>

  <pre>            { <span class="kwrd">new</span> SiteToSearchItem() </pre>

  <pre class="alt">                {   Language = <span class="str">&quot;en-us&quot;</span>,</pre>

  <pre>                    SiteName = <span class="str">&quot;Zillow&quot;</span>, </pre>

  <pre class="alt">                    Domain = <span class="str">&quot;www.zillow.com&quot;</span>, </pre>

  <pre>                    SearchUrlTemplate = <span class="str">&quot;http://www.zillow.com/homes/{0}/&quot;</span> } }</pre>

  <pre class="alt">        };</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">string</span> _siteToSearchAzureMobileServicesTableUrlTemplate = <span class="str">&quot;https://robchblogsamples.azure-mobile.net/tables/SiteToSearchItem?$filter=Language%20eq%20'{0}'&quot;</span>;</pre>

  <pre>        <span class="kwrd">private</span> <span class="kwrd">int</span> _downloadTimeout = 5000;</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="preproc">#endregion</span></pre>

  <pre class="alt">&#160;</pre>

  <pre>    }</pre>

  <pre class="alt">&#160;</pre>

  <pre>    <span class="kwrd">public</span> <span class="kwrd">class</span> SiteToSearchItem</pre>

  <pre class="alt">    {</pre>

  <pre>        <span class="kwrd">public</span> <span class="kwrd">int</span> Id { get; set; }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">public</span> <span class="kwrd">string</span> Domain { get; set; }</pre>

  <pre class="alt">        <span class="kwrd">public</span> <span class="kwrd">string</span> SiteName { get; set; }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">public</span> <span class="kwrd">string</span> SearchUrlTemplate { get; set; }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">public</span> <span class="kwrd">string</span> Language { get; set; }</pre>

  <pre>    }</pre>

  <pre class="alt">}</pre>
</div>]]></content:encoded>
    </item>
    <item>
      <title>WP8 Voice Commands: Wildcards</title>
      <link>https://docs.microsoft.com/archive/blogs/robch/wp8-voice-commands-wildcards</link>
      <pubDate>Thu, 08 Nov 2012 15:44:58 GMT</pubDate>
      <dc:creator><![CDATA[Rob Chambers]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/robch/2012/11/08/wp8-voice-commands-wildcards/</guid>
      <description><![CDATA[In today’s post, we’re going to dig into a very useful feature of the Windows Phone 8.0 speech...]]></description>
      <content:encoded><![CDATA[<p>In today’s post, we’re going to dig into a very useful feature of the Windows Phone 8.0 speech platform, specifically how to use wildcards with the VoiceCommandService.</p>  <p>As those of you following along already know, in our <a href="http://blogs.msdn.com/b/robch/archive/2012/11/06/how-many-lines-of-code-does-it-take-to-build-a-complete-wp8-speech-app.aspx">first post</a>, we built a WP8 speech app, called “Search On”, enabling users to “Search On Amazon” by voice for anything they wanted. In the <a href="http://blogs.msdn.com/b/robch/archive/2012/11/07/wp8-voice-commands-phrase-lists.aspx">second post</a>, we added the ability to search on 15+ more sites by incorporating a PhraseList of many popular web sites.</p>  <p>Today, we’ll continuing adding to our “Search On” speech app, enabling our users to search any web site at all, even when it’s not one of our built in 15+ sites we know how to search. Specifically, we’ll extend the app to support the following scenarios:</p>  <blockquote>   <p><strong>User: </strong>&quot;Search a web site&quot;       <br /><strong>Phone: </strong>&quot;What web site would you like to search?&quot; </p>    <p><strong>User: </strong>&quot;Whitehouse Dot Gov&quot;       <br /><strong>Phone: </strong>&quot;Search Whitehouse.gov for what?&quot; </p>    <p><strong>User: </strong>&quot;Elections results&quot;      <br /><strong>Phone: </strong>&quot;Searching Whitehouse.gov for Election results”</p> </blockquote>  <p>… and, similarly, if the user doesn’t know if we know about the site name or not … </p>  <blockquote>   <p><strong>User: </strong>&quot;Search Whitehouse Dot Gov&quot;       <br /><strong>Phone: </strong>&quot;What web site would you like to search?&quot; </p>    <p><strong>User: </strong>&quot;Whitehouse Dot Gov&quot;       <br /><strong>Phone: </strong>&quot;Search Whitehouse.gov for what?&quot; </p>    <p><strong>User: </strong>&quot;Elections results&quot;      <br /><strong>Phone: </strong>&quot;Searching Whitehouse.gov for Election results”</p> </blockquote>  <p>In the 2nd example above, it’s better to help the user complete her task, than just beeping at her, or complaining that we don’t know what to do at all. We <em>DO </em>know at least part of the task: She wants to search a web site, but we just didn’t know what the site was she said… </p>  <p>Now, let’s dig in and see how WP8’s VoiceCommandService can help us achieve this…</p>  <p>Let’s start with the Voice Command Definition file, vcd.xml. We’re going to add a new Command, named “searchSiteCatchAll”. We’ll add a few &lt;ListenFor&gt; elements for that Command, that will “capture” all the websites that we don’t know how to search yet. </p>  <div class="csharpcode">   <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">&lt;</span><span class="html">Command</span> <span class="attr">Name</span><span class="kwrd">=&quot;searchSiteCatchAll&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   2:  </span>  <span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>a web site<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>[a] [specific] [web] site<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   4:  </span>  <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{*} <span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{*} {dotComOrNet} <span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   6:  </span>  <span class="kwrd">&lt;</span><span class="html">Feedback</span><span class="kwrd">&gt;</span>What site would you like to search?<span class="kwrd">&lt;/</span><span class="html">Feedback</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   7:  </span>  <span class="kwrd">&lt;</span><span class="html">Navigate</span> <span class="attr">Target</span><span class="kwrd">=&quot;MainPage.xaml&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">   8:  </span><span class="kwrd">&lt;/</span><span class="html">Command</span><span class="kwrd">&gt;</span></pre>
</div>


<p>Remember how we used a PhraseList in yesterday’s post to contain a list of websites? Then, we added “{siteToSearch}&quot; as the content to the &lt;ListenFor&gt; element in the &lt;Command&gt; element? Right? Well, the VoiceCommandService wildcard feature, or garbage rule as it’s sometimes called, is very similar. Instead of referring to a PhraseList by Label, just use an asterisks inside the same squiggly brackets we put around the PhraseList Label. So it’s “{*}” instead of “{siteToSearch}”. </p>

<p>Now, you can see that I also added a &lt;ListenFor&gt; that doesn’t use the wildcard. That will allow the user to say things like, “Search On a website”, or “Search On a specific site”. That way, if the user already knows we don’t know about the site, she can get into the same flow, more deterministically. </p>

<p>OK, now you’ll see that there’s another new PhraseList being referred to here. Named “dotComOrNet”. Let’s add that PhraseList now:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">&lt;</span><span class="html">PhraseList</span> <span class="attr">Label</span><span class="kwrd">=&quot;dotComOrNet&quot;</span> <span class="attr">Disambiguate</span><span class="kwrd">=&quot;false&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   2:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>dot com<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>dot net<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   4:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>dot org<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>dot gov<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   6:  </span><span class="kwrd">&lt;/</span><span class="html">PhraseList</span><span class="kwrd">&gt;</span></pre>
</div>

<p>We use that as the “tail” of the ListenFor to help the recognizer on WP8 to choose our application instead of the built in search experience in WP8. Without this “tail”, due to the fact that our application name is phonetically very similar to a build in command’s verb “Search”, the 1st party experience will get picked more often than we’d expect. I’ll save describing why that is for another day, though (for the very curious it’s because of some internal weighting we’ve done to ensure the built in WP8 speech features can more reliably be accessed, even if/when poorly designed 3rd party applications might be on the phone with phonetically similar voice command phrases). </p>

<p>Also, did you notice the “Disambiguate=”false”” part? What’s that do? Good question … Basically, it tells the VoiceCommandService to not worry about asking the user to pick between the different choices if there’s ever any ambiguity. We don’t really need to know what they said, for our built in items. We’ll take a look at this more closely in a future post. </p>

<p>OK. Now, I’ve also updated the “siteToSearch” command, to also take advantage of this “tail”. Combined with the catch all command, it looks like this:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">&lt;</span><span class="html">Command</span> <span class="attr">Name</span><span class="kwrd">=&quot;searchSiteCatchAll&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   2:  </span>  <span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>a web site<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>[a] [specific] [web] site<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   4:  </span>  <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{*} <span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{*} {dotComOrNet} <span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   6:  </span>  <span class="kwrd">&lt;</span><span class="html">Feedback</span><span class="kwrd">&gt;</span>What site would you like to search?<span class="kwrd">&lt;/</span><span class="html">Feedback</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   7:  </span>  <span class="kwrd">&lt;</span><span class="html">Navigate</span> <span class="attr">Target</span><span class="kwrd">=&quot;MainPage.xaml&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">   8:  </span><span class="kwrd">&lt;/</span><span class="html">Command</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   9:  </span>&#160;</pre>

  <pre><span class="lnum">  10:  </span><span class="kwrd">&lt;</span><span class="html">Command</span> <span class="attr">Name</span><span class="kwrd">=&quot;searchSite&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  11:  </span>  <span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>Amazon, Bing, Facebook, Twitter, ...<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  12:  </span>  <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{siteToSearch} <span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  13:  </span>  <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{siteToSearch} {dotComOrNet}<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  14:  </span>  <span class="kwrd">&lt;</span><span class="html">Feedback</span><span class="kwrd">&gt;</span>Search on {siteToSearch} for what?<span class="kwrd">&lt;/</span><span class="html">Feedback</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  15:  </span>  <span class="kwrd">&lt;</span><span class="html">Navigate</span> <span class="attr">Target</span><span class="kwrd">=&quot;MainPage.xaml&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  16:  </span><span class="kwrd">&lt;/</span><span class="html">Command</span><span class="kwrd">&gt;</span></pre>
</div>

<p>On to the code!</p>

<p>First, let’s look at the HandleVoiceCommand function. </p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> HandleVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">switch</span> (queryString[<span class="str">&quot;voiceCommandName&quot;</span>])</pre>

  <pre><span class="lnum">   4:  </span>    {</pre>

  <pre class="alt"><span class="lnum">   5:  </span>        <span class="kwrd">case</span> <span class="str">&quot;searchSite&quot;</span>:</pre>

  <pre><span class="lnum">   6:  </span>        <span class="kwrd">case</span> <span class="str">&quot;searchSiteCatchAll&quot;</span>:</pre>

  <pre class="alt"><span class="lnum">   7:  </span>            SearchSiteVoiceCommand(queryString);</pre>

  <pre><span class="lnum">   8:  </span>            <span class="kwrd">break</span>;</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    }</pre>

  <pre><span class="lnum">  10:  </span>}</pre>
</div>

<p>Now it’s set up to handle more than one voice command, but for now, it’s going to do the same thing for both searchSite and searchSiteCatchAll commands. For that to work, though, we’ll have to also change the SearchSiteVoiceCommand method to look like this:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> async <span class="kwrd">void</span> SearchSiteVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">string</span> siteName, findText;</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">if</span> (<span class="kwrd">null</span> != (siteName = await GetSiteName(queryString)) &amp;&amp;</pre>

  <pre><span class="lnum">   6:  </span>        <span class="kwrd">null</span> != (findText = await GetTextToFindOnSite(queryString, siteName)))</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    {</pre>

  <pre><span class="lnum">   8:  </span>        await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Searching {0} for {1}&quot;</span>, siteName, findText));</pre>

  <pre class="alt"><span class="lnum">   9:  </span>&#160;</pre>

  <pre><span class="lnum">  10:  </span>        <span class="kwrd">string</span> siteUrlTemplate = GetUrlTemplateFromSiteName(siteName);</pre>

  <pre class="alt"><span class="lnum">  11:  </span>        NavigateToUrl(<span class="kwrd">string</span>.Format(siteUrlTemplate, findText, siteName));</pre>

  <pre><span class="lnum">  12:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  13:  </span>}</pre>
</div>

<p>Basically, we’ll get the site name, from a new method called GetSiteName, and we’ll get the text to find from a new method as well, called GetTextToFindOnSite. Let’s take a look at both of those methods:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; GetSiteName(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">return</span> queryString.ContainsKey(<span class="str">&quot;siteToSearch&quot;</span>)</pre>

  <pre><span class="lnum">   4:  </span>        ? queryString[<span class="str">&quot;siteToSearch&quot;</span>]</pre>

  <pre class="alt"><span class="lnum">   5:  </span>        : NormalizeDotComSuffixes(</pre>

  <pre><span class="lnum">   6:  </span>                await RecognizeTextFromWebSearchGrammar(<span class="str">&quot;Ex. \&quot;msdn blogs\&quot;&quot;</span>));</pre>

  <pre class="alt"><span class="lnum">   7:  </span>}</pre>

  <pre><span class="lnum">   8:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   9:  </span><span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; GetTextToFindOnSite(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString, <span class="kwrd">string</span> siteName)</pre>

  <pre><span class="lnum">  10:  </span>{</pre>

  <pre class="alt"><span class="lnum">  11:  </span>    <span class="kwrd">if</span> (!queryString.ContainsKey(<span class="str">&quot;siteToSearch&quot;</span>))</pre>

  <pre><span class="lnum">  12:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  13:  </span>        await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Search {0} for what?&quot;</span>, siteName));</pre>

  <pre><span class="lnum">  14:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  15:  </span>&#160;</pre>

  <pre><span class="lnum">  16:  </span>    <span class="kwrd">return</span> await RecognizeTextFromWebSearchGrammar(<span class="str">&quot;Ex. \&quot;electronics\&quot;&quot;</span>);</pre>

  <pre class="alt"><span class="lnum">  17:  </span>}</pre>
</div>

<p>In the first method, GetSiteName, we’ll check the dictionary, and if it has the siteToSearch, we’ll use that. But, if it doesn’t, we’ll get that site name from the same method we were getting the text to search for before, RecognizeTextFromWebSearchGrammar. Previously, though, that method had a hard coded example string, but now that we’re using it in two different ways, we’ll pass the example text string in as a parameter.</p>

<p>The second new method, GetTextToFindOnSite, similarly calls off to RecognizeTextFromWebSearchGrammar, but it also optionally prompts the user. This is because in the case of the “searchSite” voice command, the prompt will have already been played, by the VoiceCommandService’s use of that command’s &lt;Feedback&gt; element. However, for “searchSiteCatchAll”, the prompt from the VoiceCommandService is asking the user to will be asking what site to search. So, once the user responds to that, we’ll need to prompt them for the text they’d like to search for. Clear as mud? Well, hopefully it’s at least as clear as chicken broth. :-)</p>

<p>The actual implementation of RecognizeTextFromWebSearchGrammar is almost identical; only two lines are different: line 1 has a new parameter being passed in, the exampleText, and line 9, where we use that instead of the hard coded example from before. </p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; RecognizeTextFromWebSearchGrammar(<span class="kwrd">string</span> exampleText)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">string</span> text = <span class="kwrd">null</span>;</pre>

  <pre><span class="lnum">   4:  </span>    <span class="kwrd">try</span></pre>

  <pre class="alt"><span class="lnum">   5:  </span>    {</pre>

  <pre><span class="lnum">   6:  </span>        SpeechRecognizerUI sr = <span class="kwrd">new</span> SpeechRecognizerUI();</pre>

  <pre class="alt"><span class="lnum">   7:  </span>        sr.Recognizer.Grammars.AddGrammarFromPredefinedType(<span class="str">&quot;web&quot;</span>, SpeechPredefinedGrammar.WebSearch);</pre>

  <pre><span class="lnum">   8:  </span>        sr.Settings.ListenText = <span class="str">&quot;Listening...&quot;</span>;</pre>

  <pre class="alt"><span class="lnum">   9:  </span>        sr.Settings.ExampleText = exampleText;</pre>

  <pre><span class="lnum">  10:  </span>        sr.Settings.ReadoutEnabled = <span class="kwrd">false</span>;</pre>

  <pre class="alt"><span class="lnum">  11:  </span>        sr.Settings.ShowConfirmation = <span class="kwrd">false</span>;</pre>

  <pre><span class="lnum">  12:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  13:  </span>        SpeechRecognitionUIResult result = await sr.RecognizeWithUIAsync();</pre>

  <pre><span class="lnum">  14:  </span>        <span class="kwrd">if</span> (result != <span class="kwrd">null</span> &amp;&amp; </pre>

  <pre class="alt"><span class="lnum">  15:  </span>            result.ResultStatus == SpeechRecognitionUIStatus.Succeeded &amp;&amp;</pre>

  <pre><span class="lnum">  16:  </span>            result.RecognitionResult != <span class="kwrd">null</span> &amp;&amp;</pre>

  <pre class="alt"><span class="lnum">  17:  </span>            result.RecognitionResult.TextConfidence != SpeechRecognitionConfidence.Rejected)</pre>

  <pre><span class="lnum">  18:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  19:  </span>            text = result.RecognitionResult.Text;</pre>

  <pre><span class="lnum">  20:  </span>        }</pre>

  <pre class="alt"><span class="lnum">  21:  </span>    }</pre>

  <pre><span class="lnum">  22:  </span>    <span class="kwrd">catch</span> </pre>

  <pre class="alt"><span class="lnum">  23:  </span>    {</pre>

  <pre><span class="lnum">  24:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  25:  </span>    <span class="kwrd">return</span> text;</pre>

  <pre><span class="lnum">  26:  </span>}</pre>
</div>

<p>OK… The next change we’re going to make is to the GetUrlTemplateFromSiteName method. Previously, this was just looking up the site name in the dictionary of strings for our 15+ sites, and if it couldn’t find it, it would use a default URL template. Very similar to that still, now it also uses the “site:____.__” feature of Bing search, as long as it thinks that the siteName is actually a web site. I’m checking that in a fairly lame fashion for this example, but it works pretty well. Feel free to do a better check here yourself (see lines 9-12). :-)</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateFromSiteName(<span class="kwrd">string</span> siteName)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">string</span> url = <span class="kwrd">null</span>;</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">if</span> (_siteUrlTemplateDictionary.ContainsKey(siteName))</pre>

  <pre><span class="lnum">   6:  </span>    {</pre>

  <pre class="alt"><span class="lnum">   7:  </span>        url = _siteUrlTemplateDictionary[siteName];</pre>

  <pre><span class="lnum">   8:  </span>    }</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    <span class="kwrd">else</span> <span class="kwrd">if</span> (siteName.Length &gt; 4 &amp;&amp; siteName[siteName.Length - 4] != <span class="str">'.'</span>)</pre>

  <pre><span class="lnum">  10:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  11:  </span>        url = <span class="kwrd">string</span>.Format(_defaultUrlTemplateForUnknownSites, siteName + <span class="str">&quot;%20{0}&quot;</span>);</pre>

  <pre><span class="lnum">  12:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  13:  </span>    <span class="kwrd">else</span></pre>

  <pre><span class="lnum">  14:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  15:  </span>        url = <span class="kwrd">string</span>.Format(_defaultUrlTemplateForUnknownSites, <span class="str">&quot;site:&quot;</span> + siteName + <span class="str">&quot;%20{0}&quot;</span>);</pre>

  <pre><span class="lnum">  16:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  17:  </span>&#160;</pre>

  <pre><span class="lnum">  18:  </span>    <span class="kwrd">return</span> url;</pre>

  <pre class="alt"><span class="lnum">  19:  </span>}</pre>
</div>

<p>Last substantive change coming up … In our new GetSiteName method up above, I snuck in a call to a 3rd new method, NormalizeDotComSuffixes. It, well … Normalizes the site name we get back from voice search by trying to convert the tail of the string from things like “ dot com” and “dot O. R. G.” into “.com” and “.org”. That’ll be pretty important to make the new “site:____.___” Bing site specific search feature work in our app. Don’t forget to add a “using System.Text.RegularExpressions;” up at the top as well. </p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> NormalizeDotComSuffixes(<span class="kwrd">string</span> input)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    Regex re1 = <span class="kwrd">new</span> Regex(<span class="str">@&quot;\s+dot\s+(?&lt;suffix&gt;(com|net|org|gov))\z&quot;</span>);</pre>

  <pre><span class="lnum">   4:  </span>    <span class="kwrd">if</span> (input != <span class="kwrd">null</span> &amp;&amp; re1.IsMatch(input))</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    {</pre>

  <pre><span class="lnum">   6:  </span>        input = re1.Replace(input, <span class="str">@&quot;.${suffix}&quot;</span>).Replace(<span class="str">&quot; &quot;</span>, <span class="str">&quot;&quot;</span>);</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    }</pre>

  <pre><span class="lnum">   8:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    Regex re2 = <span class="kwrd">new</span> Regex(<span class="str">@&quot;\s+dot\s+(?&lt;l1&gt;[A-Z])[.]\s+(?&lt;l2&gt;[A-Z])[.]\s+(?&lt;l3&gt;[A-Z])[.]\z&quot;</span>);</pre>

  <pre><span class="lnum">  10:  </span>    <span class="kwrd">if</span> (input != <span class="kwrd">null</span> &amp;&amp; re2.IsMatch(input))</pre>

  <pre class="alt"><span class="lnum">  11:  </span>    {</pre>

  <pre><span class="lnum">  12:  </span>        input = re2.Replace(input, <span class="str">@&quot;.${l1}${l2}${l3}&quot;</span>).Replace(<span class="str">&quot; &quot;</span>, <span class="str">&quot;&quot;</span>);</pre>

  <pre class="alt"><span class="lnum">  13:  </span>        input = input.Substring(0, input.Length - 4) + input.Substring(input.Length - 4).ToLower();</pre>

  <pre><span class="lnum">  14:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  15:  </span>&#160;</pre>

  <pre><span class="lnum">  16:  </span>    <span class="kwrd">return</span> input;</pre>

  <pre class="alt"><span class="lnum">  17:  </span>}</pre>
</div>

<p>OK … Now, here’s the final change before we can test out our 3rd version of “Search On” … </p>

<p>Remember when the app was launched from the Start menu, or in any other non-VoiceCommandService type of way yesterday? When that happened, we did a search over to my blog. That’s neat and all, but … Now that we have the ability to ask the user what site they want to search, let’s just go ahead and start there in the conversation if our app is launched in t non-VoiceCommand kind of way. </p>

<p>To do that, we’ll make a super simple change to OnNavigatedTo (see line11, and a new function, called HandleNonVoiceCommandInvocation):</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">base</span>.OnNavigatedTo(e);</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New &amp;&amp; NavigationContext.QueryString.ContainsKey(<span class="str">&quot;voiceCommandName&quot;</span>))</pre>

  <pre><span class="lnum">   6:  </span>    {</pre>

  <pre class="alt"><span class="lnum">   7:  </span>        HandleVoiceCommand(NavigationContext.QueryString);</pre>

  <pre><span class="lnum">   8:  </span>    }</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New)</pre>

  <pre><span class="lnum">  10:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  11:  </span>        HandleNonVoiceCommandInvocation();</pre>

  <pre><span class="lnum">  12:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  13:  </span>    <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.Back &amp;&amp; !System.Diagnostics.Debugger.IsAttached)</pre>

  <pre><span class="lnum">  14:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  15:  </span>        NavigationService.GoBack();</pre>

  <pre><span class="lnum">  16:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  17:  </span>}</pre>

  <pre><span class="lnum">  18:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  19:  </span><span class="kwrd">private</span> async <span class="kwrd">void</span> HandleNonVoiceCommandInvocation()</pre>

  <pre><span class="lnum">  20:  </span>{</pre>

  <pre class="alt"><span class="lnum">  21:  </span>    await Speak(<span class="str">&quot;What site would you like to search?&quot;</span>);</pre>

  <pre><span class="lnum">  22:  </span>    SearchSiteVoiceCommand(<span class="kwrd">new</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt;());</pre>

  <pre class="alt"><span class="lnum">  23:  </span>}</pre>
</div>

<p>Basically, we’ll just prompt the user, and then do a site search just like we do when we get a “searchSiteCatchAll” voice command. That’s it.</p>

<p>OK. Time to give it a run! Press F5 and let’s take it for a spin. </p>

<blockquote>
  <p><strong>You: </strong>&quot;Whitehouse Dot Gov&quot; 

    <br /><strong>Phone: </strong>&quot;Search Whitehouse.gov for what?&quot; </p>

  <p><strong>You: </strong>&quot;Elections results&quot;

    <br /><strong>Phone: </strong>&quot;Searching Whitehouse.gov for Election results”</p>
</blockquote>

<p>Did it work? It did for me. Yeah!</p>

<p>Well, what about the voice command path into the code? Let’s try that out too … Press and hold the “Start” button and follow along below… </p>

<blockquote>
  <p><strong>User: </strong>&quot;Search a web site&quot; 

    <br /><strong>Phone: </strong>&quot;What web site would you like to search?&quot; </p>

  <p><strong>User: </strong>&quot;Whitehouse Dot Gov&quot; 

    <br /><strong>Phone: </strong>&quot;Search Whitehouse.gov for what?&quot; </p>

  <p><strong>User: </strong>&quot;Elections results&quot;

    <br /><strong>Phone: </strong>&quot;Searching Whitehouse.gov for Election results”</p>
</blockquote>

<p>… and, similarly …</p>

<blockquote>
  <p><strong>User: </strong>&quot;Search Whitehouse Dot Gov&quot; 

    <br /><strong>Phone: </strong>&quot;What web site would you like to search?&quot; </p>

  <p><strong>User: </strong>&quot;Whitehouse Dot Gov&quot; 

    <br /><strong>Phone: </strong>&quot;Search Whitehouse.gov for what?&quot; </p>

  <p><strong>User: </strong>&quot;Elections results&quot;

    <br /><strong>Phone: </strong>&quot;Searching Whitehouse.gov for Election results”</p>
</blockquote>

<p>Did those both work too? </p>

<p>OK. So that’s it for today… What’d we learn? Hopefully, you learned a few things:</p>

<ul>
  <li>You can use {*} very similarly to how you use {phraseListLabel}, without defining the list</li>

  <li>You can have more than one &lt;Command&gt; element in the &lt;CommandSet&gt;</li>

  <li>You can use the “Disambiguate” attribute on your &lt;PhraseList&gt; elements to tell the VoiceCommandService to not worry about clarifying which one the user said, in cases of ambiguity. </li>

  <li>And … Last by not least … You’ve learned that I really enjoy typing three dots in a row in all my posts … Like that … And like this … :-)</li>
</ul>

<p>Keep scrolling down for the full listings for our two most important source files. Catch you later!</p>

<p><strong>vcd.xml</strong></p>

<div class="csharpcode">
  <pre class="alt"><span class="kwrd">&lt;?</span><span class="html">xml</span> <span class="attr">version</span><span class="kwrd">=&quot;1.0&quot;</span> <span class="attr">encoding</span><span class="kwrd">=&quot;utf-8&quot;</span>?<span class="kwrd">&gt;</span></pre>

  <pre>&#160;</pre>

  <pre class="alt"><span class="kwrd">&lt;</span><span class="html">VoiceCommands</span> <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/voicecommands/1.0&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre>&#160;</pre>

  <pre class="alt">  <span class="kwrd">&lt;</span><span class="html">CommandSet</span> <span class="attr">xml:lang</span><span class="kwrd">=&quot;en-US&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre>&#160;</pre>

  <pre class="alt">    <span class="kwrd">&lt;</span><span class="html">CommandPrefix</span><span class="kwrd">&gt;</span>Search On<span class="kwrd">&lt;/</span><span class="html">CommandPrefix</span><span class="kwrd">&gt;</span></pre>

  <pre>    <span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>Amazon, Bing, Facebook, Twitter, ...<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">&#160;</pre>

  <pre>    <span class="kwrd">&lt;</span><span class="html">Command</span> <span class="attr">Name</span><span class="kwrd">=&quot;searchSiteCatchAll&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>a web site<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>[a] [specific] [web] site<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{*} <span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{*} {dotComOrNet} <span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Feedback</span><span class="kwrd">&gt;</span>What site would you like to search?<span class="kwrd">&lt;/</span><span class="html">Feedback</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Navigate</span> <span class="attr">Target</span><span class="kwrd">=&quot;MainPage.xaml&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre class="alt">    <span class="kwrd">&lt;/</span><span class="html">Command</span><span class="kwrd">&gt;</span></pre>

  <pre>&#160;</pre>

  <pre class="alt">    <span class="kwrd">&lt;</span><span class="html">Command</span> <span class="attr">Name</span><span class="kwrd">=&quot;searchSite&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>Amazon, Bing, Facebook, Twitter, ...<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{siteToSearch} <span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{siteToSearch} {dotComOrNet}<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Feedback</span><span class="kwrd">&gt;</span>Search on {siteToSearch} for what?<span class="kwrd">&lt;/</span><span class="html">Feedback</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Navigate</span> <span class="attr">Target</span><span class="kwrd">=&quot;MainPage.xaml&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre class="alt">    <span class="kwrd">&lt;/</span><span class="html">Command</span><span class="kwrd">&gt;</span></pre>

  <pre>&#160;</pre>

  <pre class="alt">    <span class="kwrd">&lt;</span><span class="html">PhraseList</span> <span class="attr">Label</span><span class="kwrd">=&quot;siteToSearch&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Amazon<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Bing<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>CNN<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Dictionary.com<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Ebay<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Facebook<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Google<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Hulu<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>IMDB<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Kayak<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Linked In<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>MSN<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Netflix<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Twitter<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Weather.com<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>YouTube<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Zillow<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">    <span class="kwrd">&lt;/</span><span class="html">PhraseList</span><span class="kwrd">&gt;</span></pre>

  <pre>&#160;</pre>

  <pre class="alt">    <span class="kwrd">&lt;</span><span class="html">PhraseList</span> <span class="attr">Label</span><span class="kwrd">=&quot;dotComOrNet&quot;</span> <span class="attr">Disambiguate</span><span class="kwrd">=&quot;false&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>dot com<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>dot net<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>dot org<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>dot gov<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre>    <span class="kwrd">&lt;/</span><span class="html">PhraseList</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">&#160;</pre>

  <pre>  <span class="kwrd">&lt;/</span><span class="html">CommandSet</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt">&#160;</pre>

  <pre><span class="kwrd">&lt;/</span><span class="html">VoiceCommands</span><span class="kwrd">&gt;</span></pre>
</div>

<p><strong>MainPage.xaml.cs</strong></p>

<div class="csharpcode">
  <pre class="alt"><span class="kwrd">using</span> System;</pre>

  <pre><span class="kwrd">using</span> System.Collections.Generic;</pre>

  <pre class="alt"><span class="kwrd">using</span> System.Net;</pre>

  <pre><span class="kwrd">using</span> System.Windows;</pre>

  <pre class="alt"><span class="kwrd">using</span> System.Windows.Navigation;</pre>

  <pre><span class="kwrd">using</span> Microsoft.Phone.Controls;</pre>

  <pre class="alt"><span class="kwrd">using</span> Windows.Phone.Speech.VoiceCommands;</pre>

  <pre><span class="kwrd">using</span> Windows.Phone.Speech.Recognition;</pre>

  <pre class="alt"><span class="kwrd">using</span> Windows.Phone.Speech.Synthesis;</pre>

  <pre><span class="kwrd">using</span> System.Threading.Tasks;</pre>

  <pre class="alt"><span class="kwrd">using</span> Microsoft.Phone.Tasks;</pre>

  <pre><span class="kwrd">using</span> System.Text.RegularExpressions;</pre>

  <pre class="alt">&#160;</pre>

  <pre><span class="kwrd">namespace</span> SearchOn</pre>

  <pre class="alt">{</pre>

  <pre>    <span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> MainPage : PhoneApplicationPage</pre>

  <pre class="alt">    {</pre>

  <pre>        <span class="kwrd">public</span> MainPage()</pre>

  <pre class="alt">        {</pre>

  <pre>            InitializeComponent();</pre>

  <pre class="alt">&#160;</pre>

  <pre>            VoiceCommandService.InstallCommandSetsFromFileAsync(<span class="kwrd">new</span> Uri(<span class="str">&quot;ms-appx:///vcd.xml&quot;</span>));</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">base</span>.OnNavigatedTo(e);</pre>

  <pre>&#160;</pre>

  <pre class="alt">            <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New &amp;&amp; NavigationContext.QueryString.ContainsKey(<span class="str">&quot;voiceCommandName&quot;</span>))</pre>

  <pre>            {</pre>

  <pre class="alt">                HandleVoiceCommand(NavigationContext.QueryString);</pre>

  <pre>            }</pre>

  <pre class="alt">            <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New)</pre>

  <pre>            {</pre>

  <pre class="alt">                HandleNonVoiceCommandInvocation();</pre>

  <pre>            }</pre>

  <pre class="alt">            <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.Back &amp;&amp; !System.Diagnostics.Debugger.IsAttached)</pre>

  <pre>            {</pre>

  <pre class="alt">                NavigationService.GoBack();</pre>

  <pre>            }</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> async <span class="kwrd">void</span> HandleNonVoiceCommandInvocation()</pre>

  <pre>        {</pre>

  <pre class="alt">            await Speak(<span class="str">&quot;What site would you like to search?&quot;</span>);</pre>

  <pre>            SearchSiteVoiceCommand(<span class="kwrd">new</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt;());</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">void</span> HandleVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre>        {</pre>

  <pre class="alt">            <span class="kwrd">switch</span> (queryString[<span class="str">&quot;voiceCommandName&quot;</span>])</pre>

  <pre>            {</pre>

  <pre class="alt">                <span class="kwrd">case</span> <span class="str">&quot;searchSite&quot;</span>:</pre>

  <pre>                <span class="kwrd">case</span> <span class="str">&quot;searchSiteCatchAll&quot;</span>:</pre>

  <pre class="alt">                    SearchSiteVoiceCommand(queryString);</pre>

  <pre>                    <span class="kwrd">break</span>;</pre>

  <pre class="alt">            }</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> async <span class="kwrd">void</span> SearchSiteVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">string</span> siteName, findText;</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">if</span> (<span class="kwrd">null</span> != (siteName = await GetSiteName(queryString)) &amp;&amp;</pre>

  <pre class="alt">                <span class="kwrd">null</span> != (findText = await GetTextToFindOnSite(queryString, siteName)))</pre>

  <pre>            {</pre>

  <pre class="alt">                await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Searching {0} for {1}&quot;</span>, siteName, findText));</pre>

  <pre>&#160;</pre>

  <pre class="alt">                <span class="kwrd">string</span> siteUrlTemplate = GetUrlTemplateFromSiteName(siteName);</pre>

  <pre>                NavigateToUrl(<span class="kwrd">string</span>.Format(siteUrlTemplate, findText, siteName));</pre>

  <pre class="alt">            }</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; GetSiteName(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">return</span> queryString.ContainsKey(<span class="str">&quot;siteToSearch&quot;</span>)</pre>

  <pre class="alt">                ? queryString[<span class="str">&quot;siteToSearch&quot;</span>]</pre>

  <pre>                : NormalizeDotComSuffixes(</pre>

  <pre class="alt">                        await RecognizeTextFromWebSearchGrammar(<span class="str">&quot;Ex. \&quot;msdn blogs\&quot;&quot;</span>));</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; GetTextToFindOnSite(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString, <span class="kwrd">string</span> siteName)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">if</span> (!queryString.ContainsKey(<span class="str">&quot;siteToSearch&quot;</span>))</pre>

  <pre class="alt">            {</pre>

  <pre>                await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Search {0} for what?&quot;</span>, siteName));</pre>

  <pre class="alt">            }</pre>

  <pre>&#160;</pre>

  <pre class="alt">            <span class="kwrd">return</span> await RecognizeTextFromWebSearchGrammar(<span class="str">&quot;Ex. \&quot;electronics\&quot;&quot;</span>);</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; RecognizeTextFromWebSearchGrammar(<span class="kwrd">string</span> exampleText)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">string</span> text = <span class="kwrd">null</span>;</pre>

  <pre class="alt">            <span class="kwrd">try</span></pre>

  <pre>            {</pre>

  <pre class="alt">                SpeechRecognizerUI sr = <span class="kwrd">new</span> SpeechRecognizerUI();</pre>

  <pre>                sr.Recognizer.Grammars.AddGrammarFromPredefinedType(<span class="str">&quot;web&quot;</span>, SpeechPredefinedGrammar.WebSearch);</pre>

  <pre class="alt">                sr.Settings.ListenText = <span class="str">&quot;Listening...&quot;</span>;</pre>

  <pre>                sr.Settings.ExampleText = exampleText;</pre>

  <pre class="alt">                sr.Settings.ReadoutEnabled = <span class="kwrd">false</span>;</pre>

  <pre>                sr.Settings.ShowConfirmation = <span class="kwrd">false</span>;</pre>

  <pre class="alt">&#160;</pre>

  <pre>                SpeechRecognitionUIResult result = await sr.RecognizeWithUIAsync();</pre>

  <pre class="alt">                <span class="kwrd">if</span> (result != <span class="kwrd">null</span> &amp;&amp; </pre>

  <pre>                    result.ResultStatus == SpeechRecognitionUIStatus.Succeeded &amp;&amp;</pre>

  <pre class="alt">                    result.RecognitionResult != <span class="kwrd">null</span> &amp;&amp;</pre>

  <pre>                    result.RecognitionResult.TextConfidence != SpeechRecognitionConfidence.Rejected)</pre>

  <pre class="alt">                {</pre>

  <pre>                    text = result.RecognitionResult.Text;</pre>

  <pre class="alt">                }</pre>

  <pre>            }</pre>

  <pre class="alt">            <span class="kwrd">catch</span> </pre>

  <pre>            {</pre>

  <pre class="alt">            }</pre>

  <pre>            <span class="kwrd">return</span> text;</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> async Task Speak(<span class="kwrd">string</span> text)</pre>

  <pre>        {</pre>

  <pre class="alt">            SpeechSynthesizer tts = <span class="kwrd">new</span> SpeechSynthesizer();</pre>

  <pre>            await tts.SpeakTextAsync(text);</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">void</span> NavigateToUrl(<span class="kwrd">string</span> url)</pre>

  <pre>        {</pre>

  <pre class="alt">            WebBrowserTask task = <span class="kwrd">new</span> WebBrowserTask();</pre>

  <pre>            task.Uri = <span class="kwrd">new</span> Uri(url, UriKind.Absolute);</pre>

  <pre class="alt">            task.Show();</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateFromSiteName(<span class="kwrd">string</span> siteName)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">string</span> url = <span class="kwrd">null</span>;</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">if</span> (_siteUrlTemplateDictionary.ContainsKey(siteName))</pre>

  <pre class="alt">            {</pre>

  <pre>                url = _siteUrlTemplateDictionary[siteName];</pre>

  <pre class="alt">            }</pre>

  <pre>            <span class="kwrd">else</span> <span class="kwrd">if</span> (siteName.Length &gt; 4 &amp;&amp; siteName[siteName.Length - 4] != <span class="str">'.'</span>)</pre>

  <pre class="alt">            {</pre>

  <pre>                url = <span class="kwrd">string</span>.Format(_defaultUrlTemplateForUnknownSites, siteName + <span class="str">&quot;%20{0}&quot;</span>);</pre>

  <pre class="alt">            }</pre>

  <pre>            <span class="kwrd">else</span></pre>

  <pre class="alt">            {</pre>

  <pre>                url = <span class="kwrd">string</span>.Format(_defaultUrlTemplateForUnknownSites, <span class="str">&quot;site:&quot;</span> + siteName + <span class="str">&quot;%20{0}&quot;</span>);</pre>

  <pre class="alt">            }</pre>

  <pre>&#160;</pre>

  <pre class="alt">            <span class="kwrd">return</span> url;</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> <span class="kwrd">string</span> NormalizeDotComSuffixes(<span class="kwrd">string</span> input)</pre>

  <pre class="alt">        {</pre>

  <pre>            Regex re1 = <span class="kwrd">new</span> Regex(<span class="str">@&quot;\s+dot\s+(?&lt;suffix&gt;(com|net|org|gov))\z&quot;</span>);</pre>

  <pre class="alt">            <span class="kwrd">if</span> (input != <span class="kwrd">null</span> &amp;&amp; re1.IsMatch(input))</pre>

  <pre>            {</pre>

  <pre class="alt">                input = re1.Replace(input, <span class="str">@&quot;.${suffix}&quot;</span>).Replace(<span class="str">&quot; &quot;</span>, <span class="str">&quot;&quot;</span>);</pre>

  <pre>            }</pre>

  <pre class="alt">&#160;</pre>

  <pre>            Regex re2 = <span class="kwrd">new</span> Regex(<span class="str">@&quot;\s+dot\s+(?&lt;l1&gt;[A-Z])[.]\s+(?&lt;l2&gt;[A-Z])[.]\s+(?&lt;l3&gt;[A-Z])[.]\z&quot;</span>);</pre>

  <pre class="alt">            <span class="kwrd">if</span> (input != <span class="kwrd">null</span> &amp;&amp; re2.IsMatch(input))</pre>

  <pre>            {</pre>

  <pre class="alt">                input = re2.Replace(input, <span class="str">@&quot;.${l1}${l2}${l3}&quot;</span>).Replace(<span class="str">&quot; &quot;</span>, <span class="str">&quot;&quot;</span>);</pre>

  <pre>                input = input.Substring(0, input.Length - 4) + input.Substring(input.Length - 4).ToLower();</pre>

  <pre class="alt">            }</pre>

  <pre>&#160;</pre>

  <pre class="alt">            <span class="kwrd">return</span> input;</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> <span class="kwrd">string</span> _defaultUrlTemplateForUnknownSites = <span class="str">&quot;http://m.bing.com/search?q={0}&quot;</span>;</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; _siteUrlTemplateDictionary = <span class="kwrd">new</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt;()</pre>

  <pre class="alt">        {</pre>

  <pre>            { <span class="str">&quot;Amazon&quot;</span>, <span class="str">&quot;http://www.amazon.com/gp/aw/s/ref=is_box_?k={0}&quot;</span> },</pre>

  <pre class="alt">            { <span class="str">&quot;Bing&quot;</span>, <span class="str">&quot;http://www.bing.com/?q={0}&quot;</span> },</pre>

  <pre>            { <span class="str">&quot;CNN&quot;</span>, <span class="str">&quot;http://www.cnn.com/search/?query={0}&quot;</span> },</pre>

  <pre class="alt">            { <span class="str">&quot;Dictionary.com&quot;</span>, <span class="str">&quot;http://dictionary.reference.com/browse/{0}&quot;</span> },</pre>

  <pre>            { <span class="str">&quot;Ebay&quot;</span>, <span class="str">&quot;http://www.ebay.com/sch/i.html?_nkw={0}&quot;</span> },</pre>

  <pre class="alt">            { <span class="str">&quot;Facebook&quot;</span>, <span class="str">&quot;http://www.facebook.com/search/results.php?q={0}&quot;</span> },</pre>

  <pre>            { <span class="str">&quot;Google&quot;</span>, <span class="str">&quot;https://www.google.com/search?hl=en&amp;q={0}&quot;</span> },</pre>

  <pre class="alt">            { <span class="str">&quot;Hulu&quot;</span>, <span class="str">&quot;http://www.hulu.com/#!search?q={0}&quot;</span> },</pre>

  <pre>            { <span class="str">&quot;IMDB&quot;</span>, <span class="str">&quot;http://www.imdb.com/find?s=all&amp;q={0}&quot;</span> },</pre>

  <pre class="alt">            { <span class="str">&quot;Linked In&quot;</span>, <span class="str">&quot;http://www.linkedin.com/search/fpsearch?keywords={0}&quot;</span> },</pre>

  <pre>            { <span class="str">&quot;MSN&quot;</span>, <span class="str">&quot;http://www.bing.com/search?scope=msn&amp;q={0}&quot;</span> },</pre>

  <pre class="alt">            { <span class="str">&quot;Twitter&quot;</span>, <span class="str">&quot;https://twitter.com/search/{0}&quot;</span> },</pre>

  <pre>            { <span class="str">&quot;Weather&quot;</span>, <span class="str">&quot;http://www.weather.com/info/sitesearch?q={0}&quot;</span> },</pre>

  <pre class="alt">            { <span class="str">&quot;YouTube&quot;</span>, <span class="str">&quot;https://www.youtube.com/results?search_query={0}&quot;</span> },</pre>

  <pre>            { <span class="str">&quot;Zillow&quot;</span>, <span class="str">&quot;http://www.zillow.com/homes/{0}/&quot;</span> },</pre>

  <pre class="alt">        };</pre>

  <pre>    }</pre>

  <pre class="alt">}</pre>
</div>]]></content:encoded>
    </item>
    <item>
      <title>WP8 Voice Commands: Phrase Lists</title>
      <link>https://docs.microsoft.com/archive/blogs/robch/wp8-voice-commands-phrase-lists</link>
      <pubDate>Wed, 07 Nov 2012 12:00:14 GMT</pubDate>
      <dc:creator><![CDATA[Rob Chambers]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/robch/2012/11/07/wp8-voice-commands-phrase-lists/</guid>
      <description><![CDATA[Today, I ’m going to show you how to extend the app we built in yesterday’s post, using something we...]]></description>
      <content:encoded><![CDATA[<p>Today, I ’m going to show you how to extend the app we built in yesterday’s <a href="http://blogs.msdn.com/b/robch/archive/2012/11/06/how-many-lines-of-code-does-it-take-to-build-a-complete-wp8-speech-app.aspx">post</a>, using something we call Phrase Lists. Using a Phrase List, we’ll be able to let users of our “Search On” application “Search on” 15 more sites, not just search on Amazon.com. </p>  <p>Here are a couple examples of how that’ll play out for users of the app…</p>  <p>To search on Amazon, it’ll work just like it did yesterday (with a small tweak to the prompt):</p>  <blockquote>   <p><strong>User: </strong>&quot;Search On Amazon&quot;       <br /><strong>Phone: </strong>&quot;Search Amazon for what?&quot;       <br /><strong>User: </strong>&quot;Electronics&quot; (or whatever the user wants)       <br /><strong>Phone: </strong>&quot;Searching Amazon for Electronics&quot; (or whatever the user said she wanted)</p> </blockquote>  <p>But with the changes today, you’ll also be able to search on a <em>bunch</em> of sites. Here are the sites we’ll add today: Amazon, Bing, CNN, Dictionary.com, Ebay, Facebook, MSN, Twitter, Weather.com, YouTube, or Zillow. Feel free to add more when you’re typing it up on your computer.</p>  <blockquote>   <p><strong>User: </strong>&quot;Search On CNN&quot;       <br /><strong>Phone: </strong>&quot;Search CNN for what?&quot;       <br /><strong>User: </strong>&quot;Presidential Election Results”      <br /><strong>Phone: </strong>&quot;Searching CNN for Presidential Election Results&quot;</p> </blockquote>  <p>… or … </p>  <blockquote>   <p><strong>User: </strong>&quot;Search On Weather.com&quot;       <br /><strong>Phone: </strong>&quot;Search Weather.com for what?&quot;       <br /><strong>User: </strong>&quot;Seattle 10 day forecast”      <br /><strong>Phone: </strong>&quot;Searching Weather.com for Seattle 10 day forecast&quot;</p> </blockquote>  <p>Sound Good? OK… Let’s get started.</p>  <p>First of all, if you haven’t built the app from yesterday, go do that now. Start <a href="http://blogs.msdn.com/b/robch/archive/2012/11/06/how-many-lines-of-code-does-it-take-to-build-a-complete-wp8-speech-app.aspx">here</a>…&#160; </p>  <p>Now, let’s update our Voice Command Definition file. We’re going to make 4 changes to the VCD file. 1.) We’re going to update the examples phrases that get displayed to users in the built in speech UX in WP8, 2.) We’re going to add a Phrase List&#160; that will contain the list of sites that we want to be able to search, 3.) We’ll refer to that PhraseList from our searchSite &lt;Command&gt;, specifically, from our &lt;ListenFor&gt; elements, and, finally 4.) We’ll change the text feedback in the &lt;Feedback&gt; element to react dynamically to what the user said.</p>  <p>Here we go … </p>  <p>To update the example phrases, simply find the existing &lt;Example&gt; elements from the vcd.xml file, and replace them this:</p>  <div class="csharpcode">   <pre class="alt"><span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>Amazon, Bing, CNN, Dictionary.com, Ebay, Facebook, </pre>

  <pre>         MSN, Twitter, Weather.com, YouTube, or Zillow<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>
</div>


<p>Now, let’s actually define the PhraseList. You can have up to 10 PhraseLists in your VoiceCommands CommandSet, and the PhraseLists must be <em>after</em> all the Command elements in the XML file. If there are more than 10, or they’re not in the right spot in the VCD file, Visual Studio should give you a red underlined squiggly line that will tell you what’s wrong when you hover over it. If for some reason you miss this, at runtime the call to InstallCommandSetsFromFileAsync will throw an exception. In our sample, we’re not trying to catch those, so if you don’t have a debugger hooked up, you’ll miss it. </p>

<p>We’ll name our PhraseList “siteToSearch”, and define it like this:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">&lt;</span><span class="html">PhraseList</span> <span class="attr">Label</span><span class="kwrd">=&quot;siteToSearch&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   2:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Amazon<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   3:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Bing<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   4:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>CNN<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Dictionary.com<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   6:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Ebay<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   7:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Facebook<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   8:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Google<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   9:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Hulu<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  10:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>IMDB<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  11:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Kayak<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  12:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Linked In<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  13:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>MSN<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  14:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Netflix<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  15:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Twitter<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  16:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Weather.com<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  17:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>YouTube<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  18:  </span>  <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Zillow<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  19:  </span><span class="kwrd">&lt;/</span><span class="html">PhraseList</span><span class="kwrd">&gt;</span></pre>
</div>

<p>Next, let’s update our Command, with ListenFor elements that reference this list. </p>

<p>The text inside a ListenFor element is used as a constraint for the recognizer. In yesterday’s example, we used a simple string, “Amazon”, as the content for our one and only ListenFor element. That meant that the user had to say “Search On”, which is the command prefix for our application, followed by “Amazon”. If you have several things you want the user to be able to say, you can do one, or both, of the following 2 things: have more than one &lt;ListenFor&gt; element in your command, and/or have your &lt;ListenFor&gt; element refer to a PhraseList by it’s Label. </p>

<p>Let’s see what that looks like for our updated application. Replace the &lt;ListenFor&gt; from yesterday, with the following:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{siteToSearch}<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   2:  </span><span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{siteToSearch} dot com<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>
</div>

<p>The first &lt;ListenFor&gt; element only contains a reference to the PhraseList. The second &lt;ListenFor&gt;, though, both references the same PhraseList, but it also has the words “dot com” after that PhraseList reference. What does this do? Well, it tells the recognizer that it’s OK for the user to say any one of the items inside the PhraseList with the siteToSearch Label, followed by the phrase “dot com”. Because we have both of these &lt;ListenFor&gt; elements, it essentially makes the “dot com” and optional phrase. We could have specified using an “optional” notation, using square brackets, like this:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{siteToSearch} [dot com]<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>
</div>

<p>Either of these two representations is essentially result in the same constraint being communicated to the speech recognizer. </p>

<p>OK. We’ve updated our examples, we’ve added our PhraseList for the sites to search, and we’ve updated our phrases for our command. Last thing we need to do is to update the &lt;Feedback&gt; element. </p>

<p>Similar to the &lt;ListenFor&gt; elements’ use of the PhraseList Label, we can substitute what was said from the PhraseList into the text feedback as well. Let’s update our &lt;Feedback&gt; element, and it should be pretty obvious what I mean:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">&lt;</span><span class="html">Feedback</span><span class="kwrd">&gt;</span>Search on {siteToSearch} for what?<span class="kwrd">&lt;/</span><span class="html">Feedback</span><span class="kwrd">&gt;</span></pre>
</div>

<p>What that’ll do is this: Once the VoiceCommandService determines that one of your commands was recognized, it’ll take the text inside the corresponding &lt;Feedback&gt; element, and it’ll replace all occurrences of curly brace delimited PhraseLists with the text for the item that was actually recognized from the user speaking. That way, if I said “Search On Amazon”, the VoiceCommandService will replace the “{siteToSearch}” part of “Search on {siteToSearch} for what?” feedback string with “Amazon”. It’s a lot like C# string formatting, except using PhraseList Labels instead of order based parameter references, like 0, 1, 2. </p>

<p>OK. Now, our VCD file is all up to date. Great. Now let’s turn our attention to the code in MainPage.xaml.cs.</p>

<p>Let’s start off by adding a Dictionary of strings that we’ll use to look up the URL for the site we’ll be searching. And, if let’s have a backup way of searching if we can’t find that URL. Scroll down to the bottom of the MainPage class, and add the following:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> _defaultUrlTemplateForUnknownSites = <span class="str">&quot;http://m.bing.com/search?q={0}&quot;</span>;</pre>

  <pre><span class="lnum">   2:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">private</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; _siteUrlTemplateDictionary = <span class="kwrd">new</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt;()</pre>

  <pre><span class="lnum">   4:  </span>{</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    { <span class="str">&quot;Amazon&quot;</span>, <span class="str">&quot;http://www.amazon.com/gp/aw/s/ref=is_box_?k={0}&quot;</span> },</pre>

  <pre><span class="lnum">   6:  </span>    { <span class="str">&quot;Bing&quot;</span>, <span class="str">&quot;http://www.bing.com/?q={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    { <span class="str">&quot;CNN&quot;</span>, <span class="str">&quot;http://www.cnn.com/search/?query={0}&quot;</span> },</pre>

  <pre><span class="lnum">   8:  </span>    { <span class="str">&quot;Dictionary.com&quot;</span>, <span class="str">&quot;http://dictionary.reference.com/browse/{0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    { <span class="str">&quot;Ebay&quot;</span>, <span class="str">&quot;http://www.ebay.com/sch/i.html?_nkw={0}&quot;</span> },</pre>

  <pre><span class="lnum">  10:  </span>    { <span class="str">&quot;Facebook&quot;</span>, <span class="str">&quot;http://www.facebook.com/search/results.php?q={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum">  11:  </span>    { <span class="str">&quot;Google&quot;</span>, <span class="str">&quot;https://www.google.com/search?hl=en&amp;q={0}&quot;</span> },</pre>

  <pre><span class="lnum">  12:  </span>    { <span class="str">&quot;Hulu&quot;</span>, <span class="str">&quot;http://www.hulu.com/#!search?q={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum">  13:  </span>    { <span class="str">&quot;IMDB&quot;</span>, <span class="str">&quot;http://www.imdb.com/find?s=all&amp;q={0}&quot;</span> },</pre>

  <pre><span class="lnum">  14:  </span>    { <span class="str">&quot;Linked In&quot;</span>, <span class="str">&quot;http://www.linkedin.com/search/fpsearch?keywords={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum">  15:  </span>    { <span class="str">&quot;MSN&quot;</span>, <span class="str">&quot;http://www.bing.com/search?scope=msn&amp;q={0}&quot;</span> },</pre>

  <pre><span class="lnum">  16:  </span>    { <span class="str">&quot;Twitter&quot;</span>, <span class="str">&quot;https://twitter.com/search/{0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum">  17:  </span>    { <span class="str">&quot;Weather&quot;</span>, <span class="str">&quot;http://www.weather.com/info/sitesearch?q={0}&quot;</span> },</pre>

  <pre><span class="lnum">  18:  </span>    { <span class="str">&quot;YouTube&quot;</span>, <span class="str">&quot;https://www.youtube.com/results?search_query={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum">  19:  </span>    { <span class="str">&quot;Zillow&quot;</span>, <span class="str">&quot;http://www.zillow.com/homes/{0}/&quot;</span> },</pre>

  <pre><span class="lnum">  20:  </span>};</pre>
</div>

<p>Now, let’s add a method that’ll do the lookup for us:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateFromSiteName(<span class="kwrd">string</span> siteName)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">return</span> _siteUrlTemplateDictionary.ContainsKey(siteName)</pre>

  <pre><span class="lnum">   4:  </span>        ? _siteUrlTemplateDictionary[siteName]</pre>

  <pre class="alt"><span class="lnum">   5:  </span>        : <span class="kwrd">string</span>.Format(_defaultUrlTemplateForUnknownSites, siteName + <span class="str">&quot;%20{1}&quot;</span>);</pre>

  <pre><span class="lnum">   6:  </span>}</pre>
</div>

<p>Great. Now let’s update our SearchSiteVoiceCommand method to figure out what site we’re actually searching, update how we speak the feedback based on the site name, use our new GetUrlTemplateFromSiteName method to find the right URL template, and then stick the search string into the URL template appropriately. When it’s all done, it should look like this:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> async <span class="kwrd">void</span> SearchSiteVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">string</span> text = await RecognizeTextFromWebSearchGrammar();</pre>

  <pre><span class="lnum">   4:  </span>    <span class="kwrd">if</span> (text != <span class="kwrd">null</span>)</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    {</pre>

  <pre><span class="lnum">   6:  </span>        <span class="kwrd">string</span> siteName = queryString[<span class="str">&quot;siteToSearch&quot;</span>];</pre>

  <pre class="alt"><span class="lnum">   7:  </span>        await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Searching {0} for {1}&quot;</span>, siteName, text));</pre>

  <pre><span class="lnum">   8:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   9:  </span>        <span class="kwrd">string</span> siteUrlTemplate = GetUrlTemplateFromSiteName(siteName);</pre>

  <pre><span class="lnum">  10:  </span>        NavigateToUrl(<span class="kwrd">string</span>.Format(siteUrlTemplate, text, siteName));</pre>

  <pre class="alt"><span class="lnum">  11:  </span>    }</pre>

  <pre><span class="lnum">  12:  </span>}</pre>
</div>

<p>One additional thing I’ll do, that we don’t absolutely need to at this point, but I think it’s good practice, is to make sure that we actually have a “siteToSearch” item in our query string dictionary in our HandleVoiceCommand method. </p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> HandleVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">if</span> (queryString[<span class="str">&quot;voiceCommandName&quot;</span>] == <span class="str">&quot;searchSite&quot;</span> &amp;&amp; </pre>

  <pre><span class="lnum">   4:  </span>        queryString.ContainsKey(<span class="str">&quot;siteToSearch&quot;</span>))</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    {</pre>

  <pre><span class="lnum">   6:  </span>        SearchSiteVoiceCommand(queryString);</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    }</pre>

  <pre><span class="lnum">   8:  </span>}</pre>
</div>

<p>One more change, and then we can test it out. </p>

<p>Since we were only searching Amazon.com yesterday, it was probably OK for us to open up the Amazon.com home page if you started the Search On application from the Start menu, not by voice. But … It doesn’t make as much sense now, since we can search 15 different sites. Right?</p>

<p>So, I’ll update the code to search for blog posts by me about Windows Phone 8 on my MSDN blog instead. A bit self serving, I know, but … Hey … It’s my sample app, right? :-)</p>

<p>First, I’ll define a class variable to hold the new location we’ll open in that situation:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">string</span> _defaultUrlForNewNavigations = </pre>

  <pre><span class="lnum">   2:  </span>    <span class="str">&quot;http://m.bing.com/search?q=Rob's%20Rhapsody%20Windows%20Phone%208%20site:blogs.msdn.com&quot;</span>;</pre>
</div>

<p>And then, I’ll update the OnNavigatedTo method to use that new class variable (see line 11 in the snippet below):</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">base</span>.OnNavigatedTo(e);</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New &amp;&amp; NavigationContext.QueryString.ContainsKey(<span class="str">&quot;voiceCommandName&quot;</span>))</pre>

  <pre><span class="lnum">   6:  </span>    {</pre>

  <pre class="alt"><span class="lnum">   7:  </span>        HandleVoiceCommand(NavigationContext.QueryString);</pre>

  <pre><span class="lnum">   8:  </span>    }</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New)</pre>

  <pre><span class="lnum">  10:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  11:  </span>        NavigateToUrl(_defaultUrlForNewNavigations);</pre>

  <pre><span class="lnum">  12:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  13:  </span>    <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.Back &amp;&amp; !System.Diagnostics.Debugger.IsAttached)</pre>

  <pre><span class="lnum">  14:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  15:  </span>        NavigationService.GoBack();</pre>

  <pre><span class="lnum">  16:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  17:  </span>}</pre>
</div>

<p>Now we’re ready to try it out. </p>

<p>If you haven’t typed this in all along the way, you can scroll down below and copy/paste into Visual Studio and give it a go that way.</p>

<p>Press F5, and you should see a Bing Search for my blog. Yeah.</p>

<p>Now, on the phone, Press and hold the “Start” menu, and let’s try out our examples from above. </p>

<blockquote>
  <p><strong>You: </strong>&quot;Search On Amazon&quot; 

    <br /><strong>Phone: </strong>&quot;Search Amazon for what?&quot; 

    <br /><strong>You: </strong>&quot;Electronics&quot; (or whatever you want) 

    <br /><strong>Phone: </strong>&quot;Searching Amazon for Electronics&quot; (or whatever you said you wanted)</p>
</blockquote>

<p>Great. That one still works! Let’s try out the others…</p>

<blockquote>
  <p><strong>User: </strong>&quot;Search On CNN&quot; 

    <br /><strong>Phone: </strong>&quot;Search CNN for what?&quot; 

    <br /><strong>User: </strong>&quot;Presidential Election Results”

    <br /><strong>Phone: </strong>&quot;Searching CNN for Presidential Election Results&quot;</p>
</blockquote>

<p>Did that one work as well? Mine did. :-) Last one … we’ll try here today…</p>

<blockquote>
  <p><strong>User: </strong>&quot;Search On Weather.com&quot; 

    <br /><strong>Phone: </strong>&quot;Search Weather.com for what?&quot; 

    <br /><strong>User: </strong>&quot;Seattle 10 day forecast”

    <br /><strong>Phone: </strong>&quot;Searching Weather.com for Seattle 10 day forecast&quot;</p>
</blockquote>

<p>Excellent. Well … except it’s going to rain this week. Bummer. But the speech part worked. If only I could say “Clouds, stop raining!!” I’m sure I can do the speech part of that one; it’s the actual stop raining part I don’t know how to do. Yet. :-)</p>

<p>Well. That’s it for today. Hopefully, you now know how to use PhraseLists with the VoiceCommandService. And … Our “Search On” application is starting to actually become useful. I wonder how far we can take this … </p>

<p>Drop me some feedback below and let me know what you’d like to see, and I’ll try to work that into posts in the future.</p>

<p>Happy coding! … Oh yeah … I almost forgot … Here’s the full listing for the code, and the VCD file.</p>

<p><strong>MainPage.xaml.cs</strong></p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">using</span> System;</pre>

  <pre><span class="lnum">   2:  </span><span class="kwrd">using</span> System.Collections.Generic;</pre>

  <pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">using</span> System.Net;</pre>

  <pre><span class="lnum">   4:  </span><span class="kwrd">using</span> System.Windows;</pre>

  <pre class="alt"><span class="lnum">   5:  </span><span class="kwrd">using</span> System.Windows.Navigation;</pre>

  <pre><span class="lnum">   6:  </span><span class="kwrd">using</span> Microsoft.Phone.Controls;</pre>

  <pre class="alt"><span class="lnum">   7:  </span><span class="kwrd">using</span> Windows.Phone.Speech.VoiceCommands;</pre>

  <pre><span class="lnum">   8:  </span><span class="kwrd">using</span> Windows.Phone.Speech.Recognition;</pre>

  <pre class="alt"><span class="lnum">   9:  </span><span class="kwrd">using</span> Windows.Phone.Speech.Synthesis;</pre>

  <pre><span class="lnum">  10:  </span><span class="kwrd">using</span> System.Threading.Tasks;</pre>

  <pre class="alt"><span class="lnum">  11:  </span><span class="kwrd">using</span> Microsoft.Phone.Tasks;</pre>

  <pre><span class="lnum">  12:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  13:  </span><span class="kwrd">namespace</span> SearchOn</pre>

  <pre><span class="lnum">  14:  </span>{</pre>

  <pre class="alt"><span class="lnum">  15:  </span>    <span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> MainPage : PhoneApplicationPage</pre>

  <pre><span class="lnum">  16:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  17:  </span>        <span class="kwrd">public</span> MainPage()</pre>

  <pre><span class="lnum">  18:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  19:  </span>            InitializeComponent();</pre>

  <pre><span class="lnum">  20:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  21:  </span>            VoiceCommandService.InstallCommandSetsFromFileAsync(<span class="kwrd">new</span> Uri(<span class="str">&quot;ms-appx:///vcd.xml&quot;</span>));</pre>

  <pre><span class="lnum">  22:  </span>        }</pre>

  <pre class="alt"><span class="lnum">  23:  </span>&#160;</pre>

  <pre><span class="lnum">  24:  </span>        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)</pre>

  <pre class="alt"><span class="lnum">  25:  </span>        {</pre>

  <pre><span class="lnum">  26:  </span>            <span class="kwrd">base</span>.OnNavigatedTo(e);</pre>

  <pre class="alt"><span class="lnum">  27:  </span>&#160;</pre>

  <pre><span class="lnum">  28:  </span>            <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New &amp;&amp; NavigationContext.QueryString.ContainsKey(<span class="str">&quot;voiceCommandName&quot;</span>))</pre>

  <pre class="alt"><span class="lnum">  29:  </span>            {</pre>

  <pre><span class="lnum">  30:  </span>                HandleVoiceCommand(NavigationContext.QueryString);</pre>

  <pre class="alt"><span class="lnum">  31:  </span>            }</pre>

  <pre><span class="lnum">  32:  </span>            <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New)</pre>

  <pre class="alt"><span class="lnum">  33:  </span>            {</pre>

  <pre><span class="lnum">  34:  </span>                NavigateToUrl(_defaultUrlForNewNavigations);</pre>

  <pre class="alt"><span class="lnum">  35:  </span>            }</pre>

  <pre><span class="lnum">  36:  </span>            <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.Back &amp;&amp; !System.Diagnostics.Debugger.IsAttached)</pre>

  <pre class="alt"><span class="lnum">  37:  </span>            {</pre>

  <pre><span class="lnum">  38:  </span>                NavigationService.GoBack();</pre>

  <pre class="alt"><span class="lnum">  39:  </span>            }</pre>

  <pre><span class="lnum">  40:  </span>        }</pre>

  <pre class="alt"><span class="lnum">  41:  </span>&#160;</pre>

  <pre><span class="lnum">  42:  </span>        <span class="kwrd">private</span> <span class="kwrd">void</span> HandleVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre class="alt"><span class="lnum">  43:  </span>        {</pre>

  <pre><span class="lnum">  44:  </span>            <span class="kwrd">if</span> (queryString[<span class="str">&quot;voiceCommandName&quot;</span>] == <span class="str">&quot;searchSite&quot;</span> &amp;&amp; </pre>

  <pre class="alt"><span class="lnum">  45:  </span>                queryString.ContainsKey(<span class="str">&quot;siteToSearch&quot;</span>))</pre>

  <pre><span class="lnum">  46:  </span>            {</pre>

  <pre class="alt"><span class="lnum">  47:  </span>                SearchSiteVoiceCommand(queryString);</pre>

  <pre><span class="lnum">  48:  </span>            }</pre>

  <pre class="alt"><span class="lnum">  49:  </span>        }</pre>

  <pre><span class="lnum">  50:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  51:  </span>        <span class="kwrd">private</span> async <span class="kwrd">void</span> SearchSiteVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre><span class="lnum">  52:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  53:  </span>            <span class="kwrd">string</span> text = await RecognizeTextFromWebSearchGrammar();</pre>

  <pre><span class="lnum">  54:  </span>            <span class="kwrd">if</span> (text != <span class="kwrd">null</span>)</pre>

  <pre class="alt"><span class="lnum">  55:  </span>            {</pre>

  <pre><span class="lnum">  56:  </span>                <span class="kwrd">string</span> siteName = queryString[<span class="str">&quot;siteToSearch&quot;</span>];</pre>

  <pre class="alt"><span class="lnum">  57:  </span>                await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Searching {0} for {1}&quot;</span>, siteName, text));</pre>

  <pre><span class="lnum">  58:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  59:  </span>                <span class="kwrd">string</span> siteUrlTemplate = GetUrlTemplateFromSiteName(siteName);</pre>

  <pre><span class="lnum">  60:  </span>                NavigateToUrl(<span class="kwrd">string</span>.Format(siteUrlTemplate, text, siteName));</pre>

  <pre class="alt"><span class="lnum">  61:  </span>            }</pre>

  <pre><span class="lnum">  62:  </span>        }</pre>

  <pre class="alt"><span class="lnum">  63:  </span>&#160;</pre>

  <pre><span class="lnum">  64:  </span>        <span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; RecognizeTextFromWebSearchGrammar()</pre>

  <pre class="alt"><span class="lnum">  65:  </span>        {</pre>

  <pre><span class="lnum">  66:  </span>            <span class="kwrd">string</span> text = <span class="kwrd">null</span>;</pre>

  <pre class="alt"><span class="lnum">  67:  </span>            <span class="kwrd">try</span></pre>

  <pre><span class="lnum">  68:  </span>            {</pre>

  <pre class="alt"><span class="lnum">  69:  </span>                SpeechRecognizerUI sr = <span class="kwrd">new</span> SpeechRecognizerUI();</pre>

  <pre><span class="lnum">  70:  </span>                sr.Recognizer.Grammars.AddGrammarFromPredefinedType(<span class="str">&quot;web&quot;</span>, SpeechPredefinedGrammar.WebSearch);</pre>

  <pre class="alt"><span class="lnum">  71:  </span>                sr.Settings.ListenText = <span class="str">&quot;Listening...&quot;</span>;</pre>

  <pre><span class="lnum">  72:  </span>                sr.Settings.ExampleText = <span class="str">&quot;Ex. \&quot;electronics\&quot;&quot;</span>;</pre>

  <pre class="alt"><span class="lnum">  73:  </span>                sr.Settings.ReadoutEnabled = <span class="kwrd">false</span>;</pre>

  <pre><span class="lnum">  74:  </span>                sr.Settings.ShowConfirmation = <span class="kwrd">false</span>;</pre>

  <pre class="alt"><span class="lnum">  75:  </span>&#160;</pre>

  <pre><span class="lnum">  76:  </span>                SpeechRecognitionUIResult result = await sr.RecognizeWithUIAsync();</pre>

  <pre class="alt"><span class="lnum">  77:  </span>                <span class="kwrd">if</span> (result != <span class="kwrd">null</span> &amp;&amp; </pre>

  <pre><span class="lnum">  78:  </span>                    result.ResultStatus == SpeechRecognitionUIStatus.Succeeded &amp;&amp;</pre>

  <pre class="alt"><span class="lnum">  79:  </span>                    result.RecognitionResult != <span class="kwrd">null</span> &amp;&amp;</pre>

  <pre><span class="lnum">  80:  </span>                    result.RecognitionResult.TextConfidence != SpeechRecognitionConfidence.Rejected)</pre>

  <pre class="alt"><span class="lnum">  81:  </span>                {</pre>

  <pre><span class="lnum">  82:  </span>                    text = result.RecognitionResult.Text;</pre>

  <pre class="alt"><span class="lnum">  83:  </span>                }</pre>

  <pre><span class="lnum">  84:  </span>            }</pre>

  <pre class="alt"><span class="lnum">  85:  </span>            <span class="kwrd">catch</span> </pre>

  <pre><span class="lnum">  86:  </span>            {</pre>

  <pre class="alt"><span class="lnum">  87:  </span>            }</pre>

  <pre><span class="lnum">  88:  </span>            <span class="kwrd">return</span> text;</pre>

  <pre class="alt"><span class="lnum">  89:  </span>        }</pre>

  <pre><span class="lnum">  90:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  91:  </span>        <span class="kwrd">private</span> async Task Speak(<span class="kwrd">string</span> text)</pre>

  <pre><span class="lnum">  92:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  93:  </span>            SpeechSynthesizer tts = <span class="kwrd">new</span> SpeechSynthesizer();</pre>

  <pre><span class="lnum">  94:  </span>            await tts.SpeakTextAsync(text);</pre>

  <pre class="alt"><span class="lnum">  95:  </span>        }</pre>

  <pre><span class="lnum">  96:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  97:  </span>        <span class="kwrd">private</span> <span class="kwrd">void</span> NavigateToUrl(<span class="kwrd">string</span> url)</pre>

  <pre><span class="lnum">  98:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  99:  </span>            WebBrowserTask task = <span class="kwrd">new</span> WebBrowserTask();</pre>

  <pre><span class="lnum"> 100:  </span>            task.Uri = <span class="kwrd">new</span> Uri(url, UriKind.Absolute);</pre>

  <pre class="alt"><span class="lnum"> 101:  </span>            task.Show();</pre>

  <pre><span class="lnum"> 102:  </span>        }</pre>

  <pre class="alt"><span class="lnum"> 103:  </span>&#160;</pre>

  <pre><span class="lnum"> 104:  </span>        <span class="kwrd">private</span> <span class="kwrd">string</span> GetUrlTemplateFromSiteName(<span class="kwrd">string</span> siteName)</pre>

  <pre class="alt"><span class="lnum"> 105:  </span>        {</pre>

  <pre><span class="lnum"> 106:  </span>            <span class="kwrd">return</span> _siteUrlTemplateDictionary.ContainsKey(siteName)</pre>

  <pre class="alt"><span class="lnum"> 107:  </span>                ? _siteUrlTemplateDictionary[siteName]</pre>

  <pre><span class="lnum"> 108:  </span>                : <span class="kwrd">string</span>.Format(_defaultUrlTemplateForUnknownSites, siteName + <span class="str">&quot;%20{1}&quot;</span>);</pre>

  <pre class="alt"><span class="lnum"> 109:  </span>        }</pre>

  <pre><span class="lnum"> 110:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum"> 111:  </span>        <span class="kwrd">private</span> <span class="kwrd">string</span> _defaultUrlForNewNavigations = <span class="str">&quot;http://m.bing.com/search?q=Rob's%20Rhapsody%20Windows%20Phone%208%20site:blogs.msdn.com&quot;</span>;</pre>

  <pre><span class="lnum"> 112:  </span>        <span class="kwrd">private</span> <span class="kwrd">string</span> _defaultUrlTemplateForUnknownSites = <span class="str">&quot;http://m.bing.com/search?q={0}&quot;</span>;</pre>

  <pre class="alt"><span class="lnum"> 113:  </span>&#160;</pre>

  <pre><span class="lnum"> 114:  </span>        <span class="kwrd">private</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; _siteUrlTemplateDictionary = <span class="kwrd">new</span> Dictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt;()</pre>

  <pre class="alt"><span class="lnum"> 115:  </span>        {</pre>

  <pre><span class="lnum"> 116:  </span>            { <span class="str">&quot;Amazon&quot;</span>, <span class="str">&quot;http://www.amazon.com/gp/aw/s/ref=is_box_?k={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum"> 117:  </span>            { <span class="str">&quot;Bing&quot;</span>, <span class="str">&quot;http://www.bing.com/?q={0}&quot;</span> },</pre>

  <pre><span class="lnum"> 118:  </span>            { <span class="str">&quot;CNN&quot;</span>, <span class="str">&quot;http://www.cnn.com/search/?query={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum"> 119:  </span>            { <span class="str">&quot;Dictionary.com&quot;</span>, <span class="str">&quot;http://dictionary.reference.com/browse/{0}&quot;</span> },</pre>

  <pre><span class="lnum"> 120:  </span>            { <span class="str">&quot;Ebay&quot;</span>, <span class="str">&quot;http://www.ebay.com/sch/i.html?_nkw={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum"> 121:  </span>            { <span class="str">&quot;Facebook&quot;</span>, <span class="str">&quot;http://www.facebook.com/search/results.php?q={0}&quot;</span> },</pre>

  <pre><span class="lnum"> 122:  </span>            { <span class="str">&quot;Google&quot;</span>, <span class="str">&quot;https://www.google.com/search?hl=en&amp;q={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum"> 123:  </span>            { <span class="str">&quot;Hulu&quot;</span>, <span class="str">&quot;http://www.hulu.com/#!search?q={0}&quot;</span> },</pre>

  <pre><span class="lnum"> 124:  </span>            { <span class="str">&quot;IMDB&quot;</span>, <span class="str">&quot;http://www.imdb.com/find?s=all&amp;q={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum"> 125:  </span>            { <span class="str">&quot;Linked In&quot;</span>, <span class="str">&quot;http://www.linkedin.com/search/fpsearch?keywords={0}&quot;</span> },</pre>

  <pre><span class="lnum"> 126:  </span>            { <span class="str">&quot;MSN&quot;</span>, <span class="str">&quot;http://www.bing.com/search?scope=msn&amp;q={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum"> 127:  </span>            { <span class="str">&quot;Twitter&quot;</span>, <span class="str">&quot;https://twitter.com/search/{0}&quot;</span> },</pre>

  <pre><span class="lnum"> 128:  </span>            { <span class="str">&quot;Weather&quot;</span>, <span class="str">&quot;http://www.weather.com/info/sitesearch?q={0}&quot;</span> },</pre>

  <pre class="alt"><span class="lnum"> 129:  </span>            { <span class="str">&quot;YouTube&quot;</span>, <span class="str">&quot;https://www.youtube.com/results?search_query={0}&quot;</span> },</pre>

  <pre><span class="lnum"> 130:  </span>            { <span class="str">&quot;Zillow&quot;</span>, <span class="str">&quot;http://www.zillow.com/homes/{0}/&quot;</span> },</pre>

  <pre class="alt"><span class="lnum"> 131:  </span>        };</pre>

  <pre><span class="lnum"> 132:  </span>    }</pre>

  <pre class="alt"><span class="lnum"> 133:  </span>}</pre>
</div>

<p><strong>vcd.xml</strong></p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">&lt;?</span><span class="html">xml</span> <span class="attr">version</span><span class="kwrd">=&quot;1.0&quot;</span> <span class="attr">encoding</span><span class="kwrd">=&quot;utf-8&quot;</span>?<span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   2:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">&lt;</span><span class="html">VoiceCommands</span> <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/voicecommands/1.0&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">&lt;</span><span class="html">CommandSet</span> <span class="attr">xml:lang</span><span class="kwrd">=&quot;en-US&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   6:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    <span class="kwrd">&lt;</span><span class="html">CommandPrefix</span><span class="kwrd">&gt;</span>Search On<span class="kwrd">&lt;/</span><span class="html">CommandPrefix</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   8:  </span>    <span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>Amazon, Bing, CNN, Dictionary.com, Ebay, Facebook, MSN, Twitter, Weather.com, YouTube, or Zillow<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   9:  </span>&#160;</pre>

  <pre><span class="lnum">  10:  </span>    <span class="kwrd">&lt;</span><span class="html">Command</span> <span class="attr">Name</span><span class="kwrd">=&quot;searchSite&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  11:  </span>      <span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>Amazon, Bing, CNN, Dictionary.com, Ebay, Facebook, MSN, Twitter, Weather.com, YouTube, or Zillow<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  12:  </span>      <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{siteToSearch}<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  13:  </span>      <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>{siteToSearch} dot com<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  14:  </span>      <span class="kwrd">&lt;</span><span class="html">Feedback</span><span class="kwrd">&gt;</span>Search on {siteToSearch} for what?<span class="kwrd">&lt;/</span><span class="html">Feedback</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  15:  </span>      <span class="kwrd">&lt;</span><span class="html">Navigate</span> <span class="attr">Target</span><span class="kwrd">=&quot;MainPage.xaml&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre><span class="lnum">  16:  </span>    <span class="kwrd">&lt;/</span><span class="html">Command</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  17:  </span>&#160;</pre>

  <pre><span class="lnum">  18:  </span>    <span class="kwrd">&lt;</span><span class="html">PhraseList</span> <span class="attr">Label</span><span class="kwrd">=&quot;siteToSearch&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  19:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Amazon<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  20:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Bing<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  21:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>CNN<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  22:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Dictionary.com<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  23:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Ebay<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  24:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Facebook<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  25:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Google<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  26:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Hulu<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  27:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>IMDB<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  28:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Kayak<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  29:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Linked In<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  30:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>MSN<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  31:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Netflix<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  32:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Twitter<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  33:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Weather.com<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  34:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>YouTube<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  35:  </span>      <span class="kwrd">&lt;</span><span class="html">Item</span><span class="kwrd">&gt;</span>Zillow<span class="kwrd">&lt;/</span><span class="html">Item</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  36:  </span>    <span class="kwrd">&lt;/</span><span class="html">PhraseList</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  37:  </span>&#160;</pre>

  <pre><span class="lnum">  38:  </span>  <span class="kwrd">&lt;/</span><span class="html">CommandSet</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  39:  </span>&#160;</pre>

  <pre><span class="lnum">  40:  </span><span class="kwrd">&lt;/</span><span class="html">VoiceCommands</span><span class="kwrd">&gt;</span></pre>
</div>]]></content:encoded>
    </item>
    <item>
      <title>How many lines of code does it take to build a complete WP8 speech app?</title>
      <link>https://docs.microsoft.com/archive/blogs/robch/how-many-lines-of-code-does-it-take-to-build-a-complete-wp8-speech-app</link>
      <pubDate>Tue, 06 Nov 2012 15:31:18 GMT</pubDate>
      <dc:creator><![CDATA[Rob Chambers]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/robch/2012/11/06/how-many-lines-of-code-does-it-take-to-build-a-complete-wp8-speech-app/</guid>
      <description><![CDATA[In today's post, I'm going to show you how to use the three different parts of the speech platform...]]></description>
      <content:encoded><![CDATA[  <p>In today's post, I'm going to show you how to use the three different parts of the speech platform on Windows Phone 8.0: Voice Commands, Speech Recognition, and Speech Synthesis. To do that, we're going to build an actual application, that has real value, but hopefully will be less than 100 lines of code.</p>  <p>Ready? Here we go ...</p>  <p>Here's the plan: Let's build an application that let's the user search Amazon.com for anything they'd like to find, all by simply using their voice. Here's the flow we'll enable today:</p>  <blockquote>   <p><strong>User: </strong>&quot;Search On Amazon&quot;       <br /><strong>Phone: </strong>&quot;What would you like to search for on Amazon?&quot;       <br /><strong>User: </strong>&quot;Electronics&quot; (or whatever they want)       <br /><strong>Phone: </strong>&quot;Searching Amazon for Electronics&quot; (or whatever they said they wanted)</p> </blockquote>  <p>Sound interesting? Great.</p>  <p>First, let's start off by launching Visual Studio, and creating a new Windows Phone App project.</p>  <blockquote></blockquote>  <blockquote>   <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/8103.image_5B37D677.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/8103.image_5F00_5B37D677.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/1072.image_thumb_13764D90.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/1072.image_5F00_thumb_5F00_13764D90.png" width="484" height="274" /></a></p> </blockquote>  <p>Then, we'll update the application's manifest, so we can use speech in our project. </p>  <blockquote>   <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/4212.image_012D86CE.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/4212.image_5F00_012D86CE.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/7848.image_thumb_19BD241E.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/7848.image_5F00_thumb_5F00_19BD241E.png" width="484" height="274" /></a></p> </blockquote>  <p>On the Capabilities tab, click the checkmark next to the Microphone and Speech Recognition items. This tells the Market Place, at application submission time, that your app needs these capabilities. That way, the Market Place can be transparent to the end user, letting them know what your app is really going to do.</p>  <blockquote>   <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/4621.image_408B3A5E.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/4621.image_5F00_408B3A5E.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/6763.image_thumb_0B127839.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/6763.image_5F00_thumb_5F00_0B127839.png" width="484" height="274" /></a>       <br /></p> </blockquote>  <p>Next, let's add the XML file that specifies what voice commands you want users to be able to say. From the Solution Explorer, add a new item to your project, and select the Voice Command Definition item template.    <br /></p>  <blockquote>   <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/3716.image_63D82F03.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/3716.image_5F00_63D82F03.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/6862.image_thumb_3F46A17F.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/6862.image_5F00_thumb_5F00_3F46A17F.png" width="484" height="274" /></a></p>    <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/3125.image_180C584A.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/3125.image_5F00_180C584A.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/5775.image_thumb_4997C5DF.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/5775.image_5F00_thumb_5F00_4997C5DF.png" width="484" height="274" /></a></p> </blockquote>  <p>The default template shows a few examples of what you can do. In a future post, I'll describe in more detail what each XML element does, and why they're important for your application. </p>  <p>For the app we're building today, simply type the following XML into the editor. As you're typing, notice that intellisense is active, making suggestions for you along the way, making it fairly easy to build your own XML file from the ground up.</p>  <div class="csharpcode">   <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">&lt;?</span><span class="html">xml</span> <span class="attr">version</span><span class="kwrd">=&quot;1.0&quot;</span> <span class="attr">encoding</span><span class="kwrd">=&quot;utf-8&quot;</span>?<span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   2:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">&lt;</span><span class="html">VoiceCommands</span> <span class="attr">xmlns</span><span class="kwrd">=&quot;http://schemas.microsoft.com/voicecommands/1.0&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>  <span class="kwrd">&lt;</span><span class="html">CommandSet</span> <span class="attr">xml:lang</span><span class="kwrd">=&quot;en-US&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   6:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    <span class="kwrd">&lt;</span><span class="html">CommandPrefix</span><span class="kwrd">&gt;</span>Search On<span class="kwrd">&lt;/</span><span class="html">CommandPrefix</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">   8:  </span>    <span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>Amazon<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">   9:  </span>&#160;</pre>

  <pre><span class="lnum">  10:  </span>    <span class="kwrd">&lt;</span><span class="html">Command</span> <span class="attr">Name</span><span class="kwrd">=&quot;searchSite&quot;</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  11:  </span>      <span class="kwrd">&lt;</span><span class="html">Example</span><span class="kwrd">&gt;</span>Amazon<span class="kwrd">&lt;/</span><span class="html">Example</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  12:  </span>      <span class="kwrd">&lt;</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span>Amazon<span class="kwrd">&lt;/</span><span class="html">ListenFor</span><span class="kwrd">&gt;</span></pre>

  <pre class="alt"><span class="lnum">  13:  </span>      <span class="kwrd">&lt;</span><span class="html">Feedback</span><span class="kwrd">&gt;</span>What would you like to search for on Amazon<span class="kwrd">&lt;/</span><span class="html">Feedback</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  14:  </span>      <span class="kwrd">&lt;</span><span class="html">Navigate</span> <span class="attr">Target</span><span class="kwrd">=&quot;MainPage.xaml&quot;</span> <span class="kwrd">/&gt;</span></pre>

  <pre class="alt"><span class="lnum">  15:  </span>    <span class="kwrd">&lt;/</span><span class="html">Command</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  16:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  17:  </span>  <span class="kwrd">&lt;/</span><span class="html">CommandSet</span><span class="kwrd">&gt;</span></pre>

  <pre><span class="lnum">  18:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  19:  </span><span class="kwrd">&lt;/</span><span class="html">VoiceCommands</span><span class="kwrd">&gt;</span></pre>
</div>

<p>Now that we have a Voice Command Definition file (often referred to as a VCD file), let's open up the MainPage.xaml.cs file to get ready to start writing some actual code! Now, go ahead and remove all the unnecessary comments. That'll help us achieve our 100 line count goal. :-)</p>

<blockquote>
  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/5466.image_69469FA7.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/5466.image_5F00_69469FA7.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/2555.image_thumb_3D95D5AB.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/2555.image_5F00_thumb_5F00_3D95D5AB.png" width="484" height="274" /></a></p>
</blockquote>

<p>Add the following using namespace statements; we need all of these for the code that follows. The first three are namespaces for the three areas of the speech platform on Windows Phone 8.0. The next namespace, System.Threading.Tasks, is needed so we can create our own asynchronous methods that we can call using the new C# await keyword. The last new namespace we'll use today, Microsoft.Phone.Tasks, will help us launch the WP8's version of Internet Explorer, allowing the user to go directly to Amazon's mobile website. </p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">using</span> Windows.Phone.Speech.VoiceCommands;</pre>

  <pre><span class="lnum">   2:  </span><span class="kwrd">using</span> Windows.Phone.Speech.Recognition;</pre>

  <pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">using</span> Windows.Phone.Speech.Synthesis;</pre>

  <pre><span class="lnum">   4:  </span><span class="kwrd">using</span> System.Threading.Tasks;</pre>

  <pre class="alt"><span class="lnum">   5:  </span><span class="kwrd">using</span> Microsoft.Phone.Tasks;</pre>
</div>

<p>Now, let's install the voice commands we've defined up above. To do that, add a line of code to the constructor of our page, after InitializeComponent, that will install our voice command definitions.</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">public</span> MainPage()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    InitializeComponent();</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    VoiceCommandService.InstallCommandSetsFromFileAsync(</pre>

  <pre><span class="lnum">   6:  </span>        <span class="kwrd">new</span> Uri(<span class="str">&quot;ms-appx:///vcd.xml&quot;</span>));</pre>

  <pre class="alt"><span class="lnum">   7:  </span>}</pre>
</div>

<p>Don't worry about keeping track of whether you've installed the VCD file before, or not, for now. The VoiceCommandService will do the right thing if you've already installed the voice commands. If you update the VCD file in your application, and hit F5, the new voice commands will be registered. But if nothing has changed since the last call to InstallCommandSetsFromFileAsync, the VoiceCommandService is smart enough to detect that no work is necessary. </p>

<p>Now that our voice commands are installed, how do we know when a user spoke one of our commands? Great question. That's where the existing OnNavigatedTo method comes in.</p>

<p>When a user speaks a voice command, the VoiceCommandService matches what the user said, with all the phrases you've previously registered when you called InstallCommandSetsFromFileAsync. If the VoiceCommandService determines that it's one of your commands, it will launch your application, on the page specified in your Navigate XML element's Target attribute. </p>

<p>So, let's go ahead and override the OnNavigatedTo protected method. </p>

<blockquote>
  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/4212.image_016A0A03.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/4212.image_5F00_016A0A03.png"><img title="image" style="display: inline; background-image: none;" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/46/88/metablogapi/8510.image_thumb_07B0E091.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-46-88-metablogapi/8510.image_5F00_thumb_5F00_07B0E091.png" width="484" height="274" /></a> 

    <br /></p>
</blockquote>

<p>When OnNavigatedTo is called, we'll be able to tell it's a &quot;New&quot; navigation, as opposed to a &quot;Back&quot;, or a &quot;Refresh&quot;, by using the NavigationMode enumeration. The event args also contain the entire query string, broken up into an IDictionary of strings. If a query string parameter named &quot;voiceCommandName&quot; is present in that dictionary, you'll know that you've been launched by the VoiceCommandService. The value of that item in the dictionary will tell you which voice command the user has spoken. </p>

<p>So ... In our version of OnNavigatedTo, we'll check to see if it's a new navigation, and that if it's a voice command, and if so, we'll pass the query string dictionary off to another method to actually handle the voice command(s) there. </p>

<p>If OnNavigatedTo is being called for some other reason, you wouldn't normally do what I'm doing here. However, to keep our app as simple as possible, we're simply going to launch IE on Amazon.com's mobile web page. </p>

<p>Also, for this simple application, there's no reason for us to be on the back stack, so we'll try to get ourselves off the back stack. Since I don't know of a clean way to do that, I've opted to call GoBack on the NavigationService, which conceptually makes sense, but will actually throw an exception since we nothing is on the back stack. That's OK for this sample app, because it has the same desired effect. </p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">base</span>.OnNavigatedTo(e);</pre>

  <pre><span class="lnum">   4:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New &amp;&amp; </pre>

  <pre><span class="lnum">   6:  </span>        NavigationContext.QueryString.ContainsKey(<span class="str">&quot;voiceCommandName&quot;</span>))</pre>

  <pre class="alt"><span class="lnum">   7:  </span>    {</pre>

  <pre><span class="lnum">   8:  </span>        HandleVoiceCommand(NavigationContext.QueryString);</pre>

  <pre class="alt"><span class="lnum">   9:  </span>    }</pre>

  <pre><span class="lnum">  10:  </span>    <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New)</pre>

  <pre class="alt"><span class="lnum">  11:  </span>    {</pre>

  <pre><span class="lnum">  12:  </span>        NavigateToUrl(<span class="str">&quot;http://m.amazon.com&quot;</span>);</pre>

  <pre class="alt"><span class="lnum">  13:  </span>    }</pre>

  <pre><span class="lnum">  14:  </span>    <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.Back &amp;&amp; </pre>

  <pre class="alt"><span class="lnum">  15:  </span>                !System.Diagnostics.Debugger.IsAttached)</pre>

  <pre><span class="lnum">  16:  </span>    {</pre>

  <pre class="alt"><span class="lnum">  17:  </span>        NavigationService.GoBack();</pre>

  <pre><span class="lnum">  18:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  19:  </span>}</pre>
</div>

<p>Now, let's add the method to dispatch the voice commands. For now, we only have one voice command, but, like I said, we'll add more voice commands in the next post. Structuring the code this way up front, will save us a little time later.</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> HandleVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">if</span> (queryString[<span class="str">&quot;voiceCommandName&quot;</span>] == <span class="str">&quot;searchSite&quot;</span>)</pre>

  <pre><span class="lnum">   4:  </span>    {</pre>

  <pre class="alt"><span class="lnum">   5:  </span>        SearchSiteVoiceCommand(queryString);</pre>

  <pre><span class="lnum">   6:  </span>    }</pre>

  <pre class="alt"><span class="lnum">   7:  </span>}</pre>
</div>

<p>OK. Now, let's actually do the site search. But, wait a minute We don't know what the user wants to search for yet. Right?</p>

<p>Let's pick up there, where the VoiceCommandService left off in the conversation with the user. After speaking, &quot;Search On Amazon&quot;, they'll hear the prompt of &quot;What would you like to search for on Amazon&quot;, due to our &lt;example&gt; element in the VCD file for the searchSite &lt;command&gt;. </p>

<p>So, let's add a new method to handle the conversation, starting at that point, breaking it up into 3 logical pieces.</p>

<p>First, we'll get some text from the speech recognizer. Then, if it recognized something, we'll let the user know what we're doing by telling them that we're about to do the search. Finally, we'll navigate to the site to actually do the search.</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> async <span class="kwrd">void</span> SearchSiteVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">string</span> text = await RecognizeTextFromWebSearchGrammar();</pre>

  <pre><span class="lnum">   4:  </span>    <span class="kwrd">if</span> (text != <span class="kwrd">null</span>)</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    {</pre>

  <pre><span class="lnum">   6:  </span>        await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Searching Amazon for {0}&quot;</span>, text));</pre>

  <pre class="alt"><span class="lnum">   7:  </span>        NavigateToUrl(<span class="kwrd">string</span>.Format(<span class="str">&quot;http://www.amazon.com/gp/aw/s/ref=is_box_?k={0}&quot;</span>, text));</pre>

  <pre><span class="lnum">   8:  </span>    }</pre>

  <pre class="alt"><span class="lnum">   9:  </span>}</pre>
</div>

<p>OK. Time to use the Speech Recognition APIs. Again, in a future post, I'll describe in more detail what all the various parameters and features, and why we have them as options in the namespace. But for now, just type the following code into Visual Studio:</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; RecognizeTextFromWebSearchGrammar()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">string</span> text = <span class="kwrd">null</span>;</pre>

  <pre><span class="lnum">   4:  </span>    <span class="kwrd">try</span></pre>

  <pre class="alt"><span class="lnum">   5:  </span>    {</pre>

  <pre><span class="lnum">   6:  </span>        SpeechRecognizerUI sr = <span class="kwrd">new</span> SpeechRecognizerUI();</pre>

  <pre class="alt"><span class="lnum">   7:  </span>        sr.Recognizer.Grammars.AddGrammarFromPredefinedType(<span class="str">&quot;web&quot;</span>, SpeechPredefinedGrammar.WebSearch);</pre>

  <pre><span class="lnum">   8:  </span>        sr.Settings.ListenText = <span class="str">&quot;Listening...&quot;</span>;</pre>

  <pre class="alt"><span class="lnum">   9:  </span>        sr.Settings.ExampleText = <span class="str">&quot;Ex. \&quot;electronics\&quot;&quot;</span>;</pre>

  <pre><span class="lnum">  10:  </span>        sr.Settings.ReadoutEnabled = <span class="kwrd">false</span>;</pre>

  <pre class="alt"><span class="lnum">  11:  </span>        sr.Settings.ShowConfirmation = <span class="kwrd">false</span>;</pre>

  <pre><span class="lnum">  12:  </span>&#160;</pre>

  <pre class="alt"><span class="lnum">  13:  </span>        SpeechRecognitionUIResult result = await sr.RecognizeWithUIAsync();</pre>

  <pre><span class="lnum">  14:  </span>        <span class="kwrd">if</span> (result != <span class="kwrd">null</span> &amp;&amp; </pre>

  <pre class="alt"><span class="lnum">  15:  </span>            result.ResultStatus == SpeechRecognitionUIStatus.Succeeded &amp;&amp;</pre>

  <pre><span class="lnum">  16:  </span>            result.RecognitionResult != <span class="kwrd">null</span> &amp;&amp;</pre>

  <pre class="alt"><span class="lnum">  17:  </span>            result.RecognitionResult.TextConfidence != SpeechRecognitionConfidence.Rejected)</pre>

  <pre><span class="lnum">  18:  </span>        {</pre>

  <pre class="alt"><span class="lnum">  19:  </span>            text = result.RecognitionResult.Text;</pre>

  <pre><span class="lnum">  20:  </span>        }</pre>

  <pre class="alt"><span class="lnum">  21:  </span>    }</pre>

  <pre><span class="lnum">  22:  </span>    <span class="kwrd">catch</span> </pre>

  <pre class="alt"><span class="lnum">  23:  </span>    {</pre>

  <pre><span class="lnum">  24:  </span>    }</pre>

  <pre class="alt"><span class="lnum">  25:  </span>    <span class="kwrd">return</span> text;</pre>

  <pre><span class="lnum">  26:  </span>}</pre>
</div>

<p>Similarly, here's the method that we'll use to speak the feedback to the end user, using the built in SpeechSynthesizer. It's simpler than using the SpeechRecognizer. Synthesis, often called TTS, or Text-To-Speech, usually is more straight forward from a programmatic standpoint.</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> async Task Speak(<span class="kwrd">string</span> text)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    SpeechSynthesizer tts = <span class="kwrd">new</span> SpeechSynthesizer();</pre>

  <pre><span class="lnum">   4:  </span>    await tts.SpeakTextAsync(text);</pre>

  <pre class="alt"><span class="lnum">   5:  </span>}</pre>
</div>

<p>And finally, here's the method we'll use to navigate to the specified URL.</p>

<div class="csharpcode">
  <pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> NavigateToUrl(<span class="kwrd">string</span> url)</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre class="alt"><span class="lnum">   3:  </span>    WebBrowserTask task = <span class="kwrd">new</span> WebBrowserTask();</pre>

  <pre><span class="lnum">   4:  </span>    task.Uri = <span class="kwrd">new</span> Uri(url, UriKind.Absolute);</pre>

  <pre class="alt"><span class="lnum">   5:  </span>    task.Show();</pre>

  <pre><span class="lnum">   6:  </span>}</pre>
</div>

<p>That's it. 100 lines of code. Exactly! Not bad, eh? :-)</p>

<p>Oh yeah ... In my application, I've also removed nearly all the UI elements from the XAML file (MainPage.xaml), so it's not distracting to the user to see while the speech conversation is happening. Typically, you'd actually have a real page, but... This is just a 100 line sample. Right? :-)</p>

<p>OK. Time to try it out. If you haven't typed it all in yet, you can go ahead and <strike>cheat </strike>copy and paste the code from below. Be sure and remember to do the first few steps, declaring the capabilities required, otherwise you’ll get an Unauthorized exception when you try to call the Speech Recognition APIs.&#160; </p>

<p>Press F5, and you should land in the Emulator, on Amazon's web page. </p>

<p>Great. Our Voice Commands should be installed now.</p>

<p>Now, press and hold the Start button (the middle hardware button beneath the screen), and wait for the Speech &quot;Listening...&quot; screen to pop up. If you haven't run speech in the emulator yet, you'll need to accept the speech terms of use. Let's follow the script from above now:</p>

<blockquote>
  <p><strong>You: </strong>&quot;Search On Amazon&quot; 

    <br /><strong>Phone: </strong>&quot;What would you like to search for on Amazon?&quot; 

    <br /><strong>You: </strong>&quot;Electronics&quot; (or whatever you want) 

    <br /><strong>Phone: </strong>&quot;Searching Amazon for Electronics&quot; (or whatever you said you wanted)</p>
</blockquote>

<p>Sometimes when you're using a fresh copy of the emulator, or if you haven't accepted the terms of use yet, you'll have to wait a few seconds for the voice commands to become active. If it doesn't work the first time, try try again. Or at least, try twice. :-)</p>

<p>That's it. You have now completed a reasonably useful speech enabled application for Windows Phone 8.0. In 100 lines of code.</p>

<p>Here's the full code listing:</p>

<div class="csharpcode">
  <pre class="alt"><span class="kwrd">using</span> System;</pre>

  <pre><span class="kwrd">using</span> System.Collections.Generic;</pre>

  <pre class="alt"><span class="kwrd">using</span> System.Net;</pre>

  <pre><span class="kwrd">using</span> System.Windows;</pre>

  <pre class="alt"><span class="kwrd">using</span> System.Windows.Navigation;</pre>

  <pre><span class="kwrd">using</span> Microsoft.Phone.Controls;</pre>

  <pre class="alt"><span class="kwrd">using</span> Windows.Phone.Speech.VoiceCommands;</pre>

  <pre><span class="kwrd">using</span> Windows.Phone.Speech.Recognition;</pre>

  <pre class="alt"><span class="kwrd">using</span> Windows.Phone.Speech.Synthesis;</pre>

  <pre><span class="kwrd">using</span> System.Threading.Tasks;</pre>

  <pre class="alt"><span class="kwrd">using</span> Microsoft.Phone.Tasks;</pre>

  <pre>&#160;</pre>

  <pre class="alt"><span class="kwrd">namespace</span> SearchOn</pre>

  <pre>{</pre>

  <pre class="alt">    <span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> MainPage : PhoneApplicationPage</pre>

  <pre>    {</pre>

  <pre class="alt">        <span class="kwrd">public</span> MainPage()</pre>

  <pre>        {</pre>

  <pre class="alt">            InitializeComponent();</pre>

  <pre>&#160;</pre>

  <pre class="alt">            VoiceCommandService.InstallCommandSetsFromFileAsync(<span class="kwrd">new</span> Uri(<span class="str">&quot;ms-appx:///vcd.xml&quot;</span>));</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnNavigatedTo(NavigationEventArgs e)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">base</span>.OnNavigatedTo(e);</pre>

  <pre class="alt">&#160;</pre>

  <pre>            <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New &amp;&amp; NavigationContext.QueryString.ContainsKey(<span class="str">&quot;voiceCommandName&quot;</span>))</pre>

  <pre class="alt">            {</pre>

  <pre>                HandleVoiceCommand(NavigationContext.QueryString);</pre>

  <pre class="alt">            }</pre>

  <pre>            <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.New)</pre>

  <pre class="alt">            {</pre>

  <pre>                NavigateToUrl(<span class="str">&quot;http://m.amazon.com&quot;</span>);</pre>

  <pre class="alt">            }</pre>

  <pre>            <span class="kwrd">else</span> <span class="kwrd">if</span> (e.NavigationMode == NavigationMode.Back &amp;&amp; !System.Diagnostics.Debugger.IsAttached)</pre>

  <pre class="alt">            {</pre>

  <pre>                NavigationService.GoBack();</pre>

  <pre class="alt">            }</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> <span class="kwrd">void</span> HandleVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">if</span> (queryString[<span class="str">&quot;voiceCommandName&quot;</span>] == <span class="str">&quot;searchSite&quot;</span>)</pre>

  <pre class="alt">            {</pre>

  <pre>                SearchSiteVoiceCommand(queryString);</pre>

  <pre class="alt">            }</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> async <span class="kwrd">void</span> SearchSiteVoiceCommand(IDictionary&lt;<span class="kwrd">string</span>, <span class="kwrd">string</span>&gt; queryString)</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">string</span> text = await RecognizeTextFromWebSearchGrammar();</pre>

  <pre class="alt">            <span class="kwrd">if</span> (text != <span class="kwrd">null</span>)</pre>

  <pre>            {</pre>

  <pre class="alt">                await Speak(<span class="kwrd">string</span>.Format(<span class="str">&quot;Searching Amazon for {0}&quot;</span>, text));</pre>

  <pre>                NavigateToUrl(<span class="kwrd">string</span>.Format(<span class="str">&quot;http://www.amazon.com/gp/aw/s/ref=is_box_?k={0}&quot;</span>, text));</pre>

  <pre class="alt">            }</pre>

  <pre>        }</pre>

  <pre class="alt">&#160;</pre>

  <pre>        <span class="kwrd">private</span> async Task&lt;<span class="kwrd">string</span>&gt; RecognizeTextFromWebSearchGrammar()</pre>

  <pre class="alt">        {</pre>

  <pre>            <span class="kwrd">string</span> text = <span class="kwrd">null</span>;</pre>

  <pre class="alt">            <span class="kwrd">try</span></pre>

  <pre>            {</pre>

  <pre class="alt">                SpeechRecognizerUI sr = <span class="kwrd">new</span> SpeechRecognizerUI();</pre>

  <pre>                sr.Recognizer.Grammars.AddGrammarFromPredefinedType(<span class="str">&quot;web&quot;</span>, SpeechPredefinedGrammar.WebSearch);</pre>

  <pre class="alt">                sr.Settings.ListenText = <span class="str">&quot;Listening...&quot;</span>;</pre>

  <pre>                sr.Settings.ExampleText = <span class="str">&quot;Ex. \&quot;electronics\&quot;&quot;</span>;</pre>

  <pre class="alt">                sr.Settings.ReadoutEnabled = <span class="kwrd">false</span>;</pre>

  <pre>                sr.Settings.ShowConfirmation = <span class="kwrd">false</span>;</pre>

  <pre class="alt">&#160;</pre>

  <pre>                SpeechRecognitionUIResult result = await sr.RecognizeWithUIAsync();</pre>

  <pre class="alt">                <span class="kwrd">if</span> (result != <span class="kwrd">null</span> &amp;&amp; </pre>

  <pre>                    result.ResultStatus == SpeechRecognitionUIStatus.Succeeded &amp;&amp;</pre>

  <pre class="alt">                    result.RecognitionResult != <span class="kwrd">null</span> &amp;&amp;</pre>

  <pre>                    result.RecognitionResult.TextConfidence != SpeechRecognitionConfidence.Rejected)</pre>

  <pre class="alt">                {</pre>

  <pre>                    text = result.RecognitionResult.Text;</pre>

  <pre class="alt">                }</pre>

  <pre>            }</pre>

  <pre class="alt">            <span class="kwrd">catch</span> </pre>

  <pre>            {</pre>

  <pre class="alt">            }</pre>

  <pre>            <span class="kwrd">return</span> text;</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> async Task Speak(<span class="kwrd">string</span> text)</pre>

  <pre>        {</pre>

  <pre class="alt">            SpeechSynthesizer tts = <span class="kwrd">new</span> SpeechSynthesizer();</pre>

  <pre>            await tts.SpeakTextAsync(text);</pre>

  <pre class="alt">        }</pre>

  <pre>&#160;</pre>

  <pre class="alt">        <span class="kwrd">private</span> <span class="kwrd">void</span> NavigateToUrl(<span class="kwrd">string</span> url)</pre>

  <pre>        {</pre>

  <pre class="alt">            WebBrowserTask task = <span class="kwrd">new</span> WebBrowserTask();</pre>

  <pre>            task.Uri = <span class="kwrd">new</span> Uri(url, UriKind.Absolute);</pre>

  <pre class="alt">            task.Show();</pre>

  <pre>        }</pre>

  <pre class="alt">    }</pre>

  <pre>}</pre>
</div>]]></content:encoded>
    </item>
    <item>
      <title>Windows Phone 8 is here! Start speech enabling your apps…</title>
      <link>https://docs.microsoft.com/archive/blogs/robch/windows-phone-8-is-here-start-speech-enabling-your-apps</link>
      <pubDate>Thu, 01 Nov 2012 14:30:00 GMT</pubDate>
      <dc:creator><![CDATA[Rob Chambers]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/robch/2012/11/01/windows-phone-8-is-here-start-speech-enabling-your-apps/</guid>
      <description><![CDATA[It&rsquo;s time to start speech enabling your Windows Phone applications, developers!
In...]]></description>
      <content:encoded><![CDATA[<p>It&rsquo;s time to start speech enabling your Windows Phone applications, developers!</p>
<p>In today&rsquo;s post, I&rsquo;ll kick things off by consolidating and linking to a bunch of different resources that you can use to get started. I&rsquo;ll also show you a real world application, that&rsquo;s not a toy / sample app, that I&rsquo;ve built using the same APIs you all have access to right now. From that, you can see what&rsquo;s possible in a relatively short amount of time, and hopefully it&rsquo;ll inspire you to think about what you can do in your applications. Over the coming weeks, I&rsquo;ll dig into that application, piece by piece, and tell you exactly how you can do the same thing. We&rsquo;ll probably end up with 10-15 posts total on the topic, having covered the basics in the first few posts, and covering some of the lower level details in the ones that follow.</p>
<p>So &hellip; Let&rsquo;s start by taking a look at that real world application. It&rsquo;s called Tivo Command. Take a look at the video, <a href="http://www.thinkman.com/tivo/tivovid.mp4">here</a>, or embedded below, then continue on with the rest of post. :-)</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/pbIhpEQPISw" frameborder="0" allowfullscreen=""></iframe></p>
<p>Finished watching the demo of Tivo Command? Does it give you some ideas of things you could do in your apps? Want to add some speech features to your app?</p>
<p>OK. Here we go &hellip;</p>
<p>First, as a developer, you might want to read Kevin Gallo&rsquo;s <a href="http://blogs.windows.com/windows_phone/b/wpdev/archive/2012/10/30/announcing-the-new-windows-phone-8-developer-platform.aspx">post from Tuesday this week</a>, where he announced the Windows Phone 8 Developer Platform&rsquo;s availability. Then, you probably should take a look at <a href="http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff402529(v=vs.105).aspx">the Getting Started with Development for Windows Phone 8.0 guide</a> on the new <a href="http://dev.windowsphone.com/">Windows Phone Dev Center</a>. That&rsquo;s where you&rsquo;ll learn where you can download the SDK and tools, register your phone as a developer, and learn how to either build your first Windows Phone application, or migrate your existing Windows Phone 7 application to Windows Phone 8.</p>
<p>Next up, you probably want to take a look at <a href="http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206940(v=vs.105).aspx">What's new in the Windows Phone 8.0 SDK</a>, to learn about all the cool new capabilities, like native code support, in app purchases, NFC support, custom app notifications and custom wallpaper. Of course, IMHO, the coolest feature of all of these is the new speech platform that all developers can take advantage of.</p>
<p>After reading the <a href="http://msdn.microsoft.com/en-US/library/windowsphone/develop/jj206958(v=vs.105).aspx">overview for Speech in Windows Phone 8</a>, you&rsquo;ll see that there are 3 main areas of investment that you can take advantage of in your apps running on Windows Phone 8: <a href="http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206959(v=vs.105).aspx">Voice Commands</a>, <a href="http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207021(v=vs.105).aspx">Speech Recognition</a>, and <a href="http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207057(v=vs.105).aspx">Speech Synthesis</a>.</p>
<p>Last but not least, you should read thru the <a href="http://msdn.microsoft.com/en-us/library/windowsphone/design/jj720572(v=vs.105).aspx">Speech Design Guidelines</a> also on the Dev Center.</p>
<p>Of course, we also have all the APIs documented here:</p>
<ul>
<li><a title="http://msdn.microsoft.com/en-us/library/windowsphone/develop/windows.phone.speech.voicecommands(v=vs.105).aspx" href="http://msdn.microsoft.com/en-us/library/windowsphone/develop/windows.phone.speech.voicecommands(v=vs.105).aspx">Voice Commands API Reference</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/windowsphone/develop/windows.phone.speech.recognition(v=vs.105).aspx">Speech Recognition API Reference</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/windowsphone/develop/windows.phone.speech.synthesis(v=vs.105).aspx">Speech Synthesis API Reference</a></li>
</ul>
<p>That should be enough for one day, right? In upcoming posts I&rsquo;ll start tearing apart Tivo Command v8 and show exactly how I added all the speech capabilities, using the Windows Phone 8.0 SDK.</p>
<p>Let me know if you have any questions in the comments below&hellip;</p>]]></content:encoded>
    </item>
    <item>
      <title>Developers: Coming soon to a phone near you… Windows Phone 8</title>
      <link>https://docs.microsoft.com/archive/blogs/robch/developers-coming-soon-to-a-phone-near-you-windows-phone-8</link>
      <pubDate>Wed, 24 Oct 2012 12:54:25 GMT</pubDate>
      <dc:creator><![CDATA[Rob Chambers]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/robch/2012/10/24/developers-coming-soon-to-a-phone-near-you-windows-phone-8/</guid>
      <description><![CDATA[Windows Phone 8 is almost here!!     Joe Belfiore introduced Windows Phone 8 to the world in June,...]]></description>
      <content:encoded><![CDATA[<p><strong>Windows Phone 8 is almost here!!</strong></p>  <ul>   <li>Joe Belfiore <a href="http://blogs.windows.com/windows_phone/b/windowsphone/archive/2012/06/20/announcing-windows-phone-8.aspx">introduced</a> Windows Phone 8 to the world in June, 2012.</li>    <li>Kevin Gallo summarized <a href="http://blogs.windows.com/windows_phone/b/wpdev/archive/2012/06/29/recapping-windows-phone-8-developer-news.aspx">what’s new for developers</a>, just a week later.</li>    <li>The new <a href="http://dev.windowsphone.com/">Windows Phone Dev Center</a> came <a href="http://blogs.windows.com/windows_phone/b/wpdev/archive/2012/08/07/meet-the-windows-phone-dev-center.aspx">online</a> in August. </li>    <li>The <a href="http://blogs.windows.com/windows_phone/b/wpdev/archive/2012/09/12/windows-phone-8-sdk-preview-program-is-now-open.aspx">Windows Phone 8 SDK Preview program</a> was announced in September.</li>    <li>The <a href="http://www.windowsphone.com/en-us/news">Windows Phone 8 press event</a> is set for Monday, October 29th, 2012.</li> </ul>  <p><strong>Are you ready to get started?</strong></p>  <p>Fellow developers…</p>  <ul>   <li>Do you want your users to be able to quickly, naturally, and easily access your application’s most used features?</li>    <li>Do you want your application to be seamlessly integrated into the phone’s existing user experience?</li>    <li>Wouldn’t it be awesome to do that with the same Visual Studio tools you use today to make apps?</li>    <li>Don’t you wish you could do all that, in just a few minutes, instead of weeks, months, or years?</li> </ul>  <p>If you answered yes to all those questions, it sounds like you want to use our latest and greatest speech platform, included in Windows Phone 8. It’s the same platform we’ve used to enable Windows Phone 8’s built in speech experiences, like Voice Dialing, SMS play back and reply, and even Bing’s very own Voice Search.</p>  <p>Are you ready to get started? Yes? I’m ready to start showing you how … </p>  <p>Stay tuned; check back next week. I think you’ll be glad you did.</p>  <p>:-)</p>]]></content:encoded>
    </item>
    <item>
      <title>Windows Phone 7.5 (Mango) and Speech Recognition</title>
      <link>https://docs.microsoft.com/archive/blogs/robch/windows-phone-7-5-mango-and-speech-recognition</link>
      <pubDate>Tue, 13 Sep 2011 09:49:41 GMT</pubDate>
      <dc:creator><![CDATA[Rob Chambers]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/robch/2011/09/13/windows-phone-7-5-mango-and-speech-recognition/</guid>
      <description><![CDATA[Here at Microsoft we've been busy over the last year adding cool new speech features to a bunch of...]]></description>
      <content:encoded><![CDATA[<p>Here at Microsoft we've been busy over the last year adding cool new speech features to a bunch of Microsoft platforms and applications. You've undoubtedly heard about at least one of these recently (unless of course you live under a rock :-])...</p>
<p>One such example is the work we've done in Windows Phone 7.5 (aka Mango). Perhaps the sweetest new speech feature we've added to Windows Phone is the work we've done around the end to end experience of text messages. Instead of telling you about it myself, you should take a look at a recent article on ZDNet written by Matthew Miller. Check it out <a href="http://www.zdnet.com/blog/cell-phones/new-windows-phone-mango-speech-technology-cant-be-beat/6548">here</a>.</p>
<p>As always, we'd love to hear what you think, so drop us an <a href="mailto:listen@microsoft.com?subject=Windows Phone Speech">email</a>... We're listening...</p>]]></content:encoded>
    </item>
    <item>
      <title>Want to see what you can do with Speech across 3 screens and a cloud?</title>
      <link>https://docs.microsoft.com/archive/blogs/robch/want-to-see-what-you-can-do-with-speech-across-3-screens-and-a-cloud</link>
      <pubDate>Thu, 14 Jan 2010 12:24:00 GMT</pubDate>
      <dc:creator><![CDATA[Rob Chambers]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/robch/2010/01/14/want-to-see-what-you-can-do-with-speech-across-3-screens-and-a-cloud/</guid>
      <description><![CDATA[Happy 2010!
&nbsp;
I talked about what we’ve all been up to in 2009 in the Speech group on the...]]></description>
      <content:encoded><![CDATA[<P style="MARGIN: 0in 0in 0pt" class=MsoNormal><FONT size=3><FONT face=Calibri>Happy 2010!<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></FONT></FONT></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal><o:p><FONT size=3 face=Calibri>&nbsp;</FONT></o:p></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal><FONT size=3 face=Calibri>I talked about what we’ve all been up to in 2009 in the Speech group on the </FONT><A href="http://blogs.msdn.com/speech/archive/2010/01/08/happy-2010.aspx"><FONT size=3 face=Calibri>Speech Team blog</FONT></A><FONT size=3><FONT face=Calibri> the other day… Focusing across the 3 screens and a cloud... </FONT></FONT></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal><o:p><FONT size=3 face=Calibri>&nbsp;</FONT></o:p></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal><FONT size=3 face=Calibri>I also thought it’d be interesting to see the demo/video I put together on Channel 10 that demos some of that, and talks about how developers can take advantage of our speech platform. You can check it out </FONT><A href="http://on10.net/blogs/larry/A-Deeper-Look-at-Speech-NUI/"><FONT size=3 face=Calibri>here</FONT></A><FONT size=3><FONT face=Calibri>. <o:p></o:p></FONT></FONT></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal><o:p><FONT size=3 face=Calibri>&nbsp;</FONT></o:p></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal><A href="mailto:listen@microsoft.com"><FONT color=#0000ff size=3 face=Calibri>Let us</FONT></A><FONT size=3><FONT face=Calibri> know if you have any questions.</FONT></FONT></P>
<P style="MARGIN: 0in 0in 0pt" class=MsoNormal><FONT size=3><FONT face=Calibri><o:p></o:p></FONT></FONT>&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>Bing on the iPhone (with Voice Search!)</title>
      <link>https://docs.microsoft.com/archive/blogs/robch/bing-on-the-iphone-with-voice-search</link>
      <pubDate>Wed, 16 Dec 2009 08:45:59 GMT</pubDate>
      <dc:creator><![CDATA[Rob Chambers]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/robch/2009/12/16/bing-on-the-iphone-with-voice-search/</guid>
      <description><![CDATA[Microsoft's Bing for iPhone went live yesterday, and is now available in the iPhone application...]]></description>
      <content:encoded><![CDATA[<p>Microsoft's Bing for iPhone went live yesterday, and is now available in the iPhone application store. You can read more about it <a href="http://www.pcworld.com/article/184793/bing_gets_an_iphone_app.html">here</a> on PC World.com. I downloaded the app last night on my wife's iPhone and it's working great! </p>  <p>The Speech team here at Microsoft has been working with Bing on the Voice Search capabilities for a while now, and the whole team is excited that the latest version of our speech technology is powering the newest version of Bing's mobile client software. </p>  <p>I especially like how easily you can get to movies, stocks, and images, with simple voice commands. Download the app, and try it out for yourself. </p>  <p><a href="mailto:listen@microsoft.com?subject=Bing%20for%20the%20iPhone">Let us know</a> what you think of the Voice Search capabilities!</p>]]></content:encoded>
    </item>
  </channel>
</rss>