Quantcast
Channel: MSDN Blogs
Viewing all articles
Browse latest Browse all 29128

WP8 Speech – Exploring the MVVM pattern

$
0
0

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.

If you haven’t read the earlier posts, you might want to take a few minutes and see where we left off.

Since those posts went live, I’ve completely re-written the application with a full blown UX.

And … It’s not just a sample application anymore, either. Its an actual, real, publically available application.

Go Search On is available in the Windows Phone Store as of today, and … It’s FREE!

Before we dive into the developer details, let’s take a look at the new features I’ve added:

  • Designed to be used with or without speech recognition
    • The main screen has a textbox for the site you’d like to search, and another for what you’d like to search for.
    • Either textbox can be filled with the soft keyboard or using speech via a buddy microphone icon.
    • The site to search textbox has autocomplete, based on the same site list that we use to populate the voice command’s phrase lists.
  • Demonstrates the “dialog” and “implicit confirmation” speech UX metaphors
    • After users issue a Go Search On voice command (e.g. “Go Search On Amazon.com”)
    • … the app prompts and collects the search terms,
    • … then, the app informs the user (both visually and verbally) what it’s about to do.
    • … e.g. “Searching on Amazon.com for Legos”
    • While the “confirmation” prompt is playing, the user can either…
    • … do nothing, and the search will take place once the prompt is complete, or
    • … cancel the task by clicking cancel, or by attempting to edit the site name or the search terms
  • Search more “sites”
    • 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.
    • I’ve also added the ability to search the Windows Phone App Store as well as Xbox Music Marketplace,
    • … using the phone’s built in UX.
  • User authentication to allow CRUD (create, read, update, delete) type operations on what sites are available to search on:
    • Authenticated users can add, edit, and delete their own personalized list of sites to search.
    • The authenticated “Admin” has the ability to update the list of sites that is common for all users.
    • Authentication is performed via the Windows Live SDK, allowing users to use their Microsoft Account credentials, where …
    • … the Live Authentication Client Session’s authentication token is used to authenticate with Azure’s Mobile Service.

OK … Now, on the developer aspects of “Go Search On” …

 

Go Search On – Exploring the MVVM pattern with WP8 and Speech

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?! :-)

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:

  • The basics – MVVM and Go Search On in it’s most simplistic high level form
    • The Model, View, and the View Model
    • XAML binding, Property change notifications, and Commands
    • Three different app interactions, with the same end result
  • And the rest …
    • 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.
    • XAML Value Converters – what are they, why use them, and a few helper classes I’ve created.
    • Implicit Confirmation UX – what is it, and how I’ve done it in an MVVM manner.
    • Authentication – Using Windows Live, integrated with the Azure Mobile Service, demonstrating connections into the MVVM world.
    • Autocomplete – Demonstrating how I’ve done it in an MVVM manner, sharing the underlying models.
    • Site Lists – Exposing the site lists for All Users and the Current User using MVVM.
    • CRUD in MVVM – Implications for a basic MVVM based UX managing data in the cloud.

Today, we’ll tackle the basics, and I’ll try to tackle the rest of the topics in future posts.

Go Search On and MVVM Basics

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, here.

Here’s my take on MVVM …

The View

In a Windows Phone MVVM application, the View is the collection of all XAML UIElements in a page, along with all associated code behind.

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.

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.

The View has 3 UI elements we’ll discuss in today’s post:

  • The “[what site?] AutoCompleteTextBox,
  • The “[what?] TextBox, and
  • The “Go!” Button.

3 - Main Screen - logged in

The Model

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.

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).

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.

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.

image

The View Model

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.

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).

image

XAML Binding

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 here.

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.

We can achieve both of those goals by setting the Text attribute on the AutoCompleteTextBox XML element as follows:

<AutoCompleteTextBox Text="{Binding SearchSiteName, Mode=TwoWay}" .../>

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:

<TextBoxText="{Binding SearchForWhat, Mode=TwoWay}" .../>

Now, let’s hook up the “Go!” Button:

<ButtonCommand="{Binding SearchNowCommand, Mode=OneWay}"Content="GO! ".../>

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:

<Gridx:Name="LayoutRoot"DataContext="{StaticResource _model}">

Just as you’d expect, that “_model” is of type SearchOnViewModel, declared in the Resources section of our XAML page like this:

<so:SearchOnViewModelx:Name="_model"/>

That’s all we need as far as the XAML file is concerned for today’s post.

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.

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.

diag4

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?

Good questions …

INotifyPropertyChanged

For binding to work properly in both directions, the public string properties can’t just be naked string properties.

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.

Here’s what that looks like for our View Model:

   1:  publicstring SearchSiteName
   2:  {
   3:      set { SetSearchSite(value); }
   4:      get { return GetSearchSite(); }
   5:  }
   6:   
   7:  publicstring SearchForWhat
   8:  {
   9:      set { SetSearchForWhat(value); }
  10:      get { return GetSearchForWhat(); }
  11:  }
  12:   
  13:  privatestring GetSearchSite()
  14:  {
  15:  return _searchSite;
  16:  }
  17:   
  18:  privatevoid SetSearchSite(string siteName)
  19:  {
  20:      _notifyHelper.UpdateValue(this, ref _searchSite, siteName, "SearchSiteName");
  21:  }
  22:   
  23:  privatestring GetSearchForWhat()
  24:  {
  25:  return _searchForWhat;
  26:  }
  27:   
  28:  privatevoid SetSearchForWhat(string s)
  29:  {
  30:      _notifyHelper.UpdateValue(this, ref _searchForWhat, s, "SearchForWhat");
  31:  }
  32:   
  33:  privatestring _searchSite = "[what site?]";
  34:  privatestring _searchForWhat = "[what?]";

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:

   1:  publicclass NotifyPropertyChangedHelper
   2:  {
   3:  publicevent PropertyChangedEventHandler PropertyChanged;
   4:   
   5:  #regionvalue setters
   6:   
   7:  publicvoid SetValue<T>(object sender, ref T value, T newValue, paramsstring[] propertyNames)
   8:      {
   9:  value = newValue;
  10:          NotifyPropertyChanged(sender, propertyNames);
  11:      }
  12:   
  13:  publicbool UpdateValue<T>(object sender, ref T value, T newValue, paramsstring[] propertyNames) where T : System.IComparable<T>
  14:      {
  15:  bool fChanged = false;
  16:   
  17:  if (value == null || value.CompareTo(newValue) != 0)
  18:          {
  19:              fChanged = true;
  20:  value = newValue;
  21:              NotifyPropertyChanged(sender, propertyNames);
  22:          }
  23:   
  24:  return fChanged;
  25:      }
  26:   
  27:  #endregion
  28:   
  29:  #region notify helpers
  30:   
  31:  publicvoid NotifyPropertyChanged(object sender, params String[] propertyNames)
  32:      {
  33:  foreach (string propertyName in propertyNames)
  34:          {
  35:              NotifyPropertyChanged(sender, propertyName);
  36:          }
  37:      }
  38:   
  39:  publicvoid NotifyPropertyChanged(object sender, String propertyName)
  40:      {
  41:          PropertyChangedEventHandler handler = PropertyChanged;
  42:   
  43:  if (null != handler)
  44:          {
  45:              handler(sender, new PropertyChangedEventArgs(propertyName));
  46:          }
  47:      }
  48:   
  49:  #endregion
  50:  }

You’ll also have to hook it up in your View Model’s class, like this:

   1:  #region Common INotifyPropertyChanged properties and data
   2:   
   3:  publicevent PropertyChangedEventHandler PropertyChanged
   4:  {
   5:      add
   6:      {
   7:          _notifyHelper.PropertyChanged += value;
   8:      }
   9:      remove
  10:      {
  11:          _notifyHelper.PropertyChanged -= value;
  12:      }
  13:  }
  14:   
  15:  private NotifyPropertyChangedHelper _notifyHelper = new NotifyPropertyChangedHelper();
  16:   
  17:  #endregion

 

ICommand

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.

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.

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.

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:

   1:  privatevoid InitCommands()
   2:  {
   3:      _commandSearchNow = new Command(
   4:  "Search Now", (object param) => { returntrue; }, 
   5:          (object param) => { SearchNowCommand_Execute(param); });

And, for that to work, let’s take a look at the Command helper class, in its entirety:

   1:  publicclass Command : ICommand
   2:  {
   3:  public Command(Command command)
   4:      {
   5:          _execute = command.Execute;
   6:          _canExecute = command.CanExecute;
   7:          _name = command.Name;
   8:      }
   9:   
  10:  public Command(string name, CanExecuteStart canExecute, ExecuteStart execute)
  11:      {
  12:          _execute = execute;
  13:          _canExecute = canExecute;
  14:          _name = name;
  15:      }
  16:   
  17:  publicstring Name { get { return _name; } }
  18:   
  19:  #region ICommand interface implementation
  20:   
  21:  publicevent EventHandler CanExecuteChanged;
  22:   
  23:  publicbool CanExecute(object parameter)
  24:      {
  25:  return _canExecute(parameter);
  26:      }
  27:   
  28:  publicvoid Execute(object parameter)
  29:      {
  30:          _execute(parameter);
  31:      }
  32:   
  33:  #endregion
  34:   
  35:  #region delegates
  36:   
  37:  publicdelegatebool CanExecuteStart(object parameter);
  38:  publicdelegatevoid ExecuteStart(object parameter);
  39:   
  40:  #endregion
  41:   
  42:  #regionprivate data
  43:   
  44:  privatestring _name;
  45:  private CanExecuteStart _canExecute;
  46:  private ExecuteStart _execute;
  47:   
  48:  #endregion
  49:  }

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.

OK … Back to Go Search On …

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.

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.

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.

   1:  privateasync void SearchNowCommand_Execute(object param)
   2:  {
   3:      SetSearchNowCommandIsVisible(false);
   4:      SetCancelSearchNowCommandIsVisible(true);
   5:   
   6:  if (IsSearchSiteDefaultOrEmpty())
   7:      {
   8:          SetSearchSite(await _model.GetSearchSiteViaSpeech(true));
   9:      }
  10:   
  11:  if (!IsSearchSiteDefaultOrEmpty() && IsSearchForWhatDefaultOrEmpty())
  12:      {
  13:          SetSearchForWhat(await _model.GetSearchForWhatViaSpeech(GetSearchSite(), true));
  14:      }
  15:   
  16:  if (!IsSearchSiteDefaultOrEmpty() && !IsSearchForWhatDefaultOrEmpty())
  17:      {
  18:  await SearchSiteForTextNow(GetSearchSite(), GetSearchForWhat());
  19:      }
  20:   
  21:      SetSearchNowCommandIsVisible(true);
  22:  }

Now, finally, inside SearchSiteForTextNow, we call the CreateNewSearchTask method on the underlying Model.

   1:  privateasync Task SearchSiteForTextNow(string siteName, string findText)
   2:  {
   3:      SetSearchNowCommandIsVisible(false);
   4:   
   5:  try
   6:      {
   7:          _model.CreateNewSearchTask(siteName, findText);

 

3 user scenarios, 1 view model, 1 model implementation

Now, you might be wondering, why is it good to use MVVM. “This is a lot of code, Rob!!” Yes, you’re right!

To  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:

  1. User invokes app, fills in each field, clicks Go button
  2. User invokes app, clicks Go button right away
  3. User uses a voice command to invoke app (e.g. “Go Search On Amazon.com”)

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.

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.

OK .. On to the three scenarios…

User invokes app, fills in each field, clicks Go button

Here’s the basic flow of the app in this scenario:

  1. Application starts, initializing the View (aka MainPage)
  • The View ensures that the View Model has been created
  • The View Model ensures that the Model has been created
  • MainPage.OnNavigated is called
    • App could have been invoked by a voice command, or normally
    • MainPage.OnNavigated determines invocation is not a voice command invocation
    • … Calls the View’s HandleNonVoiceCommandInvocation
    • … … calls the View Model’s EnsureVoiceCommandsInstalled
    • … … … calls _Model’s EnsureVoiceCommandsInstalledAsync
    • The Model ensures that the voice commands have been installed, and the Phrase Lists are all up to date (similar to previous post)
  • MainPage is Loaded
    • XAML binding updates …
    • … AutoCompleteTextBox.Text property from
    • … … View Model’s SearchSiteName string value (which defaultly is “[what site?]”
    • … TextBox.Text property from
    • … … View Model’s SearchForWhat string value (which defaultly is “[what?]”
  • User types in site name, clicks back to dismiss keyboard
    • AutoCompleteTextBox.Text property is updated
    • … XAML binding updates …
    • … … View Model’s SearchSiteName string value
  • User types in "for what" text, clicks back to dismiss keyboard
    • TextBox.Text property is updated
    • … XAML binding updates …
    • … … View Model’s SearchForWhat string value
  • User clicks on Go button   
    • XAML Button click logic calls ICommand.Execute
    • … Calls the View Model’s SearchNowCommand_Execute method
    • … … calls the View Model’s SearchSiteForTextNow passing SearchSiteName and SearchForWhat
    • … … … calls the Model’s CreateNewSearchTask with passed SearchSiteName and SearchForWhat

    User invokes app, clicks Go button right away

    Now, what if the user just clicks Go right away? Its very similar to the previous flow, except, as noted above, we’ll make sure that the SearchSiteName and SearchForWhat properties are not empty and aren’t the defaults. If they are, down in step 4 below, we’ll use the Model to ask the user via the WP8 speech APIs.

    1. Application starts, initializing the View (aka MainPage)
    • The View ensures that the View Model has been created
    • The View Model ensures that the Model has been created
  • MainPage.OnNavigated is called
    • App could have been invoked by a voice command, or normally
    • MainPage.OnNavigated determines invocation is not a voice command invocation
    • … Calls the View’s HandleNonVoiceCommandInvocation
    • … … calls the View Model’s EnsureVoiceCommandsInstalled
    • … … … calls _Model’s EnsureVoiceCommandsInstalledAsync
    • The Model ensures that the voice commands have been installed, and the Phrase Lists are all up to date (similar to previous post)
  • MainPage is Loaded
    • Binding updates …
    • … AutoCompleteTextBox.Text property from
    • … … View Model’s SearchSiteName string value (which defaultly is “[what site?]”
    • … TextBox.Text property from
    • … … View Model’s SearchForWhat string value (which defaultly is “[what?]”
  • User clicks on Go button   
    • XAML Button click logic calls ICommand.Execute
    • … Calls the View Model’s SearchNowCommand_Execute method, which
    • … … calls the Model’s _GetSearchSiteViaSpeech method and updates the SearchSiteName property
    • … … … which notifies the XAML binding, updating the AutoCompleteTextBox.Text property
    • … … calls the Model’s GetSearchForWhatViaSpeech method, and updates the SearchForWhat property
    • … … … which notifies the XAML binding, updating the TextBox.Text property
    • … … and finally …
    • … … calls the View Model’s SearchSiteForTextNow passing SearchSiteName and SearchForWhat
    • … … … which calls the Model’s CreateNewSearchTask with passed SearchSiteName and SearchForWhat

    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.

    User uses a voice command to invoke the app (e.g. “Go Search On Amazon.com” )

    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.

    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 … ;-)

    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.

    We’ll take advantage of that facility to make our Voice Commands look like Button Commands, passing the query string as the single parameter.

    Here’s what that’ll look like:

       1:  privatevoid VoiceCommandServiceCommand_Execute(object param)
       2:  {
       3:      IDictionary<string, string> queryString = param as IDictionary<string, string>;
       4:  if (queryString != null)
       5:      {
       6:          VoiceCommandServiceCommand_Execute(queryString);
       7:      }
       8:  }
       9:   
      10:  privatevoid VoiceCommandServiceCommand_Execute(IDictionary<string, string> queryString)
      11:  {
      12:  switch (queryString["voiceCommandName"])
      13:      {
      14:  case"searchSite":
      15:  case"searchSiteCatchAll":
      16:  case"searchSiteCatchAll2":
      17:  case"searchSiteCatchAll3":
      18:  case"searchSiteCatchAll4":
      19:  case"searchSiteCatchAll5":
      20:  case"searchSiteCatchAll6":
      21:  case"searchSiteCatchAll7":
      22:              SearchSiteVoiceCommand_Execute(queryString);
      23:  break;
      24:      }
      25:  }
      26:   
      27:  privateasync void SearchSiteVoiceCommand_Execute(IDictionary<string, string> queryString)
      28:  {
      29:      SetSearchNowCommandIsVisible(false);
      30:      SetCancelSearchNowCommandIsVisible(true);
      31:   
      32:      SetSearchSite(
      33:          queryString.ContainsKey("siteToSearch")
      34:              ? queryString["siteToSearch"]
      35:              : await _model.GetSearchSiteViaSpeech(false));
      36:   
      37:  if (!IsSearchSiteDefaultOrEmpty())
      38:      {
      39:  bool fVoiceCommandServiceAlreadyPrompted = queryString.ContainsKey("siteToSearch");
      40:          SetSearchForWhat(await _model.GetSearchForWhatViaSpeech(GetSearchSite(), !fVoiceCommandServiceAlreadyPrompted));
      41:      }
      42:   
      43:  if (!IsSearchSiteDefaultOrEmpty() && !IsSearchForWhatDefaultOrEmpty())
      44:      {
      45:  await SearchSiteForTextNow(GetSearchSite(), GetSearchForWhat());
      46:      }
      47:   
      48:      SetSearchNowCommandIsVisible(true);
      49:  }

    There are a couple key differences between the implementations of the SearchNowCommand_Execute method and our new SearchSiteVoiceCommand_Execute method. In our new SearchSiteVoiceCommand_Execute method:

    1. We need to set the SearchSiteName based on the Voice Command query string parameter named “siteToSearch”.
    • If we don’t have one of those, we’ll use Speech to get one, just like the 2nd scenario
  • When we try and get the SearchForWhat via Speech, we might not want to prompt.
    • If we hit the wildcard voice command case,
    • … we’ll collect the SearchSiteName, after the VCD TextFeedback prompted the user for that.
    • Then, we’ll have to prompt the user directly, ourselves, for the SearchForWhat text,
    • … with a prompt like “Search Amazon.com for what?”

    OK. Now with that, let’s look at the entire app flow for this 3rd scenario:

    1. Application starts, initializing the View (aka MainPage)
    • The View ensures that the View Model has been created
    • The View Model ensures that the Model has been created
  • MainPage.OnNavigated is called
    • App could have been invoked by a voice command, or normally
    • MainPage.OnNavigated determines invocation is a voice command invocation
    • … Calls the View’s HandleVoiceCommandInvocation
    • … … calls the ICommand.Execute for the ICommand obtained from SearchOnViewModel.VoiceCommand
    • … … … calls the View Model’s VoiceCommandServiceCommand_Execute method
    • … … … … calls the View Model’s SearchSiteVoiceCommand_Execute method
  • Meanwhile, MainPage is Loaded
    • Binding updates …
    • … AutoCompleteTextBox.Text property from
    • … … View Model’s SearchSiteName string value (which defaultly is “[what site?]”
    • … TextBox.Text property from
    • … … View Model’s SearchForWhat string value (which defaultly is “[what?]”
  • SearchSiteVoiceCommand_Execute continues
    • … … calls the Model’s GetSearchSiteViaSpeech method and updates the SearchSiteName property
    • … … … which notifies the XAML binding, updating the AutoCompleteTextBox.Text property
    • … … calls the Model’s GetSearchForWhatViaSpeech method, and updates the SearchForWhat property
    • … … … which notifies the XAML binding, updating the TextBox.Text property
    • … … and finally …
    • … … calls the View Model’s SearchSiteForTextNow passing SearchSiteName and SearchForWhat
    • … … … which calls the Model’s CreateNewSearchTask with passed SearchSiteName and SearchForWhat

    The End!

    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 here. 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?

    And … You can download the app from the Windows Phone Marketplace here, as well.

    I hope you find the app, the source, and the blog post useful. ;-)


    Viewing all articles
    Browse latest Browse all 29128

    Trending Articles



    <script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>