Click here to Skip to main content
Click here to Skip to main content

MVVM Pattern in WPF: A Simple Tutorial for Absolute Beginners

, 11 Nov 2010
Rate this:
Please Sign up or sign in to vote.
MVVM pattern in WPF: A simple tutorial for absolute beginners.

Introduction

As part of learning the MVVM pattern, I tried to search many sites and blogs and found most of them explained the pattern in a complicated way. After some research, I cracked the very basic steps in MVVM pattern, and here I am trying to write an MVVM tutorial for absolute beginners.

I don’t think much more time or words need to be spent for explaining the various parts of MVVM and the relationship between MVVM and WPF. If you travel to the depths of WPF, you will realize that MVVM is the best suitable pattern for WPF (you might not understand the difference between these two).

As a formal procedure, I am giving a simple diagram and definition for MVVM:

I start this tutorial with two examples: WpfSimple.csproj and WpfMvvmTest.csproj.

For the sake of simplicity, in the first project (WpfSimple.csproj), we are avoiding the Model object (an example with Model will come later).

In the example WpfSimple, the View contains just a Button and no code-behind, but the button click event is loosely bound with the ViewModel. The bindings between the View and ViewModel are simple to construct because a ViewModel object is set as the DataContext of a View. If property values in the ViewModel change, those new values automatically propagate to the View via data binding. When the user clicks a button in the View, a command on the ViewModel executes to perform the requested action.

The View

The following code snippets are from the WpfSimple application (available with the tutorial):

<Window x:Class="WpfSimple.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfSimple"
        Title="MainWindow" Height="150" Width="370">
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
        <Grid>
        <Button Content="Click" 
                Height="23" 
                HorizontalAlignment="Left" 
                Margin="77,45,0,0" 
                Name="btnClick" 
                VerticalAlignment="Top" 
                Width="203"
                Command="{Binding ButtonCommand}" 
                CommandParameter="Hai" />
    </Grid>
</Window>

The ViewModel class used here is MainWindowViewModel, the object set as the DataContext of the View.

The ViewModel

The ViewModel class used over here is MainWindowViewModel.

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

namespace WpfSimple
{
    class MainWindowViewModel
    {
        private ICommand m_ButtonCommand;
        public ICommand ButtonCommand
        {
            get
            {
                return m_ButtonCommand;
            }
            set
            {
                m_ButtonCommand = value;
            }
        }

        public MainWindowViewModel()
        {
            ButtonCommand=new RelayCommand(new Action<object>(ShowMessage));
        }

        public void ShowMessage(object obj)
        {
            MessageBox.Show(obj.ToString());
        }
    }
}

You can see an empty code-behind file here. If you click on the button, it will prompt a message box, despite the lack of event handling methods in the Views. When the user clicks on buttons, the application reacts and satisfies the user's requests. This works because of bindings that were established on the Command property of Button displayed in the UI. The command object act as an adapter that makes it easy to consume a ViewModel's functionality from a View declared in XAML.

RelayCommand

RelayCommand is the custom class which is implemented in the ICommand interface. You can use any name instead of RelayCommand.
Its usage is as follows:

private ICommand m_ButtonCommand;
public ICommand ButtonCommand
{
get
{
return m_ButtonCommand;
}
set
{
m_ButtonCommand = value;
}
}

ButtonCommand=new RelayCommand(new Action<object>(ShowMessage));

public void ShowMessage(object obj)
{
// do Something
}

In the View using the ButtonCommand as follows:

<Button Content="Click" 
Command="{Binding ButtonCommand}" 
CommandParameter="Hai" /> 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace WpfSimple
{
    class RelayCommand : ICommand
    {
        private Action<object> _action;

        public RelayCommand(Action<object> action)
        {
            _action = action;
        }

        #region ICommand Members

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            if (parameter != null)
            {
                _action(parameter);
            }
            else
            {
                _action("Hello World");
            }
        }

        #endregion
    }
}

I think it’s a simple and standard approach. Another common approach is also available by using a nested inner class.

Next, I am going to discuss MVVM with an example that has a Model object. I will also talk a bit about the INotifyPropertyChanged Interface.

INotifyPropertyChanged

The INotifyPropertyChanged interface is used to notify clients, typically binding clients, when a property value has changed. The INotifyPropertyChanged interface contains an event called PropertyChanged. Whenever a property on a ViewModel / Model object has a new value, it can raise the PropertyChanged event to notify the WPF binding system of the new value. Upon receiving that notification, the binding system queries the property, and the bound property on some UI element receives the new value.

From the example WpfMvvmTest project, I am illustrating the following code:

public class Product:INotifyPropertyChanged
{
    private int m_ID;
    private string m_Name;
    private double m_Price;

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion

    public int ID
    {
        get
        {
            return m_ID;
        }
        set
        {
            m_ID = value;
            OnPropertyChanged("ID");
        }
    }
    public string Name
    {
        get
        {
            return m_Name;
        }
        set
        {
            m_Name = value;
            OnPropertyChanged("Name");
        }
    }
    public double Price
    {
        get
        {
            return m_Price;
        }
        set
        {
            m_Price = value;
            OnPropertyChanged("Price");
        }
    }
}

Another approach for binding the ViewModel object as a DataContext of the View is shown here:

public partial class App: Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        WpfMvvmTest.MainWindow window = new MainWindow();
        ProductViewModel VM = new ProductViewModel();
        window.DataContext = VM;
        window.Show();
    }
}

In the following code snippet, we use the inner class approach for implementing the ICommand interface; i.e., create a private nested class within the ViewModel class so that the command has access to private members of its containing ViewModel and does not pollute the namespace.

The disadvantage of this approach is that it is required to create a nested class that implements ICommand for each command exposed by a ViewModel, which will increase the size of the ViewModel class.

class ProductViewModel 
{
    private IList<Product> m_Products;
    public ProductViewModel()
    {
        m_Products = new List<Product>
        {
            new Product {ID=1, Name ="Pro1", Price=10},
            new Product{ID=2, Name="BAse2", Price=12}
        };
    }
    public IList<Product> Products
    {
        get
        {
            return m_Products;
        }
        set
        {
            m_Products = value;
        }
    }
    private ICommand mUpdater;
    public ICommand UpdateCommand
    {
        get
        {
            if (mUpdater == null)
                mUpdater = new Updater();
            return mUpdater;
        }
        set
        {
            mUpdater = value;
        }
    }
    private class Updater : ICommand
    {
        #region ICommand Members

        public bool CanExecute(object parameter)
        {
            return true;
        }
        public event EventHandler CanExecuteChanged;
        public void Execute(object parameter)
        {

        }
        #endregion
    }
}

From the following View XAML, you can understand how to bind a collection of objects to a list control.

<Window x:Class="WpfMvvmTest.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">
    <Grid Height="314">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ListView Name="ListViewEmployeeDetails" Grid.Row="1" 
               Margin="4,109,12,23"  ItemsSource="{Binding Products}"  >
            <ListView.View>
                <GridView x:Name="grdTest">
                    <GridViewColumn Header="ID" 
                          DisplayMemberBinding="{Binding ID}"  Width="100"/>
                    <GridViewColumn Header="Name" 
                          DisplayMemberBinding="{Binding Name}"  Width="100" />
                    <GridViewColumn Header="Price" 
                          DisplayMemberBinding="{Binding Price}" Width="100" />
                </GridView>
            </ListView.View>
        </ListView>
        <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" 
           Margin="80,7,0,0" Name="txtID" VerticalAlignment="Top" Width="178" 
           Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.ID}" />
        <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" 
           Margin="80,35,0,0" Name="txtName" VerticalAlignment="Top" Width="178" 
           Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.Name}" />
        <TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,61,0,0" 
           Name="txtPrice" VerticalAlignment="Top" Width="178" 
           Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.Price}" />
        <Label Content="ID" Grid.Row="1" HorizontalAlignment="Left" 
               Margin="12,12,0,274" Name="label1" />
        <Label Content="Price" Grid.Row="1" Height="28" 
           HorizontalAlignment="Left" Margin="12,59,0,0" 
           Name="label2" VerticalAlignment="Top" />
        <Label Content="Name" Grid.Row="1" Height="28" 
           HorizontalAlignment="Left" Margin="12,35,0,0" 
           Name="label3" VerticalAlignment="Top" />
        <Button Content="Update" Grid.Row="1" Height="23" 
           HorizontalAlignment="Left" Margin="310,40,0,0" Name="btnUpdate" 
           VerticalAlignment="Top" Width="141"
           Command="{Binding Path=UpdateCommand}"
                />
    </Grid>
</Window>

I hope you were able to get a small insight into MVVM from this article.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)

About the Author

ptMujeeb
Software Developer (Senior) BlackstoneCube
India India
6 years of extensive experience in Business Analysis, Implementation, Solution Providing, Designing, Developing, and testing of distributed applications.
Hands on experience in handling Multiple Projects simultaneously. Strong experience implementing enterprises distributed application using C#, VB.Net and Winform.
VSTO(Visual studio Tools for office) expert and successfully executed many project for Excel, Word and Outlook. Depth knowledge in .Net 3.5 with design and development experience in WCF and WPF application.
Currently Working in BlackstoneCube Business Solution
www.blackstonecube.com

Comments and Discussions

 
Generalnice walk through , easy collected and well presented bro ... Pinmembershrikanth_BG15-Jun-14 20:05 
QuestionHow to implement textbox events with this model? Pinmemberragha201210-Jun-14 21:08 
QuestionHow to implement textbox events with this? Pinmemberragha201210-Jun-14 21:08 
GeneralMy vote of 1 PinmemberMember 1058315018-Apr-14 5:31 
QuestionReally nice article Pinmembersathishmncl2-Dec-13 1:04 
GeneralMy vote of 2 PinmemberShweta Lodha7-Nov-13 10:09 
QuestionGood articles Pinmemberaschik ahamed29-Oct-13 16:35 
QuestionGreat Tutorial!!!!! PinmemberMember 776086221-Aug-13 17:58 
QuestionICommand Pinmembertam15111965@gmail.com29-Jun-13 16:18 
GeneralMy vote of 5 Pinmemberbozkirayazi27-May-13 2:28 
QuestionNice article PinmemberEugene_Buzin3-Apr-13 3:22 
GeneralMy vote of 5 PinmemberHerksNikaw25-Jan-13 1:06 
Simplify the concept!
GeneralMy vote of 4 PinmemberMember 947252822-Jan-13 1:58 
GeneralNice Articlw!! PinmemberJubinTK21-Jan-13 5:13 
Questionveryfy my one is correct Pinmemberprageeth.madhu21-Jan-13 3:35 
QuestionGood article. PinmemberEugene_Buzin16-Jan-13 1:54 
GeneralMy vote of 3 PinmemberMember 866348212-Jan-13 2:08 
QuestionTHANKS!! PinmemberNoe R. Garcia11-Jan-13 10:25 
GeneralMy vote of 5 PinmemberNawawi Sabri8-Jan-13 22:22 
SuggestionExcellent Article PinmemberRamesh Muthiah2-Jan-13 1:25 
Generalgood Pinmembertomas42124-Sep-12 3:52 
GeneralMy vote of 5 PinmemberMember 942805518-Sep-12 14:33 
GeneralMy vote of 5 PinmemberDadeeoh1-Aug-12 6:39 
GeneralMy vote of 4 Pinmembersamsabor17-Jul-12 11:03 
GeneralMy vote of 5 PinmemberFarhan Ghumra13-Jun-12 23:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 12 Nov 2010
Article Copyright 2010 by ptMujeeb
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid