Overview:
There is an extremely vast array of tutorials over the internet on learning the MVVM pattern and sadly, in my opinion, many of them do not break the pattern down to the bare essentials. I will not say that their approach to teaching the pattern is wrong or that mine is the end all be all method. Everyone learns differently and sometimes the basic approach is the best. That being said, I will do my best to explain the MVVM pattern with the basic implementation in mind.
What I mean by the basic implementation of the MVVM pattern is, I will not be utilizing the ICommand Interface, nor will I be using an external library such as MVVMLight. The only required thing will be the INotifyPropertyChanged Interface.
This tutorial is broken down into two sections. Section 1 is theory with explanations. Section 2 is a simple project with a breakdown on the important pieces of code to understand. My code written below was written in .Net 4.5.2 and also tested with .Net 4.6 to ensure stability with the release of Visual Studio 2015, so that this article could be the most up to date as possible.
Without further adeu, Let’s get started with Section 1.
Section 1:
The MVVM pattern is an extension on the MVC pattern that is mainly used in Web development. Instead of Model View Controller, it features a Model, a View and ViewModel. So, if you are a beginner on the MVVM pattern, you are probably wondering why this pattern is so important. You would be right to wonder this, and the reasoning is quite simple. Code Separation. Code Separation allows you to keep your UI and your back end code separate. This is especially useful in various situations.
A primary example is you are working on backend code while another developer is working on the UI, if you don’t use the MVVM pattern, any changes the UI Developer makes could break your code. The MVVM pattern helps eliminate this problem.
Additionally, whenever you use the MVVM pattern, it is important to note that you are now doing a declarative programming style.
What are the Benefits of the MVVM pattern?
1. Your UX designer and a Backend programmer can work on the same project without bumping heads.
2. It is easy to create Unit tests for the ViewModel and the Model without the View.
3. Easy to redesign the UI that doesn’t affect your Backend code.
4. It is easier to integrate an existing business logic into an MVVM solution.
5. Easier to maintain and update
6. Less code you have to write in the long run
What does each portion of the MVVM model mean and do?
The Model is a class that exposes the data you want to use. In addition, this class also implements the INotifyPropertyChanged Interface.
The View is either your page or usercontrol (whichever you decide to use). This class should not have any backend code to it, however, there is one exception to this rule. Setting the DataContext to the ViewModel.
The ViewModel is a class that does all of the heavy lifting. This is where you would call a database, create an observablecollection, and any other backend code you would need to implement.
How does MVVM work?
The model class acts as the basis for your data. It holds the information you want to portray in your application. The viewmodel acts as the glue between your data and your UI. And your View is your UI.
Why is DataBinding Important with MVVM?
Databinding enables the user to bind objects so that whenever the other object changes, the main object reflects its changes. The main motive is to ensure that the UI is always synchronized with the internal object structure automatically.
What does DataBinding do?
This is by no means everything that databinding can do, it is more of a brief overview.
Databinding connects two properties together, if one changes, the other will as well. There are many ways to do this, such as what I do in Section 2. What I do in Section 2 is utilize the PropertyChanged event, the other method is a Dependency property.
Dependency Property versus PropertyChanged Event:
There are several differences between Dependency Properties and PropertyChanged Events.
Dependency Objects are not marked serializable, have thread affinity (which means it can only be accessed on the thread in which it was created, and overrides and seals the Equals() and GetHashCode() methods.
However, in testing, Dependency Objects perform much better than NotifyPropertyChanged. If you are interest in the findings of the test, another Article has been written about the subject in detail. (http://www.codeproject.com/Articles/62158/DependencyProperties-or-INotifyPropertyChanged)
What technologies can utilize the MVVM pattern?
It should be noted that it is not a requirement to use the MVVM pattern with these technologies.
It is acceptable to use MVVM with web technologies such as JavaScript or ASP.NET, however, there is a requirement. If you are making a rich UI application for a web solution, you can use MVVM. Windows Phone 7, Windows Phone 8, Windows Phone 8.1, Windows Metro Applications (8 and 8.1), and Windows 10 Universal Projects are all exceptional candidates for using the MVVM pattern. If you are a developer that still uses the deprecated Silverlight, MVVM is also great there. The most notable however, is a Windows Desktop WPF application is generally where most people start to learn the MVVM pattern. I have also seen instances where people use MVVM with a Unity project.
Why should I learn the MVVM pattern?
I personally feel that if you develop using technologies that have a way for you to implement it, that you should learn it because it will be that much easier for you in the long run. What I mean by that is, if you have a colleague that implements it in a project for your job or a prospective client requires you to implement the pattern for their project then it would be very much advantageous for you to know it and understand at least how it works.
How do you use DataBinding?
In XAML, databinding is very simple to do. Consider the snippet below.
<TextBox x:Name="textBox" Height="34" TextWrapping="Wrap" Text="{Binding Genre}" IsReadOnly="True"/>
What this XAML snippet is telling us is that, The textbox's text is set to the Bound path of Genre.
Now, what if you wanted to write the code using C# instead of using XAML? Well, consider the snippet below.
BindingSource binding = new BindingSource();
binding.Add(new Models.ModelClass("Action");
textbox.text = binding;
Now that the preliminaries are done, let’s go to Section 2 and have some fun with code!
Section 2:
First, let's talk about the model class.
In this example, we want to expose ReleaseDate, Name, and Genre. We also want to implement the INotifyPropertyChanged Interface and call the event in the setter of each public property.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace PracticeProject.Models
{
public class ModelClass : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
NotifyPropertyChanged();
}
}
private string releaseDate;
public string ReleaseDate
{
get { return releaseDate; }
set
{
releaseDate = value;
NotifyPropertyChanged();
}
}
private string genre;
public string Genre
{
get { return genre; }
set
{
genre = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Next up, The ViewModel Class. In the example, we will take advantage of using an ObservableCollection and set the parameters to be the Model Class. We will use Linq and lambda expressions to enumerate over the ObservableCollection. The xml file is embedded into the application, so we will use reflection and the streamreader class to call this data and put it into the ObservableCollection.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Xml.Linq;
using System.IO;
using System.Reflection;
using System.Windows;
namespace PracticeProject.ViewModels
{
public class ViewModelClass
{
public ObservableCollection<Models.ModelClass> Movies { get; set; }
StreamReader _textStreamReader;
public ViewModelClass()
{
LoadEmbeddedResource("PracticeProject.DataSources.Movies.xml");
XDocument xdoc = XDocument.Load(_textStreamReader);
var movies = xdoc.Descendants("Movies")
.Select(x =>
new Models.ModelClass
{
Name = (string)x.Element("Name"),
Genre = (string)x.Element("Genre").Value,
ReleaseDate = (string)x.Element("ReleaseDate").Value
}
).ToList();
Movies = new ObservableCollection<Models.ModelClass>(movies);
}
private void LoadEmbeddedResource(string resource)
{
try
{
Assembly _assembly;
_assembly = Assembly.GetExecutingAssembly();
_textStreamReader = new StreamReader(_assembly.GetManifestResourceStream(resource));
}
catch (Exception ex)
{
MessageBox.Show("Error Loading Embedded Resource: " + ex, "Error!", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}
Third on our plate is the View's CodeBehind. This example will illustrate that you shouldn't have any backend code for it, although, it is acceptable for one line as shown below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace PracticeProject.Views
{
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
DataContext = new ViewModels.ViewModelClass();
}
}
}
Finally, the View's XAML code. This is honestly the hardest part about using the MVVM pattern. We first declare the ViewModel in a namespace of the XAML document. We create a listbox and Bind the Movies ObservableCollection to it. We then set the UpdateSourceTrigger to PropertyChanged. Lastly, we set the DisplayMemberPath to Name. Make sure IsSynchronizedWithCurrentItem is set to true.
Next, we create a StackPanel and we set the DataContext of it to be to the ListBox with the Path set as selected item.
We do this to ensure that any item that is selected within the listbox will force the bound objects to update accordingly.
We now will create a label and textbox within the stackpanel, we will bind the text of the textbox to Genre and the context of the label to ReleaseDate.
<UserControl x:Class="PracticeProject.Views.MainView"
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:PracticeProject.Views"
mc:Ignorable="d"
xmlns:vm="clr-namespace:PracticeProject.ViewModels"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<ListBox x:Name="listBox" ItemsSource="{Binding Movies, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Name" Height="100" IsSynchronizedWithCurrentItem="True"/>
<StackPanel Margin="10" VerticalAlignment="Bottom" DataContext="{Binding ElementName=listBox, Path=SelectedItem}">
<Label x:Name="label" Content="{Binding ReleaseDate}" Height="36"/>
<TextBox x:Name="textBox" Height="34" TextWrapping="Wrap" Text="{Binding Genre}" IsReadOnly="True"/>
</StackPanel>
Now, you can run the program and any item you select within the listbox will update with the corresponding values within the label and textbox.
Points of Interest
Once you get the hang of the basics of the MVVM pattern, you will be able to extend it further by learning the ICommand Interface or implement using an external library such as MVVMLight.
There are many additional things that you can do with the MVVM pattern that is not discussed in this article.
Acknowledgements
It honestly took me several months to fully understand how the MVVM pattern works and I couldn't have done it without help from people from StackOverflow, CodeProject, Youtube, and the MSDN forums. So, in this section I would like to issue my sincerest thanks to all of the individuals responsible in helping me and others. There are too many people and sources to name so, if you are an individual that took time out to answer my questions, make tutorials such as mine, or even have made video tutorials; All of you have my sincerest thanks for helping other developers such as myself.