Our first task with the new view model system will be to connect the button clicks in the main menu with the display of the corresponding pages.

The quit button

To start with something simple, we’ll implement the quit button. (We’ll soon see that it’s not as simple as it seems…)

The communication between the view layer and the view model layer is established via bindings, events and commands. Bindings are (potentially) two-way connections, events are used to communicate something from view model to view, commands are used in the other direction. Commands are provided by the view models and bound to in the view. When for example a button is clicked and this button’s Command property is bound to a command in the view model, then this button “executes” the command and allows the view model to react on that command.

The view actually expects the command to be something that implements the ICommand Interface. WPF comes with a standard implementation for ICommand called RelayCommand.

RelayCommand

A command basically consists of two parts: A method that is called from the view to determine whether the command can be executed or not (CanExecute()), and another method to actually execute the command (Execute()). RelayCommand only consists of a constructor where both delegates are passed in. The class then automatically routes calls from the view to the corresponding delegate in the view model.

Note: if you for any reason don’t have access to the RelayCommand implementation in Microsoft.TeamFoundation.MVVM, here’s one you can use:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace SimpleMVVM
{
    public class RelayCommand : ICommand
    {
        private Func<object, bool> canExecute;
        private Action<object> execute;

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public bool CanExecute(object parameter)
        {
            return this.canExecute == null || this.canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            this.execute(parameter);
        }
    }
}

The Quit Command

Define a RelayCommand field named _quitCommand and encapsulate it with a property:

using System.Windows;

namespace SimpleMVVM.ViewModels
{
    public class MainMenuPageVM : PageVM
    {
        private RelayCommand _quitCommand;

        public RelayCommand QuitCommand
        {
            get
            {
                return _quitCommand;
            }

            set
            {
                _quitCommand = value;
            }
        }
    }
}

Define two methods ExecuteQuit() and QuitCanExecute() and create the command in the constructor:

using System.Windows;

namespace SimpleMVVM.ViewModels
{
    public class MainMenuPageVM : PageVM
    {
        private RelayCommand _quitCommand;

        public MainMenuPageVM()
        {
            _quitCommand = new RelayCommand(ExecuteQuit, QuitCanExecute);
        }

        public RelayCommand QuitCommand
        {
            get
            {
                return _quitCommand;
            }

            set
            {
                _quitCommand = value;
            }
        }

        private void ExecuteQuit(object o)
        {
        }

        private bool QuitCanExecute(object o)
        {
            return true;
        }
    }
}

For now we can simply call Application.Current.Shutdown() in ExecuteQuit() but we’ll be talking about this in a short while:

using System.Windows;

namespace SimpleMVVM.ViewModels
{
    public class MainMenuPageVM : PageVM
    {
        private RelayCommand _quitCommand;

        public MainMenuPageVM()
        {
            _quitCommand = new RelayCommand(ExecuteQuit, QuitCanExecute);
        }

        public RelayCommand QuitCommand
        {
            get
            {
                return _quitCommand;
            }

            set
            {
                _quitCommand = value;
            }
        }

        private void ExecuteQuit(object o)
        {
            Application.Current.Shutdown();
        }

        private bool QuitCanExecute(object o)
        {
            return true;
        }
    }
}

If we now bind the Command property of the quit button to this new command, then our application should be able to quit:

<UserControl x:Class="SimpleMVVM.MainMenuPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:SimpleMVVM"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">

    <StackPanel Orientation="Vertical">
        <Button Content="Edit Customers" Style="{StaticResource MainMenuButton}" />
        <Button Content="Edit Products" Style="{StaticResource MainMenuButton}" />
        <Button Content="Calculate Invoice" Style="{StaticResource MainMenuButton}" />
        <Button Content="Quit" Command="{Binding QuitCommand}" Style="{StaticResource MainMenuButton}" />
    </StackPanel>
</UserControl>

If we now extend our unit test to use the new command (or “click the quit button”)…:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SimpleMVVM.ViewModels;

namespace SimpleMVVMTests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void InitTest()
        {
            SimpleMVVMApp app = new SimpleMVVMApp();
            app.Init();
            MainMenuPageVM mainWindow = (MainMenuPageVM)app.PageFrame.CurrentPage;
            Assert.IsNotNull(mainWindow);

            mainWindow.QuitCommand.Execute(null);
        }
    }
}

…we’ll get an null reference exception at the line where Application.Current.Shutdown() is called. Application.Current is null and that is because WPF is not initialized in a unit test and therefore no Application object is available.
So you see, it’s not always a good idea to call WPF methods from view models…

Suggestion #5: Don’t call WPF System methods in view models.

In a real world project you will find a lot of situations where you shouldn’t be calling WPF methods from view models. Calling Application.Current.Shutdown() also chains your view models to be used with WPF – so you can’t use them in ASP.NET for example.

What we need now is a way to abstract the quitting of the application. Instead of calling Application.Current.Shutdown() directly, we need a method that can be called from the view models and that can be rerouted in unit tests.

The system connector

Create an interface named ISystemConnector. This will be the connection between the view models and the system and it provides the methods they need to call to do their job:

namespace SimpleMVVM.ViewModels
{
    public interface ISystemConnector
    {
        void Quit();
    }
}

Since potentially every view model could need this interface, we will define it in ViewModelBase. Create a field, an encapsulating property and a constructor to initialize it:

namespace SimpleMVVM.ViewModels
{
    public class ViewModelBase
    {
        private ISystemConnector _systemConnector;

        public ViewModelBase(ISystemConnector systemConnector)
        {
            _systemConnector = systemConnector;
        }

        public ISystemConnector SystemConnector
        {
            get
            {
                return _systemConnector;
            }
            set
            {
                _systemConnector = value;
            }
        }
    }
}

We also have to adapt the constructor in PageVM:

namespace SimpleMVVM.ViewModels
{
    public class PageVM : ViewModelBase
    {
        public PageVM(ISystemConnector systemConnector)
            : base(systemConnector)
        {
        }
    }
}

And of course the constructor of MainMenuPageVM:

using System.Windows;

namespace SimpleMVVM.ViewModels
{
    public class MainMenuPageVM : PageVM
    {
        public MainMenuPageVM(ISystemConnector systemConnector)
            : base(systemConnector)
        {
            _quitCommand = new RelayCommand(ExecuteQuit, QuitCanExecute);
        }

        // ...
    }
}

And since PageFrameVM also derives from ViewModelBase, it also requires a new constructor:

namespace SimpleMVVM.ViewModels
{
    public class PageFrameVM : ViewModelBase
    {
        private PageVM _currentPage;

        public PageFrameVM(ISystemConnector systemConnector)
            : base(systemConnector)
        {
        }

        public PageVM CurrentPage
        {
            get { return _currentPage; }
            set { _currentPage = value; }
        }
    }
}

In SimpleMVVMApp we now need to add “something” that implements this interface:

using System.Windows;

namespace SimpleMVVM.ViewModels
{
    public class SimpleMVVMApp 
    {
        public void Init()
        {
            MainMenuPageVM mainMenuPage = new MainMenuPageVM(/* requires implementation of interface! */);
        }
    }
}

Since this interface represents the “outer world”, we’ll pass in the implementation via the constructor and store it in a member variable:

using System.Windows;

namespace SimpleMVVM.ViewModels
{
    public class SimpleMVVMApp
    {
        private PageFrameVM _pageFrame;
        private ISystemConnector _systemConnector;

        public SimpleMVVMApp(ISystemConnector systemConnector)
        {
            _systemConnector = systemConnector;
        }

        public void Init()
        {
            _pageFrame = new PageFrameVM(_systemConnector);
            MainMenuPageVM mainMenuPage = new MainMenuPageVM(_systemConnector);
            PageFrame.CurrentPage = mainMenuPage;
        }
    }
}

Our MainWindow will be the implementation. So add the interface to the base list of the class MainWindow and implement the Quit() method. Finally add this to the constructor call of SimpleMVVMApp:

using System;
using System.Windows;
using SimpleMVVM.ViewModels;

namespace SimpleMVVM
{
    public partial class MainWindow : Window, ISystemConnector
    {
        public MainWindow()
        {
            InitializeComponent();

            Loaded += MainWindow_Loaded;
        }

        public void Quit()
        {
            Application.Current.Shutdown();
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            SimpleMVVMApp app = new SimpleMVVMApp(this);
            app.Init();
            Content = app.PageFrame;
        }
    }
}

One last thing is missing. We have to fix our test. In our test the test class will be the implementation of the ISystemConnector interface. This allows us to verify whether methods in the interface are called correctly and mock the behaviour of the system where necessary. Add the ISystemConnector interface to the base list and implement the Quit() method; finally add this to the constructor call of SimpleMVVMApp:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SimpleMVVM.ViewModels;

namespace SimpleMVVMTests
{
    [TestClass]
    public class UnitTest1 : ISystemConnector
    {
        [TestMethod]
        public void InitTest()
        {
            SimpleMVVMApp app = new SimpleMVVMApp(this);
            app.Init();
            MainMenuPageVM mainWindow = (MainMenuPageVM)app.PageFrame.CurrentPage;
            Assert.IsNotNull(mainWindow);

            mainWindow.QuitCommand.Execute(null);
        }

        public void Quit()
        {
        }
    }
}

We actually want to test whether the Quit() method has been called correctly; that means it should be called exactly once. Therefore we define a member variable in the class named _quitCallCounter and in the Quit() method we increment it; So we finally can test whether the Quit() method has been called correctly:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SimpleMVVM.ViewModels;

namespace SimpleMVVMTests
{
    [TestClass]
    public class UnitTest1 : ISystemConnector
    {
        private int _quitCallCounter;

        [TestMethod]
        public void InitTest()
        {
            _quitCallCounter = 0;

            SimpleMVVMApp app = new SimpleMVVMApp(this);
            app.Init();
            MainMenuPageVM mainWindow = (MainMenuPageVM)app.PageFrame.CurrentPage;
            Assert.IsNotNull(mainWindow);

            mainWindow.QuitCommand.Execute(null);
            Assert.AreEqual(1, _quitCallCounter);
        }

        public void Quit()
        {
            ++_quitCallCounter;
        }
    }
}

As you can see this approach is very flexible. You can use a WPF object as implementation of the interface, or you can use the test class. You could even use a completely different class to mock the behaviour of the UI.
The interface will grow over time but it is one interface that bundles all the requirements that the view models have, and therefore it is fairly easy to substitute it.