Category Archives: MVVM Light–Visual Studio 2013, Universal Apps

MVVM Light–Visual Studio 2013, Universal Apps, Windows Phone 8.1, Windows Store 8.1 Apps–Part 3 of N

In this part 3, let us see how to build a Universal Application for Windows Phone 8.1 and Windows 8.1 with MVVM Light support. We will also learn how to create a shared viewmodel layer, how to detect design mode and what the result is in Blend and at runtime.

In Part 2, we created a Universal Phone 8.1 app that still uses all the components present inside the project. We will use MVVM Light toolkit and remove some of the classes we created as well as code written in code behind files. Then we will make this a truly Universal App, which can be created for Windows Phone 8.1 and Windows 8.1.  This offers a nice way to structure your app in order to share as much code and other files (Views, View Models, etc) as possible. It makes it easier than ever to create apps which target both the Windows Phone 8.1 and the Windows RT devices like Surface, XBox.

MVVM is the design pattern used to develop apps in Windows Store apps as well as Windows Phone apps. Lets use MVVM Light framework to develop a windows store app. You can get the latest MVVM Light toolkit from http://mvvmlight.codeplex.com/

Creating the Application

Step 1: Open the project created in Part 2 using Visual Studio 2013.
Step 2: Right click on the References folder in the Windows Phone 8.1 application, and select Manage Nuget Packages.
Step 3: Select the Online source for Nuget and search for MVVM Light.
Step 4: Select the package MVVM Light Libraries only. Alternatively you can select the package named MVVM Light Libraries Only (PCL). This will install the exact same binaries and eventually I will remove this package and keep only the main one.
Step 5: Repeat steps 2 to 5 for the Windows 8.1 application.
Step 6: At this point, you have added MVVM Light support to both your applications as shown in Figure 1. Now we can add the files that will bring the full support for the ViewModel layer and the design support.

image

Figure 1: MVVM Light libraries referenced in Universal Projects in VS 2013

Adding ViewModel Layer:

it’s time to instantiate and create the ViewModels. This is the ViewModelLocator class task. This class is quite important in the application structure enabled by MVVM Light. It’s created as a XAML resource in the file App.xaml. This creates the important link between XAML markup and source code, allowing the visual designers to create the ViewModels and to run the design-time code. Lets create two files ViewModelLocator and the MainViewModel.

Adding ViewModelLocator & PersonViewModel:

The main task of ViewLocator is to link up your views with the view models. It’s responsible for creating and disposing of all of your View-Models. In this ViewLocator, mostly we just add additional views. Let’s do that.

The main task of ViewLocator is to link up your views with the view models. It’s responsible for creating and disposing of all of your View-Models. In this ViewLocator, mostly we just add additional views. Let’s do that.

Step 7: Right click on the Shared node and select Add, New Folder. Name this folder ViewModel.
Step 8: Right click on the new ViewModel again and select Add, New Item. Select a Class, and name it ViewModelLocator.cs
Step 9: Modify the ViewModelLocator code to look like in the code segment 1 below.
Step 8: Move the class PersonViewModel.cs from Windows Phone 8.1 to ViewModel present in shared node.
Step 9: Modify the MainViewModel class to look like code snippet 2 below. Of course you can add a bunch of new methods, observable properties and commands to this ViewModel as usual in MVVM.

Here I created PersonViewModelProp property that returns an instance of PersonViewModel and we registered this PersonViewModel class in line 23 of code snippet 1.

Code Snippet 1
  1. public class ViewModelLocator
  2.     {
  3.         public MainViewModel Main
  4.         {
  5.             get
  6.             {
  7.                 return ServiceLocator.Current.GetInstance<MainViewModel>();
  8.             }
  9.         }
  10.  
  11.         public PersonViewModel PersonViewModelProp
  12.         {
  13.             get
  14.             {
  15.                 return ServiceLocator.Current.GetInstance<PersonViewModel>();
  16.             }
  17.         }
  18.  
  19.         static ViewModelLocator()
  20.         {
  21.             ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  22.             SimpleIoc.Default.Register<MainViewModel>();
  23.             SimpleIoc.Default.Register<PersonViewModel>();
  24.         }
  25.     }

Code Snippet 1: ViewModelLocator

Code Snippet 2
  1. public class PersonViewModel : ViewModelBase
  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 = IsInDesignMode
  33.                                     ? "bill" : "Bill",
  34.                                       LastName = IsInDesignMode
  35.                                           ? "gates" : "Gates" });
  36.             _persons.Add(new Person { FirstName = "Steve", LastName = "Ballmer" });
  37.             Persons = _persons;
  38.             personObject = new Person { FirstName = "Satya", LastName = "Nadella" };
  39.             _savePersonCommand = new RelayCommand(SavePerson, CanSavePerson);
  40.         }
  41.  
  42.         private bool CanSavePerson()
  43.         {
  44.             if (string.IsNullOrEmpty(personObject.FirstName) || string.IsNullOrEmpty(personObject.LastName))
  45.                 return false;
  46.             else
  47.                 return true;
  48.         }
  49.  
  50.         private void SavePerson()
  51.         {
  52.             Persons.Add(new Person { FirstName = personObject.FirstName, LastName = personObject.LastName });
  53.             //MessageDialog dialog = new MessageDialog(string.Format("Saved: {0}  {0}", personObject.FirstName, personObject.LastName));
  54.             //await dialog.ShowAsync();
  55.  
  56.         }
  57.  
  58.  
  59.     }

Code Snippet 2: PersonViewModel

Adding Locator resource to App.XAML

Open the App.xaml file in Visual Studio 2013 and modify it to look like code snippet 3 below. This creates a new resource with the ViewModelLocator, which we will use in the designer. Notice the addition of the “d” and “mc” XML namespaces so that we can mark the ViewModelLocator as a DataSource, which will make it show up in the Data panel in Blend.

Code Snippet 3
  1. <Application
  2.     x:Class="UniBlank_MVVMBasics.App"
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  5.     xmlns:local="using:UniBlank_MVVMBasics"
  6.      xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot;
  7.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
  8.     mc:Ignorable="d"
  9.     xmlns:vm="using:UniBlank_MVVMBasics.ViewModel">
  10.     
  11.     <Application.Resources>
  12.         <vm:ViewModelLocator x:Key="Locator"
  13.                              d:IsDataSource="True"/>
  14.     </Application.Resources>
  15.  
  16. </Application>

Making it a truly Universal App:

Since there is nothing great we are doing here, we can easily make it a universal app with all the code shared between both the projects.  Move all the files that we created from Windows Phone 8.1 to Shared node as shown in Figure 2. Delete the files from Windows Phone 8.1 project. In Windows 8.1 project too, delete MainPage.XAML and hurray, we have our first universal app with MVVM. Now, Windows 8.1 store app begins to show up the same UI we have created for Windows Phone 8.1. Amazing!!!!

image

Figure 2: Moving files to Shared node for making this a Universal app code.

Connecting View and ViewModel:

Step 10: Set the DataContext of the Page to the MainViewMode as shown in Code Snippet 4.

Code Snippet 4
DataContext="{Binding PersonViewModelProp, Source={StaticResource Locator}}"

This is the complete code of PersonView User control.

Code Snippet
  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.     DataContext="{Binding PersonViewModelProp, Source={StaticResource Locator}}" >

Comment the code we wrote in PersonView.xaml.cs

Code Snippet
  1. private void UserControl_Loaded(object sender, RoutedEventArgs e)
  2.       {
  3.           //PersonViewModel personViewModelObject = new PersonViewModel();
  4.           //this.DataContext = personViewModelObject;
  5.       }

 

Download the source code from here.