Getting Started with Visual Studio 2013, Windows Phone 8.1, Window Store 8.1, MVVM –Part 2 of N

 

In Part 1, we have seen how to write code in Model, view and viewmodel to wire up data and show it in the UI. There is a clear separation among the three layers. Now let us extend the sample and see how we can implement commanding. We will just add a Save button and when the user clicks Save, add a record to ObservableCollection and the UI automatically shows the data.

Step 1: Add a new class called DelegateCommand.cs and inherit from ICommand

DelegateCommand.cs
  1. public class DelegateCommand : ICommand
  2.     {
  3.         private readonly Action<object> _executeMethod = null;
  4.         private readonly Predicate<object> _canExecuteMethod = null;
  5.         private bool _isAutomaticRequeryDisabled = false;
  6.  
  7.         public DelegateCommand(Action<Object> executeMethod, Predicate<object> canExecuteMethod, bool isAutomaticRequeryDisabled)
  8.         {
  9.             if (executeMethod == null)
  10.             {
  11.                 throw new ArgumentNullException("executeMethod is null. Please set executeMethod.");
  12.             }
  13.             _executeMethod = executeMethod;
  14.             _canExecuteMethod = canExecuteMethod;
  15.             _isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
  16.         }
  17.  
  18.         public bool CanExecute(object parameter)
  19.         {
  20.             return _canExecuteMethod == null ? true : _canExecuteMethod(parameter);
  21.         }
  22.  
  23.         public event EventHandler CanExecuteChanged;
  24.  
  25.         public void Execute(object parameter)
  26.         {
  27.             if (_executeMethod != null)
  28.                 _executeMethod(parameter);
  29.         }
  30.  
  31.         //In WinRT, there is no CommandManager to raise events globally. you must update/raise CanExecuteChanged manually
  32.         public void RaiseCanExecuteChanged()
  33.         {
  34.             if (CanExecuteChanged != null)
  35.                 CanExecuteChanged(this, EventArgs.Empty);
  36.         }
  37.  
  38.     }

Step 2: Modify the person class created in Part 1 to includes command for Save.

PersonViewModel.cs
  1. public class PersonViewModel
  2.     {
  3.         public ObservableCollection<Person> Persons
  4.         {
  5.             get;
  6.             set;
  7.         }
  8.  
  9.         public Person personObject
  10.         {
  11.             get;
  12.             set;
  13.         }
  14.  
  15.  
  16.         private ICommand _savePersonCommand;
  17.         public ICommand SavePersonCommand
  18.         {
  19.             get
  20.             {
  21.                 return _savePersonCommand;
  22.             }
  23.  
  24.             set
  25.             {
  26.                 _savePersonCommand = value;
  27.             }
  28.         }
  29.         public PersonViewModel()
  30.         {
  31.             ObservableCollection<Person> _persons = new ObservableCollection<Person>();
  32.             _persons.Add(new Person { FirstName = "Bill", LastName = "Gates" });
  33.             _persons.Add(new Person { FirstName = "Steve", LastName = "Ballmer" });
  34.             Persons = _persons;
  35.             personObject = new Person { FirstName = "Satya", LastName = "Nadella" };
  36.             _savePersonCommand = new DelegateCommand(SavePerson, CanSavePerson, false);
  37.         }
  38.  
  39.         private bool CanSavePerson(object obj)
  40.         {
  41.             if (string.IsNullOrEmpty(personObject.FirstName) || string.IsNullOrEmpty(personObject.LastName))
  42.                 return false;
  43.             else
  44.                 return true;
  45.         }
  46.  
  47.         private void SavePerson(object obj)
  48.         {
  49.             Persons.Add(new Person { FirstName = personObject.FirstName, LastName = personObject.LastName });
  50.             //MessageDialog dialog = new MessageDialog(string.Format("Saved: {0}  {0}", personObject.FirstName, personObject.LastName));
  51.             //await dialog.ShowAsync();
  52.  
  53.         }
  54.  
  55.  
  56.     }

Step 3: Add a button to UserControl in PersonView.xaml and add Command property from viewmodel.

PersonView.xaml
  1. <UserControl
  2.     x:Class="UniBlank_MVVMBasics.PersonView"
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  5.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot;
  6.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
  7.     mc:Ignorable="d"
  8.     d:DesignHeight="300"
  9.     d:DesignWidth="400" Loaded="UserControl_Loaded"
  10.     xmlns:local="using:UniBlank_MVVMBasics">
  11.     <Grid>
  12.         <StackPanel HorizontalAlignment="Left">
  13.             <ListView ItemsSource="{Binding Path=Persons, Mode=TwoWay}">
  14.                 <ListView.ItemTemplate>
  15.                     <DataTemplate>
  16.                         <StackPanel Orientation="Horizontal" Margin="20,20,0,0">
  17.                             <TextBlock Margin="10,0,20,0" Text="{Binding Path=FirstName, Mode=TwoWay}" Style="{StaticResource HeaderTextBlockStyle}"></TextBlock>
  18.                             <TextBlock Text="{Binding Path=LastName, Mode=TwoWay}" Style="{StaticResource HeaderTextBlockStyle}"></TextBlock>
  19.                         </StackPanel>
  20.                     </DataTemplate>
  21.                 </ListView.ItemTemplate>
  22.             </ListView>
  23.         </StackPanel>
  24.  
  25.         <StackPanel>
  26.              <Button Content="Save" HorizontalAlignment="Right" Width="80" Command="{Binding Path=SavePersonCommand}"/>
  27.         </StackPanel>
  28.  
  29.     </Grid>
  30. </UserControl>

Note: In WinRT, you must update/raise CanExecuteChanged manually. There is no CommandManager to do this globally. You could look at this as a pain in the neck, or a serious performance boost now that CanExecute is not called constantly. It does mean you have to think about cascading property changes where before you did not have to. But this is how it is. Manual.

Download the source code from here.

Advertisements

2 thoughts on “Getting Started with Visual Studio 2013, Windows Phone 8.1, Window Store 8.1, MVVM –Part 2 of N

  1. Pingback: MVVM Light–Visual Studio 2013, Universal Apps, Windows Phone 8.1, Windows Store 8.1 Apps–Part 3 of N | Software Architect, Technology Evangelist, Technology Consultant

  2. name withheld

    Thanks for the instructions, I found them really helpful.
    Just as note you don;’t mention the change required for UserControl_Loaded in the PersonView.xaml.cs file in the article above (though it is in the source code).

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s