Tuesday, August 26, 2014

Step by Step : Understanding MVVM


Hi,

Welcome to my blog. In this post we will take a step by step approach and develop a small WPF application that uses MVVM design approach. By the end of this article, I hope you will get a basic idea of what is MVVM and what each component does and how they play their roles in our common goal ie to develop a clean that address numerous development and design issues and can make your application much easier to test, maintain, and evolve. So, let's rollup our sleeves and let's start our journey.

This is just one of the way which I followed in my projects. I am not saying this is the best and it doesnot have cons. My main intension is to share my experience so that it will be useful for the needy. I am new to blogging and I tried to make this post as much interesting as possible. Please excuse me for my grammatical errors and typos. I welcome your constructive comments and suggestions which helps in improving this post and my technical skills. 

What is MVVM:
First let's try to understand what exactly is this MVVM. Basically, The Model-View-ViewModel (MVVM) is one of the various patterns that are out there to develop your applications. MVVM is a specific implementation targeted at UI development platforms which support event-driven programming, specifically Windows Presentation Foundation (WPF) and Silverlight on the .NET platforms using XAML and .NET languages. MVVM allows you clearly separate business and presentation logic of your application from its user interface and there by allows a clean separation between user interface and application logic of your application. This clean and clear separation between application and user interface logic make your application much easier to test, maintain, and evolve. It effectively improves development by allowing code re-use and allows code developers and UI designers to more easily collaborate when developing their respective parts of the application. In MVVM both UI logic and application logic is separated into three classes.

Model : It can be either the actual data and/or information we are dealing with. An example of a model might be a Person(containing name, phone number, address, etc.) or the data access layer that represents that content (a data-centric approach). 

View : The view is what the end user interacts with. It is the presentation of the data. The view can make the data more presentable. In MVVM, the view is active and can have behaviors associated with it like button click etc. Each component in MVVM can be developed separately but the View ultimately requires knowledge of the underlying model and viewmodel since view can contain behaviors, events, and data-bindings. The view's events and behaviors might be mapped to properties, method calls, and commands in viewmodel, the view is still responsible for handling its own events, and does not turn this completely over to the viewmodel.

One thing to remember about the view is that it is not responsible for maintaining its state. Instead, it will synchronize this with the viewmodel.


ViewModel : It is the mediator between the view and the model which is the target of the view data bindings. It is key piece that keeps view separate from the model.It might take input from the view and give it to model, or it might interact with a service to retrieve the data/model, then translate properties and place it on the view. The viewmodel can also have methods, commands, and other points that helps in maintaining the state of the view, manipulating the model as the result of actions on the view, and trigger events in the view itself.

Important points to remember :

The View and the ViewModel

  • The communication between view and viewmodel happens using data-binding, messages, events, properties, method calls
  • The viewmodel can also expose other properties like is busy indicator and so on and commands
  • The view maps UI events to viewmodel's commands after handling its own UI events
  • The models and properties on the viewmodel are updated from the view via two-way databinding

The ViewModel and the Model 

  •  The viewmodel either exposes the model directly, or properties related to the model, for data-binding
  •  The viewmodel can contain interfaces to services, configuration data, etc., in order to fetch and manipulate the properties it exposes to the view

Now enough of this background information and lets start our steps.

For this article, I am using the following tools/technologies to develop a WPF application
Visual Studio 2013
C#
.NET Framework 4.5

I always have the habit of creating empty solution first and then work on it. Here also I did same thing. I created a folder called "MVVM" in "D\XXXX\My Programs" folder and created an empty visual studio solution titled "MVVMWPFDemo"

 In Solution Explorer , right click on MVVMWPFDemo and add New Project of type WPF and name it as "WpfClient". This WpfClient is our MVVM application. WpfClient  will have one UI like below which is used to 
  • add new person using MVVM pattern

Lets develop WpfClient step by step.

Create 4 folders and name them as Commands, Views, ViewModels, and Models in WpfClient by, right click on WpfClient and click Add -> New Folder 



 




















First let's create model.Right click on Models folder and add a class called Person and add below code to it. This is the actual information which we are dealing with.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfClient.Models
{
    public class Person
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
    }
}


Create a class called DelegateCommand inside Commands folder and add below code. When ever some events such as button click events happen on UI, UI will communicate with ViewModel using Commands and we are going to use below DelegateCommand  class for this purpose.

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

namespace WpfClient.Commands
{
    public class DelegateCommand : ICommand
    {
        /// <summary>
        /// Occurs when changes occur that affect whether the command should execute.
        /// </summary>
        public event EventHandler CanExecuteChanged;

        Func<object, bool> canExecute;
        Action<object> executeAction;
        bool canExecuteCache;

        /// <summary>
        /// Initializes a new instance of the <see cref="DelegateCommand"/> class.
        /// </summary>
        /// <param name="executeAction">The execute action.</param>
        /// <param name="canExecute">The can execute.</param>
        public DelegateCommand(Action<object> executeAction,
                               Func<object, bool> canExecute)
        {
            this.executeAction = executeAction;
            this.canExecute = canExecute;
        }

        #region ICommand Members
        /// <summary>
        /// Defines the method that determines whether the command
        /// can execute in its current state.
        /// </summary>
        /// <param name="parameter">
        /// Data used by the command.
        /// If the command does not require data to be passed,
        /// this object can be set to null.
        /// </param>
        /// <returns>
        /// true if this command can be executed; otherwise, false.
        /// </returns>
        public bool CanExecute(object parameter)
        {
            bool tempCanExecute = canExecute(parameter);

            if (canExecuteCache != tempCanExecute)
            {
                canExecuteCache = tempCanExecute;
                if (CanExecuteChanged != null)
                {
                    CanExecuteChanged(this, new EventArgs());
                }
            }

            return canExecuteCache;
        }

        /// <summary>
        /// Defines the method to be called when the command is invoked.
        /// </summary>
        /// <param name="parameter">
        /// Data used by the command.
        /// If the command does not require data to be passed,
        /// this object can be set to null.
        /// </param>
        public void Execute(object parameter)
        {
            executeAction(parameter);
        }
        #endregion
    }
}


Now lets create ViewModel. Right click on ViewModels folder and add class named ViewModelBase and add below code.This will be base to all our ViewModel classes. This basically has the functionality which facilitates firing a notification when some element changed on UI.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfClient.ViewModels
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}


Now in same folder add PeopleViewModel.cs and add below code. This will be ViewModel for PeopleView.xaml

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using WpfClient.Models;
using WpfClient.Commands;

namespace WpfClient.ViewModels
{
    public class PeopleViewModel : ViewModelBase
    {
        private ObservableCollection<Person> persons;
        public ObservableCollection<Person> Persons
        {
            get { return persons; }
            set
            {
                persons = value;
                RaisePropertyChanged("Persons");
            }
        }

        private Person selectedPerson;
        public Person SelectedPerson
        {
            get { return selectedPerson; }
            set
            {
                selectedPerson = value;
                RaisePropertyChanged("SelectedPerson");
            }
        }

        private string firstName;
        public string FirstName
        {
            get { return firstName; }
            set
            {
                firstName = value;
                RaisePropertyChanged("FirstName");
            }
        }

        private string lastName;
        public string LastName
        {
            get { return lastName; }
            set
            {
                lastName = value;
                RaisePropertyChanged("LastName");
            }
        }

        private int age;
        public int Age
        {
            get { return age; }
            set
            {
                age = value;
                RaisePropertyChanged("Age");
            }
        }

        public ICommand AddCommand { get; set; }
    
        public PeopleViewModel()
        {          
            Persons = new ObservableCollection<Person>();
            AddCommand = new DelegateCommand(AddPerson, CanExecuteAddPerson);          
        }

        private void AddPerson(object parameter)
        {
            Person newPerson = new Person();
            newPerson.Id = GetNextPersonId();
            newPerson.FirstName = FirstName;
            newPerson.LastName = LastName;
            newPerson.Age = Age;

            Persons.Add(newPerson);
        }

        private bool CanExecuteAddPerson(object parameter)
        {
            return true;
        }

        private int GetNextPersonId()
        {
            int count = Persons.Count;
            return ++count;
        }
    }
}



Explanation:
1) We inherited our PeopleViewModel from ViewModelBase so that we can raise an event whenever our property changed. This property will be binded to one of the UI element on UI so when UI element value changes this property value changes and we can fire an event.

private string firstName;
        public string FirstName
        {
            get { return firstName; }
            set
            {
                firstName = value;
                RaisePropertyChanged("FirstName");
            }
        }


2) The commands are created using DelegateCommand class like below
 public ICommand AddCommand { get; set; }

 public PeopleViewModel()
        {          
            Persons = new ObservableCollection<Person>();
            AddCommand = new DelegateCommand(AddPerson, CanExecuteAddPerson);          
        }


//What must happen when this command is invoked by some element on UI.
private void AddPerson(object parameter)
        {
          //do something here

        }

//whether this command can be executed or not
//if true is return it can be executed or else cannot be executed
private bool CanExecuteAddPerson(object parameter)
        {
            return true;
        }

That's it. This is basic PeopleViewModel.cs

Now lets create View like below. I know it is not fancy but just want to throw some simple UI so that we can concentrate on MVVM.



 In Views folder add UserControl and name it as PeopleView.xaml and add below code to it.

<UserControl x:Class="WpfClient.Views.PeopleView"
             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"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="30"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
       
       
        <Grid Grid.Row="0">
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
           
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition Width="3*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
           
            <TextBlock Text="First Name :" Grid.Row="0" Grid.Column="0"></TextBlock>
            <TextBlock Text="Last Name :" Grid.Row="1" Grid.Column="0"></TextBlock>
            <TextBlock Text="Age :" Grid.Row="2" Grid.Column="0"></TextBlock>


            <TextBox Grid.Row="0" Grid.Column="1" Height="30" Margin="0,0,0,5" Text="{Binding FirstName, Mode=TwoWay}"></TextBox>
            <TextBox Grid.Row="1" Grid.Column="1" Height="30" Margin="0,0,0,5" Text="{Binding LastName, Mode=TwoWay}"></TextBox>
            <TextBox Grid.Row="2" Grid.Column="1" Height="30" Margin="0,0,0,5" Text="{Binding Age, Mode=TwoWay}"></TextBox>
        </Grid>
       
        <StackPanel Grid.Row="1" Grid.Column="0"  Orientation="Horizontal">
            <Button x:Name="btnAdd" Content="Add" Margin="5" Command="{Binding AddCommand}"></Button>          
        </StackPanel>
       
        <DataGrid x:Name="dgPeople" Grid.Row="2" Grid.Column="0"  Margin="5"
                  ItemsSource="{Binding Persons, Mode=TwoWay}"
                  SelectionUnit="FullRow">

        </DataGrid>
    </Grid>
</UserControl>

   
Explanation:
Properties in the PeopleViewModel.cs are binded to elements in PeopleView.xaml like below for example
 <TextBox Grid.Row="0" Grid.Column="1" Height="30" Margin="0,0,0,5" Text="{Binding FirstName, Mode=TwoWay}"></TextBox>

 <DataGrid x:Name="dgPeople" Grid.Row="2" Grid.Column="0"  Margin="5"
                  ItemsSource="{Binding Persons, Mode=TwoWay}">          
        </DataGrid>


and command are binded like below
<Button x:Name="btnAdd" Content="Add" Margin="5" Command="{Binding AddCommand}"></Button>  

That's it now our WpfClient's View, ViewModel and Models are ready. In this post  I am showing my view in MainWindow.xaml and that can be done like below

In your MainWindow.xaml add below highlighted code

<Window x:Class="WpfClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"       
        Title="MainWindow"
        Height="350"
        Width="525"
        xmlns:views="clr-namespace:WpfClient.Views">
    <Grid>
      <views:PeopleView x:Name="peopleView"></views:PeopleView>
    </Grid>
</Window>


Now you need to make the connection between PeopleView.xaml and PeopleViewModel.cs so that they both can interact with each other. For this see below.

In MainWindow.xaml.cs add below highlighted code

using WpfClient.ViewModels;
namespace WpfClient
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            PeopleViewModel viewModel = new PeopleViewModel();
            this.peopleView.DataContext = viewModel;

        }
    }
}


That's all now run your application and if you donot have any errors it must work like below.Enter some values and press Add




Conclusion :
In this article we saw what is Model, View, and ViewModel and discussed benefits of MVVM. We deliberately created a simple application using MVVM pattern. We developed Model, ViewModel, and Views and saw step by step how communication between View and ViewModel can be done so that View and Model can be entirely unknown of each other. In last we also saw how we can show our View in MainWindow.xaml and how we can facilitate the communication between View and ViewModel.


I hope you enjoyed reading this post as much as I did while writing it. Please feel free to let me know your valuable and constructive comments and suggestions which can help me to make this article better and improve my technical and written skills. Last but not the least please excuse me for my grammar and typos.

Thanks and have a nice and wonderful day.