Thursday, November 14, 2013

Getting Started with KSMVVM.WPF

KSMVVM.WPF is a 'kinda small' Model-View-ViewModel framework for Windows Presentation Foundation (WPF) that I released earlier in 2013. It's a little different than other micro-MVVM frameworks because it was specifically designed for migrating existing code-behind WPF applications to MVVM.

Some nice features of KSMVVM.WPF include:
  • Functionality to allow ViewModels to control program navigation (in a manner to allow for automated tests)
  • Lightweight, easy-to-use string-based messaging
  • Two ICommand implementations; a 'hack' one for existing apps, and a 'non-hack' one for new apps
This 'getting started' guide will illustrate use of KSMVVM.WPF in an existing WPF application. This guide assumes that you are using a recent version of Visual Studio (or VS Express) with built-in NuGet functionality. I'm actually using VS Express for Desktop 2013 RC for this tutorial.

The tutorial continues after the page break.


Step #1 - Project Setup

The first step is opening the sample code-behind project. Go to the KSMVVM.WPF.GettingStarted GitHub page and click the 'Download ZIP' button. Extract the downloaded zip file somewhere, and then open the version of 'SampleApplication.sln' that's in the before directory.

Step #2 - Add KSMVVM.WPF NuGet Package

You'll need to add KSMVVM.WPF to the sample project before continuing. In Visual Studio, right-click on 'SampleApplication' in the Solution Explorer, then click on 'Manage NuGet Packages...'

Use the 'Manage NuGet Packages' window to locate & install KSMVVM.WPF. NuGet has provided a complete guide on Managing NuGet Packages Using The Dialog. If you search for 'KSMVVM.WPF', you'll find the package.

Step #3 - Add ViewModel for WelcomePage

The first page we'll be converting is WelcomePage. It's a very basic page with a single Label and a Button. The Button has a Click event handler named 'WelcomeButton_Click'. This handler should appear in WelcomePage's code-behind and look like this:

private void WelcomeButton_Click(object sender, RoutedEventArgs e)
{
    NavigationService.Navigate(new FormPage(
        new InventoryItem() { Name = "Test Item", Amount = 5 }));
}

This very simple click handler just tells NavigationService to go to a new page.

Now that we know what WelcomePage does, we can make a ViewModel for it. This ViewModel needs two things:
  1. An ICommand to replace this click handler
  2. A way to perform page navigation
KSMVVM.WPF provides both of these things, as we'll be seeing soon.

First, create a ViewModels directory in the SampleApplication project. Add a new class file named 'WelcomeViewModel.cs' to this directory. Replace the contents of the new file with the following:

using KSMVVM.WPF;
using KSMVVM.WPF.ViewModel;
using SampleApplication.Models;
using System.Windows.Input;

namespace SampleApplication.ViewModels
{
    public sealed class WelcomeViewModel : ViewModelBase
    {
        public WelcomeViewModel(IAppNavigationService nav)
        {
            _nav = nav;

            Submit = new BasicCommand(
                //Execute
                () =>
                {
                    InventoryItem newItem = new InventoryItem()
                    {
                        Name = "Test Item",
                        Amount = 5
                    };

                    _nav.Navigate(() =>
                        new FormPage(newItem));
                });
        }

        public ICommand Submit { get; private set; }
        private IAppNavigationService _nav;
    }
}

Basically, the IAppNavigationService instance replaces Page.NavigationService, and the ICommand property replaces the Click handler.

Step #4 - Setup WelcomePage To Use ViewModel

WelcomePage will need some changes to actually use this new ViewModel. Basically, what you need to do is set the DataContext of a new WelcomePage instance to an instance of WelcomeViewModel and change the XAML to use the ViewModel's Submit command.

The only constructor for WelcomeViewModel takes an IAppNavigationService instance as a parameter. KSMVVM.WPF comes with a concrete implementation of this interface: PageNavigationService. Add the following line below "InitializeComponent()" in WelcomePage.xaml.cs:
DataContext = new WelcomeViewModel(new PageNavigationService(this));

Next, remove the Button Click handler from the code-behind and the XAML and add a 'Command' element for the Button set to "{Binding Submit}".

WelcomePage now uses MVVM!

Step #5 -  Add ViewModel for FormPage

FormPage is mostly like WelcomePage, but with three differences: its DataContext is already set to an InventoryItem model instance, it has form fields bound to model properties, and its button handler uses the model's values.

This means that our FormViewModel class will be much like WelcomeViewModel but will include an additional InventoryItem property.

Add a new class file named 'FormViewModel.cs' to the ViewModels directory. Replace the contents of the new file with the following:

using KSMVVM.WPF;
using KSMVVM.WPF.ViewModel;
using SampleApplication.Models;
using System.Globalization;
using System.Windows;
using System.Windows.Input;

namespace SampleApplication.ViewModels
{
    public sealed class FormViewModel : ViewModelBase
    {
        public FormViewModel(InventoryItem model,
            IAppNavigationService nav)
        {
            Model = model;
            _nav = nav;

            Submit = new BasicCommand(
                //Execute
                () =>
                {
                    string boxMessage = string.Format(
                        CultureInfo.InvariantCulture,
                        "Data submitted:\n{0} - {1}",
                        Model.Name,
                        Model.Amount);

                    MessageBox.Show(boxMessage);
                    _nav.GoBack();
                });
        }

        public ICommand Submit { get; private set; }

        public InventoryItem Model { get; private set; }

        private IAppNavigationService _nav;
    }
}

Step #6 - Setup FormPage To Use ViewModel

Of course, we'll need to change FormPage to use the new ViewModel class. This process will be roughly the same as when we changed WelcomePage, but with one important difference: everything referring to the model in WelcomePage will have to be changed to point to the ViewModel's model instance.

Remove the _view field from FormPage and add the following field:
private FormViewModel _viewModel;

Remove every line of code from FormPage's constructor and insert the following:

InitializeComponent();
_viewModel = new FormViewModel(model, new PageNavigationService(this));
DataContext = _viewModel;

Next, remove the Button Click handler from the code-behind and the XAML and add a 'Command' element for the Button set to "{Binding Submit}".

Finally, you have to alter some additional bindings. FormPage.xaml has two TextBox elements that have Text bound to a model property. Add 'Model.' to the beginning of each property name. For example, Text="{Binding Name}" becomes Text="{Binding Model.Name}".

If everything compiles & works properly, then congratulations, you successfully refactored SampleApplication to use MVVM.

Continue to part 2 of the tutorial to learn about messaging:
Getting Started with KSMVVM.WPF Part 2: Messaging

No comments:

Post a Comment