SIGN UP MEMBER LOGIN:    
ARTICLE

WPF MVVM Pattern: A Simple Tutorial for Absolute Beginners

Posted by Mujeeb Rahman Articles | WPF with C# November 12, 2010
After some research I cracked the very basic steps in MVVM pattern, and then trying to write MVVM tutorials for absolute beginners.
Reader Level:
Download Files:
 

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

I don't think much more time or words spend for explaining various part of MVVM and the relationship  between MVVM and WPF. If you go to the depth 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

1.gif 

I start this tutorial with two examples, i.e WpfSimple.csproj and WpfMvvmTest.csproj

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

In the example WpfSimple, the view contains only a Button and no code behind, but its click event is loosely bound with ViewModel. The bindings between 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 

2.gif
 
The following code snippets are coming from WpfSimple application (available with 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>

ViewModel class used here is MainWindowViewModel, which is the object set as the DataContext of a view.

        xmlns:local="clr-namespace:WpfSimple"
<Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>

The ViewModel

ViewModel  class used over here is  MainWindowViewModel.cs

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. 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 acts as an adapter that makes it easy to consume a ViewModel's functionality from a view declared in XAML.

                Command="{Binding ButtonCommand}" 
                CommandParameter="Hai"

RelayCommand

In this example RelayCommand class is used for implementing ICommad object. I think it's a simple and standard approach. One more common approach is also available by using nested inner class (will  explain later).

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
    }
}

Next, I am going to discuss MVVM with an example having the Model object. So I like talk bit about INotifyPropertyChanged Interface

INotifyPropertyChanged

The INotifyPropertyChanged interface is used to notify clients, typically binding clients, which 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  taking 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 ViewModel object  as datacontext of View

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 used inner class approach for implementing 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 requires creation of 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 object to the 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=UpdateCommad}"
                />
    </Grid>
</Window>

So...  I hope you can get a small insight about MVVM from this article.

Login to add your contents and source code to this article
Article Extensions
Contents added by satya rai on Jun 20, 2011
share this article :
post comment
 

Good explanation for beginners. Im missing a bit in depth information though. For example about the ICommand interface.

Posted by michel Feb 29, 2012

It's really help for beginners

Posted by Manish Singh Dec 10, 2011

Really very good article

Posted by Arjun Panwar Dec 08, 2011

Nice presentation Rahman

Posted by Akash Ahlawat Dec 08, 2011

Thanks for sharing...

Posted by Dinesh Beniwal May 09, 2011
6 Months Free & No Setup Fees ASP.NET Hosting!
Become a Sponsor
PREMIUM SPONSORS
  • Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
    ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications. Visit DynamicPDF here
Become a Sponsor