Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

The MVVM Pattern — The Practice

DZone's Guide to

The MVVM Pattern — The Practice

Let’s continue our journey to learn the MVVM pattern, applied to Universal Windows app development. As a sample project, we’re going to create a very simple Universal Windows app.

· Web Dev Zone
Free Resource

Learn how to build modern digital experience apps with Crafter CMS. Download this eBook now. Brought to you in partnership with Crafter Software

Let’s continue our journey to learn the MVVM pattern, applied to Universal Windows app development. After we’ve learned the basic concepts in the previous post, it’s time to start writing some code. As already mentioned in the previous post, we’re going to leverage MVVM Light as a toolkit to help us implement the pattern. Since it’s the most flexible and simple to use, it will be easier to understand and apply the basic concepts we’ve learned so far.

The Project

The goal of the MVVM pattern is to help developers to organize their code in a better way. As such, the first step is to define the structure of a project in a way that, also from a logical point of view, it can follow the principles of the pattern. Consequently, usually the first thing to do is to create a set of folders where to place our classes and files, like:

  • Models — where to store all our basic entities
  • ViewModels — where to store the classes that will connect the Model with the View
  • Views — where to store the Views, which are the XAML pages in that case of a Universal Windows app

In a typical MVVM project, however, you will end up having more folders: one for the assets, one for the services, one for the helper classes, etc.

The second step is to install our chosen library in the project to help us implement the pattern. In our case, we chose MVVM Light, so we can leverage NuGet to install it. We will find two different versions:

For the moment, my suggestion is to use the second package. This way, we can do everything from scratch, giving us the chance to better learn the basic concepts. In the future, you’re free to use the first package if you want to save some time.

As a sample project, we’re going to create a very simple Universal Windows app that it’s likely you would be able to develop in no time using code behind: a Hello World app with a TextBox, where you can insert your name, and a Button that, when pressed, will display a hello message followed by your name.

Linking the View and ViewModel

The first step is to identify the three components of our application: Model, View, and ViewModel.

  • The model isn’t necessary in this application, since we don’t need to manipulate any entity.
  • The view will be made by a single page, which will show to the user the TextBox where to insert his/her name and the Button to show the message.
  • The ViewModel will be a class, which will handle the interaction in the view. It will retrieve the name filled in by the user and compose the hello message, displaying it on the page.

Let’s start to add the various components. Create a Views folder and inside it add the only page of our application. As a default behavior, when you create a new Universal Windows app, the template will create a default page for you, called MainPage.xaml. You can move it to the Views folder or delete it and create a new one in Solution Explorer by right clicking on the folder and choosing Add –> New item –> Blank page.

Now let’s create the ViewModel that will be connected to this page. As explained in the previous post, the ViewModel is just a simple class: create a ViewModels folder, right click on it, and choose Add –> New Item –> Class.

Now, we need to connect the View and the ViewModel by leveraging the DataContext property. In the previous post, in fact, we’ve learned that the ViewModel class is set as DataContext of the page; this way, all the controls in the XAML page will be able to access to all the properties and commands declared in the ViewModel. There are various ways to achieve our goal, so let’s take a look at them.

Declare the ViewModels as Resources

Let’s say that you have created a ViewModel called MainViewModel. You’ll be able to declare it as a global resource in the App.xaml file this way:

<Application
    x:Class="MVVMSample.MVVMLight.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:viewModel="using:MVVMSample.MVVMLight.ViewModel">

    <Application.Resources>
        <viewModel:MainViewModel x:Key="MainViewModel" />
    </Application.Resources>

</Application>

The first step is to declare, as an attribute of the Application class, the namespace which contains the ViewModel (in this sample, it’s MVVMSample.MVVMLight.ViewModel). Then, in the Resources collection of the Application class, we declare a new resource with the type being MainViewModel and associate it to a key with the same name. Now, we can use this key and the StaticResource keyword to connect the DataContext of the page to the resource, like in the following sample:

<Page
    x:Class="MVVMSample.MVVMLight.Views.MainPage"
    DataContext="{Binding Source={StaticResource MainViewModel}}"
    mc:Ignorable="d">

    <!-- your page content -->

</Page>

The ViewModelLocator Approach

Another frequently used approach is to leverage a class called ViewModelLocator, which has the responsability of dispatching the ViewModels to the various pages. Instead of registering all the ViewModels as global resources of the application, like in the previous approach, we register just the ViewModelLocator. All the ViewModels will be exposed, as properties, by the locator, which will be leveraged by the DataContext property of the page.

This is a sample definition of a ViewModelLocator class:

public class ViewModelLocator
{
    public ViewModelLocator()
    {
    }

    public MainViewModel Main
    {
        get
        {
            return new MainViewModel();
        }
    }
}

Or, as an alternative, you can simplify the code by leveraging one of the new C# 6 .0 features:

public class ViewModelLocator
{
    public ViewModelLocator()
    {
    }

    public MainViewModel Main => new MainViewModel();
}

After you’ve added the ViewModelLocator class as global resource, you’ll be able to use it to connect the Main property to the DataContext property of the page, like in the following sample:

<Page
    x:Class="MVVMSample.MVVMLight.Views.MainPage"
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    mc:Ignorable="d">

    <!-- your page content -->

</Page>

The syntax is very similar to the one we’ve seen with the first approach; the main difference is that, since the ViewModelLocator class can expose multiple properties, we need to specify with the Path attribute which one we want to use.

The ViewModelLocator’s approach adds a new class to maintain, but it gives you the flexibilty to handle the ViewModel’s creation in case we need to pass some parameters to the class’ constructor. In the next post, when we’ll introduce the dependeny injection’s concept, so it will be easier for you to understand the advantages in using the ViewModelLocator approach.

Let’s Set Up the ViewModel

No matter which approach we decided to use in the previous step, now we have a View (the page that will show the form to the user) connected to a ViewModel (the class that will handle the user’s interactions).

Let’s start to populate the ViewModel and define the properties that we need to reach our goal. In the previous post we’ve learned that ViewModels need to leverage the INotifyPropertyChanged interface; otherwise, every time we change the value of a property in the ViewModel, the View won’t be able to detect it and the user won’t see any change in the user interface.

To make it easier to implement this interface, MVVM Light offers a base class which we can leverage in our ViewModels using inheritance, like in the following sample:

public class MainViewModel : ViewModelBase
{

}

This class gives us access to a method called Set(), which we can use when we define our propeties to dispatch the notifications to the user interface when the value changes. Let’s see a sample related to our scenario. Our ViewModel has to be able to collect the name that the user has filled into a TextBox control in the View. Consequently, we need a property in our ViewModel to store this value. Here is what it looks like thanks to the MVVM Light support:

private string _name;

public string Name
{
    get
    {
        return _name;
    }

    set
    {
        Set(ref _name, value);
    }
}

The code is very similar to the one we’ve seen in the previous post when we introduced the concept of the INotifyPropertyChanged interface. The only difference is that, thanks to the Set() method, we can achieve two goals at the same time: storing the value in the Name property and dispatching a notification to the binding channel that the value has changed.

Now that we have learned how to create properties, let’s create another one to store the message that we will display to the user after he has pressed the button.

private string _message;

public string Message
{
    get
    {
        return _message;
    }

    set
    {
        Set(ref _message, value);
    }
}

In the end, we need to handle the interaction with the user. When he presses the Button in the view, we have to display a hello message. From a logical point of view, this means:

  1. Retrieving the value of the Name property.
  2. Leveraging the string interpolation APIs to prepare the message (something like “Hello Matteo”).
  3. Assign the result to the Message property.

In the previous post we’ve learned that, in the MVVM pattern, you use commands to handle the user interactions in a ViewModel. As such, we’re going to use another one of the classes offered by MVVM Light, which is RelayCommand. Thanks to this class, instead of having to create a new class that implements the ICommand interface for each command, we can just declare a new one with the following code:

private RelayCommand _sayHello;

public RelayCommand SayHello
{
    get
    {
        if (_sayHello == null)
        {
            _sayHello = new RelayCommand(() =>
            {
                Message = $"Hello {Name}"; 
            });
        }

        return _sayHello;
    }
}

When you create a new RelayCommand object you have to pass, as parameter, an Action, which defines the code that you want to execute when the command is invoked. The previous sample declares an Action using an anonymous method. It means that, instead of defining a new method in the class with a specific name, we define it inline in the property definition, without assigning a name.

When the command is invoked, we use the new C# 6.0 feature to perform string interpolation to get the value of the property Name and add the prefix “Hello”. The result is stored into the Message property.

Create the View

Now that the ViewModel is ready, we can move on and create the View. The previous step should have helped you to understand one of the biggest benefits of the MVVM pattern; we’ve been able to define the ViewModel to handle the logic and the user interaction without writing a single line of code in the XAML file. With the code behind approach, it would have been impossible; for example, if we wanted to retrieve the name filled in the TextBox property, we should have first added the control in the page and assigned to it a name using the x:Name property, so that we would have been able to access to it from code behind. Or, if we wanted to define the method to execute when the button is pressed, we would have needed to add the Button control in the page and subscribe to the Click event.

From a user interface point of view, the XAML we need to write for our application is more or less the same we would have created for a code behind app. The UI, in fact, doesn’t have any connection with the logic, so the way we create the layout doesn’t change when we use the MVVM pattern. The main difference is that, in a MVVM app, we will use binding a lot more, since it’s the way we can connect the controls with the properties in the ViewModel. Here is what our View looks like:

<Page
    x:Class="MVVMSample.MVVMLight.Views.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    mc:Ignorable="d">

    <Grid>
        <StackPanel Margin="12, 30, 0, 0">
            <StackPanel Orientation="Horizontal" Margin="0, 0, 0, 30">
                <TextBox Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="300" Margin="0, 0, 20, 0" />
                <Button Command="{Binding Path=SayHello}" Content="Click me!" />
            </StackPanel>

            <TextBlock Text="{Binding Path=Message}" Style="{StaticResource HeaderTextBlockStyle}" />
        </StackPanel>
    </Grid>

</Page>

We have added three controls to the page:

  1. A TextBox, where the user can fill in his/her name. We have connected it to the Name property of the ViewModel. There are two features to higlight:
    1. We have set the Mode attribute to TwoWay. It’s required since, for this scenario, we don’t just need that when the property in the ViewModel changes, the control displays the updated value, but also the opposite. When the user fills some text in the control, we need to store its value in the ViewModel.
    2. We have set the UpdateSourceTrigger attribute to PropertyChanged. This way, we make sure that, every time the text changes (which means every time the user adds or removes a char in the TextBox), the Name property will automatically update to store the changed value. Without this attribute, the value of the property would be updated only when the TextBox control loses the focus.
  2. A Button, that the user will click to see the hello message. We have connected it to the SayHello command in the ViewModel.
  3. A TextBlock, where the user will see the hello message. We have connected it to the Message property of the ViewModel.

If we have done everything properly and launch the app, we should see the application behaving as we described at the beginning of this post: after filling in your name and pressing the button, you will see the hello message.

Let’s Improve the User Interaction

Our application has a flaw: if the user presses the button without writing anything in the TextBox, he would see just the “Hello” prefix. We want to avoid this behavior by disabling the button if the TextBox control is empty. To achieve our goal we can leverage one of the features offered by the ICommand interface: we can define when a command should be enabled or not. For this scenario, the RelayCommand class allows a second parameter during the initialization, a function that returns a boolean value. Let’s see the sample:

private RelayCommand _sayHello;

public RelayCommand SayHello
{
    get
    {
        if (_sayHello == null)
        {
            _sayHello = new RelayCommand(() =>
            {
                Message = $"Hello {Name}";
            },

            () => !string.IsNullOrEmpty(Name));
        }

        return _sayHello;
    }
}

We’ve changed the initialization of the SayHello command to add, as a second parameter, a boolean value. Specifically, we check if the Name property is null or empty (in this case, we return false, otherwise true). Thanks to this change, now the Button control connected to this command will be automatically disabled (also from a visual point of view) if the Name property is empty. However, there’s a catch: if we try the application as it is, we would notice that the Button will be disabled by default when the app starts. It’s the expected behavior, since when the app is launched the TextBox control is emtpy by default. However, if we start writing something in the TextBox, the Button will continue to be disabled. The reason is that the ViewModel isn’t able to automatically determine when the execution of the SayHello command needs to be evaluated again. We need to do it manually every time we do something that may change the value of the boolean function; in our case, it happens when we change the value of the Name property, so we need to change the property definition like in the following sample:

private string _name;

public string Name
{
    get
    {
        return _name;
    }

    set
    {
        Set(ref _name, value);
        SayHello.RaiseCanExecuteChanged();
    }
}

Other than just using the Set() method to store the property and to send the notification to the user interface, we invoke the RaiseCanExecuteChanged() method of the SayHello command. This way, the boolean condition will be evaluated again. If the Name property contains some text, then the command will be enabled; otherwise, if it should become empty again, the command will be disabled.

In the Next Post

In this post, we finally started to apply the concepts we learned in the first post with a real project and began to write our first application based on the MVVM pattern. In the next posts, we’ll see some advanced scenarios, like dependency injection, messages, or how to handle secondary events. Meanwhile, you can play with the sample app we’ve created in this post, also published on my GitHub repository https://github.com/qmatteoq/UWP-MVVMSamples. Together with the sample created in this post, you will also find the same sample created using Caliburn Micro as MVVM framework instead of MVVM Light.

Happy coding!

Crafter is a modern CMS platform for building modern websites and content-rich digital experiences. Download this eBook now. Brought to you in partnership with Crafter Software.

Topics:
mvvm ,mvvm.pattern ,web design

Published at DZone with permission of Matteo Pagani, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}