Monday 3 February 2014

WPF MVVM with easy 5 steps with example.



Hi Friends,

In this article I will tell you how MVVM used in WPF with easy 5 steps with example.
First I will tell you what is MVVM and how MVVM works then  I will show you practical example of this

1.      What is MVVM
MVVM is Model-View-ViewModel where the Model should know about nothing else, the ViewModel should only know about the Model (not the View), and the View should only know about the ViewModel (and not the Model).

.Model: This can be really simple, the goal here is for the ViewModel There is no any business logic here)

ViewModel: This should essentially communicate with Model except for exposing data for the View.

View: This should just bind to the ViewModel and make stuff look pretty.
The example application I described  following features:
  • User input
  • A list of data
The MVVM Framework

Step1: Create MVVM framework as shown in the below
The first thing that we are going to do is to create a minimal MVVM framework for us to use in the rest of the application. There are two important components of the framework.



Step 2: Create some common base classes for viewmodel and model. First create class ObservableObject this handles the implementation of the INotifyPropertyChanged interface. This interface allows update messages to be passed to the View. It should also be noted that all ViewModel classes that are bound to by the View should implement this (even if the values don’t change from the ViewModel)
The simplest implementation is as follows:

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChangedEvent(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
The second class is delegateCommand class it is an implementation of the ICommand interface. There is no default implementation
The simplest implementation is as follows:

public class DelegateCommand : ICommand
{
    private readonly Action _action;

    public DelegateCommand(Action action)
    {
        _action = action;
    }

    public void Execute(object parameter)
    {
        _action();
    }

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

    public event EventHandler CanExecuteChanged;
}
One thing to note is that CanExecute always returns true
Now we have our minimal MVVM framework, we can move on to create our application.

STEP 3:  Create Model Class
In this example I created Employee class with inherits ObservableObject

In employee class I created one constructor and 4 properties where I used RaisePropertyChangedEvent method of  ObservableObject


  public class Employee : ObservableObject
    {
        #region Constructor
        public Employee(string id = "", string name = "", int age = 0, string Address = "")
        {
            _id = id;
            _name = name;
            _age = age;
            _Address = Address;
        }
        #endregion

        #region Properties
        private string _id = string.Empty;

        public string ID
        {
            get { return _id; }
            set
            {
                _id = value;
                RaisePropertyChangedEvent("ID");
            }
        }

        private string _name = string.Empty;

        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                RaisePropertyChangedEvent("Name");
            }
        }

        private int _age = 0;

        public int Age
        {
            get { return _age; }
            set
            {
                _age = value;
                RaisePropertyChangedEvent("Age");
            }
        }

        private string _Address = string.Empty;

        public string Address
        {
            get { return _Address; }
            set
            {
                _Address = value;
                RaisePropertyChangedEvent("Address");
            }
        }
        #endregion

        #region IDataErrorInfo
        public string Error
        {
            get
            {
                return this[string.Empty];
            }
        }

        public string this[string propertyName]
        {
            get
            {
                string result = string.Empty;
                propertyName = propertyName ?? string.Empty;

                if (propertyName == string.Empty || propertyName == "ID")
                {
                    if (string.IsNullOrEmpty(this.ID))
                    {
                        result = "Employee ID is invalid. ID cannot be null or blank";
                    }
                    else if (System.Text.RegularExpressions.Regex.IsMatch
                        (this.ID, "[/!@#?/}[}{ ]"))
                    {
                        result = "Employee ID is invalid.                         ID cannot have special characters";
                    }
                }
                else if (propertyName == "Name")
                {
                    if (string.IsNullOrEmpty(this.Name))
                    {
                        result = "Name is invalid. ID cannot be null or blank";
                    }
                }
                else if (propertyName == "Age")
                {
                    if (Age > 150 || Age < 0)
                    {
                        result = "Age is invalid. Age should be between 0 and 150";
                    }
                }

                return result;
            }
        }
        #endregion
    }

STEP 4:  Create ViewModel
ViewModel is nothing but DataContext of View.  We also only have a single Presenter class in our ViewModel. This is, however, slightly more complex than the Model.
public class EmployeeListViewModel : ObservableObject
    {
        public ObservableCollection<Employee> Employees { get; private set; }
        public EmployeeListViewModel()
        {
            Employees = DBHelper.getData();
        }

        private Employee _SelectedEmployee;
        public Employee SelectedEmployee
        {
            get
            {
                return _SelectedEmployee;
            }
            set
            {
                _SelectedEmployee = value;
                RaisePropertyChangedEvent("SelectedEmployee");
            }
        }
    }

 Notice that we are inheriting from our MVVM framework ObservableObject, which provides our implementation of the INotifyPropertyChanged interface. Our presenter is exposing three properties that the View can bind to. We’ll look at them one at a time.

In the above example I created constructor of EmployeeListViewModel() and we have used observationcollection object . An ObservableCollection is a dynamic collection of objects of a given type. Objects can be added, removed or be updated with an automatic notification of actions
That’s all of the coding out of the way with, now we can move on to ‘drawing’ the UI.

STEP 5:  Create View
View is the look and feel. View is represented by xaml and its xaml.cs files. In the view we are only displaying data there is no any backend code.
In this example we have created one Window and one User con

Our final piece of UI description is the main window.
<Window ...
        Title="Converter"
        MinWidth="300"
        ResizeMode="NoResize"
        SizeToContent="WidthAndHeight">
   
<Window.DataContext>
        <VM:EmployeeListViewModel/>
    </Window.DataContext>
    <Grid>
        <ListView x:Name="listEmp"
       ItemsSource="{Binding Employees, UpdateSourceTrigger=PropertyChanged}"
       Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
       SelectedValue="{Binding SelectedEmployee,
       UpdateSourceTrigger=PropertyChanged}">
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding ID}"
                     Header="ID" Width="40" />
                    <GridViewColumn DisplayMemberBinding="{Binding Name}"
                     Header="Name" Width="100"/>
                </GridView>
            </ListView.View>
        </ListView>
        <View:EmployeeDetails Grid.Column="1"
              DataContext="{Binding SelectedEmployee,
              UpdateSourceTrigger=PropertyChanged}"/>

    </Grid>
   
</Window>

We created the User Control EmployeeDetails

<UserControl x:Class="WPF_MVVM_Easy_Steps.View.EmployeeDetails"
             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 Height="50*" />
            <RowDefinition Height="33*" />
            <RowDefinition Height="33*" />
            <RowDefinition Height="33*" />
            <RowDefinition Height="63*" />
            <RowDefinition Height="33*" />
            <RowDefinition Height="33*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="75*" />
            <ColumnDefinition Width="425*" />
        </Grid.ColumnDefinitions>
        <TextBlock Grid.ColumnSpan="2" Text="Employee Details"
              HorizontalAlignment="Center" VerticalAlignment="Center"
              FontFamily="Tahoma" FontStyle="Italic" FontWeight="Bold"
              Foreground="DodgerBlue" />
        <TextBlock Grid.Column="0" Grid.Row="1" Margin="5"  Text="ID :"
              HorizontalAlignment="Right" VerticalAlignment="Center" />
        <TextBox Grid.Column="1" Grid.Row="1" Margin="5,5,15,5"
              Text="{Binding ID,ValidatesOnDataErrors=true,
              NotifyOnValidationError=true}" />
        <TextBlock Grid.Column="0" Grid.Row="2" Margin="5" 
              Text="Name :" HorizontalAlignment="Right"
              VerticalAlignment="Center" />
        <TextBox Grid.Column="1" Grid.Row="2" Margin="5,5,15,5"
              Text="{Binding Name,ValidatesOnDataErrors=true,
              NotifyOnValidationError=true}" />
        <TextBlock Grid.Column="0" Grid.Row="3" Margin="5" 
              Text="Age :" HorizontalAlignment="Right"
              VerticalAlignment="Center" />
        <TextBox Grid.Column="1" Grid.Row="3" Margin="5,5,15,5"
              Text="{Binding Age,ValidatesOnDataErrors=true,
              NotifyOnValidationError=true}" />
        <TextBlock Grid.Column="0" Grid.Row="4" Margin="5" 
              Text="Address :" HorizontalAlignment="Right"
              VerticalAlignment="Center" />
        <TextBox Grid.Column="1" Grid.Row="4" Margin="5,5,15,5"
              Text="{Binding Address}" />

    </Grid>
</UserControl>

That all my friend, all together around 35 real lines of C# code and about 18 lines of XAML.
The full code is available on google Drive.
Happy Programming!!

If you have any query mail me to Sujeet.bhujbal@gmail.com     


Regards

Sujeet Bhujbal

------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------

2 comments:

  1. Employees = DBHelper.getData();
    getting error for DBHelper...
    plz explain.

    ReplyDelete
  2. U sir are a star. Simple and to the point! Thanx again

    ReplyDelete