In the next few posts we'll dive into the basics of using the MVVM Light Toolkit with Windows 10 to build a simple project two-page with the MVVM design pattern. Today we'll show how to setup the toolkit in a Windows 10 project, and some of the basic components you'll need to define to follow the MVVM pattern.
MVVM
A complete discussion of the MVVM pattern is outside the scope of this document, so if you are new to the concept and want to learn more I suggest taking a look at articles like this one on MSDN: The MVVM Pattern and this blog on using MVVM with WPF: WPF Apps With The Model-View-ViewModel Design Pattern, the concepts of which are certainly still applicable to Windows Store Apps.
Many implementations of the MVVM pattern are available, such as Prism, and some developers even choose to roll their own framework. However, for this and all future posts, we'll be using the MVVM Light Toolkit.
The MVVM Light Toolkit
The MVVM Light Toolkit is an open-source framework for building applications using the MVVM Pattern. Originally available for Silverlight, Windows Store and Windows Phone, it has since been expanded to cover cross-platform devices including iOS and Android via Xamarin. Although we'll dive deeper into supporting other platforms in a later post, we'll get an early start by leveraging support of MVVM Light for Portable projects, and add a seperate library to contain the Models, ViewModels, and other code we will eventually share with other platforms.
Note that we've selected the Class Library (Portable) template, which prompts us to select the appropriate targets.
Since the portable project condenses all the APIs to the minimum supported version, selecting Windows 10 as a target actually also allows you to target Windows 8 (and of course, 8.1) meaning that if you wanted to cover these platforms while the Windows 10 roll-out continues, you are certainly able to do so! The same goes for Windows Phone, and as you can see in the screenshot above, our project can also support running on Android and iOS via the Xamarin Platform.
Installing MVVM Light via NuGet
Installing MVVM Light is actually quite simple thanks to NuGet. Simply open the NuGet Explorer and search for "mvvmlight", installing the package named "MvvmLightLibs" to both the main app and the portable project.
This registers the portable portions of the project (such as ObservableObject and ViewModelBase) into all projects as well as the platform-specific implementations (such as the NavigationService we'll be looking at in a future post) into the Windows project. Any time you want to target an additional platform, be sure to install this package to that project as well to enjoy all the benefits of MVVM Light on that platform!
Now that we have the required libraries in place, we can proceed to build the infrastructure for the app by adding a simple Model, ViewModels, and Views.
Create a Sample Model
The first thing we need is a sample data model to represent a simple item to display on the page. In a real-world project this might be a blog post served from an RSS feed or a To-do item from an external API. For now we'll just declare a simple item to display a few properties by adding the following model class to our portable project:
public class TestItem
{
public int Id { get; set; }
public string Title { get; set; }
public string Subtitle { get; set; }
public string HexColor { get; set; }
}
Create Pages (Views)
Next we need to actually display this information in the app, which we'll do by adding some pages in the Windows project. We already have the blank MainPage that was added by default (which we've moved into a Views folder), so we'll simply add a second page with some placeholder controls to display the model.
<Page
x:Class="Win10MvvmLight.Views.SecondPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Win10MvvmLight.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Background="{Binding SelectedItem.HexColor}" Padding="20">
<TextBlock Text="Second Page" Style="{ThemeResource TitleTextBlockStyle}" />
<TextBlock Style="{ThemeResource HeaderTextBlockStyle}" Foreground="White" />
<TextBlock Style="{ThemeResource SubheaderTextBlockStyle}" Foreground="White" />
</StackPanel>
</Page>
We'll look at the XAML we'll need for the MainPage in our next post, as well as how to wire the pages up to the properties of the model, but now that we've got both the model and views defined, let's fill in the last part of the pattern by creating some ViewModels to link it all together.
Create the ViewModels
Generally you want to make sure each View (Page) is associated with a specific ViewModel, so we'll create one for each of the pages in our app. We also want to make sure that we include common required behavior like the implementation of INotifyPropertyChanged.
Fortunately MVVM Light helps by including the ViewModelBase from which we can inherit all our ViewModels. In our case, we'll go one step further by putting a BaseViewModel in between, so we can share additional global requirements like a helpful IsLoading property for showing or hiding a loading animation (which we'll demonstrate in a later post).
public class BaseViewModel : ViewModelBase
{
private bool isLoading;
public virtual bool IsLoading
{
get { return isLoading; }
set
{
isLoading = value;
RaisePropertyChanged();
}
}
}
Now we can proceed to create the MainPageViewModel, which presents a simple list of TestItem objects (which we'll populate in our next post). Note that we use the ObservableCollection as this allows the view to automatically be notified when the collection changes.
public class MainPageViewModel : BaseViewModel
{
private ObservableCollection<TestItem> testItems = new ObservableCollection<TestItem>();
public ObservableCollection<TestItem> TestItems
{
get { return testItems; }
set
{
testItems = value;
RaisePropertyChanged();
}
}
}
We also need a SecondPageViewModel to show the selected item, exposed as a simple property:
public class SecondPageViewModel : BaseViewModel
{
private TestItem selectedItem;
public TestItem SelectedItem
{
get { return selectedItem; }
set
{
selectedItem = value;
RaisePropertyChanged();
}
}
}
Now that we have defined all of the Model, Views, and ViewModels required by our app, we need a way to wire them all together, so that each page is aware of its assigned ViewModel from which to retrieve its data.
There are several possible strategies, such as loading and assigning each ViewModel in the code-behind of each page. However, we will explore a strategy that not only makes this association more declarative, but also makes it easier to add design time data we can use while in Visual Studio and Blend (which we'll look at in our next post).
Create a ViewModelLocator
A ViewModelLocator is a class that centralizes the definitions of all the ViewModels in an app so that they can be cached and retrieved on demand, usually via Dependency Injection. A full discussion of these topics also outside the scope of this document, but this helpful answer on StackOverflow describes the pattern much better than I ever could, so definitely take a look if you're new to MVVM.
Long story short, the ViewModelLocator needs to setup the IOC provider, register each individual ViewModel, and finally expose those registered ViewModels for use by the rest of the application. This class, added to the portable project, gets the job done for our sample project:
public class BaseViewModelLocator
{
public BaseViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainPageViewModel>();
SimpleIoc.Default.Register<SecondPageViewModel>();
}
public MainPageViewModel MainPage
{
get { return ServiceLocator.Current.GetInstance<MainPageViewModel>(); }
}
public SecondPageViewModel SecondPage
{
get { return ServiceLocator.Current.GetInstance<SecondPageViewModel>(); }
}
}
The ServiceLocator is responsible for retrieving the ViewModel instances, using the SimpleIoc.Default implementation provided by MVVM Light. By registering them via the SimpleIoc.Default instance in the constructor, we can retrieve those instances from the Views via the public properties defined in the locator class.
We can then register this locator as a global static resource in App.xaml so it is available for all pages to use. These resources are automatically instantiated, both at runtime and designtime, ensuring that both our sample and live data are ready.
<Application
x:Class="Win10MvvmLight.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Win10MvvmLight"
xmlns:vm="using:Win10MvvmLight.Portable.ViewModels"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<vm:BaseViewModelLocator x:Key="ViewModelLocator" />
</ResourceDictionary>
</Application.Resources>
</Application>
At last, we can finally write each ViewModel to its appropriate page via the DataContext. Adding it to the MainPageView XAML:
<Page
x:Class="Win10MvvmLight.MainPage"
...
DataContext="{Binding Path=MainPage, Source={StaticResource ViewModelLocator}}">
and the SecondPageView:
<Page
x:Class="Win10MvvmLight.Views.SecondPage"
...
DataContext="{Binding Path=SecondPage, Source={StaticResource ViewModelLocator}}">
Each page (View) is now automatically wired up to its associated ViewModels. By following this pattern for this and any future views, we get a declarative association without writing a single line of code. We'll see just how useful that is in our next post.
Wrapping Up and Next Steps
Although it doesn't appear like we have accomplished much, what we have done is setup a framework for leveraging the MVVM design pattern in our app using MVVM Light.
We created a simple Model to represent the data we wish to display, the Views to display the actual UI to the user, and the ViewModels to contain the data to be presented.
In addition, since we defined the ViewModels and Model in a portable class, only the View is platform-specific, and would be the only piece we'd need to create new if we want to run the app on a new platform (assuming, of course, that platform supports MVVM Light).
Finally, by adding the ViewModelLocator, we were able to declaratively wire up all of the MVVM components without writing a single line of code or touching the code-behind of our pages. Best of all, as we'll see in our next post, that association will facilitate both runtime AND design-time data for our application, making it easier and faster to build the UI.
In our next post we'll see how to combine our setup with Blend for Visual Studio to quickly build the UI, using design-time data as a visual aid when creating the XAML layout.
Until then, you can grab a copy of the complete version of the sample project for this post here:
Get the CODE!
And as always, I hope this was helpful, and thanks for reading!