MVVM (Model View ViewModel) With WPF

This article is intended for the WPF -MVVM beginners with an assumption that they are aware of MVVM model.

You can get the theoretical details of MVVM on the Intenet before moving further.

In this article, I am implementing WPF solution in MVVM approach for small requirement mentioned below:

Requirement

We need to display the Employee details based on the Employee id value entered by the user using MV-VM approach.

Solution

Let's create the sample WPF projects with the following items/files.

  • View: MainWindow.Xaml
  •  MainWindow.Xaml.CS -->In MV-VM approach, codebehind plays very minor role.
  • View Model: SearchEmpVM.CS.
  • Model:Employee Class: EmpCls.cs – Created class file to hold the searched employee details.
    .

I will walk you through the Code of each entity in the order I have created.

EmpCls.cs (Entity class)

This class will contain the structure of Student entity. Here's the code:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6. namespace SampleWPFMVVM.Entity  
  7. {  
  8.     class EmpCls  
  9.     {  
  10.         private int _empNo;  
  11.         public int EmpNo  
  12.         {  
  13.             get  
  14.             {  
  15.                 return _empNo;  
  16.             }  
  17.             set  
  18.             {  
  19.                 _empNo = value;  
  20.             }  
  21.         }  
  22.         private string _name;  
  23.         public string Name  
  24.         {  
  25.             get  
  26.             {  
  27.                 return _name;  
  28.             }  
  29.             set  
  30.             {  
  31.                 _name = value;  
  32.             }  
  33.         }  
  34.         private string _designation;  
  35.         public string Designation  
  36.         {  
  37.             get  
  38.             {  
  39.                 return _designation;  
  40.             }  
  41.             set  
  42.             {  
  43.                 _designation = value;  
  44.             }  
  45.         }  
  46.         private string _department;  
  47.         public string Department  
  48.         {  
  49.             get  
  50.             {  
  51.                 return _department;  
  52.             }  
  53.             set  
  54.             {  
  55.                 _department = value;  
  56.             }  
  57.         }  
  58.     }  
  59. }  
View (MainWindow.Xaml)

Write the Xaml code as below:

 

  1. <Window x:Class="SampleWPFMVVM.MainWindow"    
  2.        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    
  4.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     
  5.         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    
  6.           mc:Ignorable="d"    
  7.           xmlns:vm="clr-namespace:SampleWPFMVVM.ViewModel"    
  8.       Title="MainWindow" Height="350" Width="333"    
  9.         x:Name="Window">    
  10.     <Window.DataContext>    
  11.        <vm:SearchEmpVM />    
  12.     </Window.DataContext>    
  13.     <Grid>    
  14.         <Grid.RowDefinitions>    
  15.             <RowDefinition Height="auto" ></RowDefinition>    
  16.             <RowDefinition Height="auto"></RowDefinition>    
  17.             <RowDefinition Height="auto"></RowDefinition>    
  18.             <RowDefinition  Height="auto" ></RowDefinition>    
  19.         </Grid.RowDefinitions>    
  20.     
  21.     
  22.         <StackPanel>    
  23.             <Grid Margin="0,51,0,-48" Grid.RowSpan="4">    
  24.                 <Grid.RowDefinitions>    
  25.                     <RowDefinition Height="auto"></RowDefinition>    
  26.                     <RowDefinition Height="auto"></RowDefinition>    
  27.                 </Grid.RowDefinitions>    
  28.                 <Grid.ColumnDefinitions>    
  29.                     <ColumnDefinition Width="auto"/>    
  30.                     <ColumnDefinition Width="auto"/>    
  31.                 </Grid.ColumnDefinitions>    
  32.                 <Label   Grid.Row="0" Grid.Column="0" Content="EmpId:"/>    
  33.                 <TextBox x:Name="txtEmpId1"   Text="{Binding  ElementName=Window,Path=DataContext.EmpId,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Row="0" Grid.Column="1" ></TextBox>    
  34.                 <StackPanel DataContext="{Binding SearchCls}" Grid.Column="1" Grid.Row="1">    
  35.                     <GroupBox>    
  36.                         <GroupBox.HeaderTemplate>    
  37.                             <DataTemplate>    
  38.                                 <Label    Content="Employee Information"/>    
  39.     
  40.                             </DataTemplate>    
  41.                         </GroupBox.HeaderTemplate>    
  42.                         <Grid >    
  43.                             <Grid.RowDefinitions>    
  44.                                 <RowDefinition Height="26*"/>    
  45.                                 <RowDefinition Height="26*"/>    
  46.                                 <RowDefinition Height="26*"/>    
  47.                                 <RowDefinition Height="26*"/>    
  48.                                 <RowDefinition Height="26*"/>    
  49.                             </Grid.RowDefinitions>    
  50.                             <Grid.ColumnDefinitions>    
  51.                                 <ColumnDefinition Width="Auto"/>    
  52.                                 <ColumnDefinition Width="Auto"/>    
  53.                                 <ColumnDefinition Width="Auto"/>    
  54.                                 <ColumnDefinition Width="Auto"/>    
  55.                                 <ColumnDefinition Width="Auto"/>    
  56.                             </Grid.ColumnDefinitions>    
  57.                             <Label   Grid.Row="0" Grid.Column="0" Content="Name:" Grid.ColumnSpan="3" />    
  58.                             <TextBox  Text="{Binding Name}" Grid.Row="0" Grid.Column="3" Width="174"/>    
  59.                             <Label   Grid.Row="1" Grid.Column="0" Content="Designation:" Grid.ColumnSpan="3"/>    
  60.                             <TextBox Text="{Binding Designation}" Grid.Row="1" Grid.Column="3" Width="174"/>    
  61.     
  62.                             <Label   Grid.Row="2" Grid.Column="0" Content="Department:" Grid.ColumnSpan="3" />    
  63.                             <TextBox  Text="{Binding Department}"  Grid.Row="2" Grid.Column="3" Width="174"/>    
  64.                              
  65.                         </Grid>    
  66.     
  67.     
  68.     
  69.                     </GroupBox>    
  70.                 </StackPanel>    
  71.     
  72.             </Grid>    
  73.     
  74.         </StackPanel>    
  75.     
  76.     
  77.     
  78.     </Grid>    
  79.     
  80.     
  81. </Window>    
Let me explain the important code lines highlighted in italic below,
  1. xmlns:vm="clr-namespace:SampleWPFMVVM.ViewModel" - This will import the namespace of our ViewModel "SearchEmpVM.CS".

  2. The following lines will bind the viewModel class as datacontext to the form:
    1. <Window.DataContext>  
    2.    <vm:SearchEmpVM />  
    3. </Window.DataContext>  
  3. The following code will bind the property "EmpId" of the viewModel class and fires the logic in the set procedure/block of the property of "EmpId" property.
    1. <TextBox x:Name="txtEmpId1"   Text="   {Binding  ElementName=Window,Path=DataContext.EmpId,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Row="0" Grid.Column="1" >  
    2. </TextBox>   
  4. The following code will bind the property "SearchCls" . This property will hold the object of the searched employees i.e "EmpCls" class,
    1. <StackPanel DataContext="{Binding SearchCls}" Grid.Column="1" Grid.Row="1">   
  5. The following code will bind the property "Name" of the class "searchCls" (internal property of "EmpCls"), so whenever the Value is assigned to "Name" property the value will be displayed in the text box. Similarly we will bind the properties of the "EmpCls" to all the controls to display the selected employee values.
    1. <TextBox Text="{Binding Name}" Grid.Row="0" Grid.Column="3" Width="174"/>   

ViewModel (SearchEmpVM.CS)

This will contain the business logic:

  1. using System;      
  2. using System.Collections.Generic;      
  3. using System.ComponentModel;      
  4. using System.Linq;      
  5. using System.Text;      
  6. using System.Threading.Tasks;      
  7. using SampleWPFMVVM.Entity; //namespace of Employee class         
  8.       
  9. namespace SampleWPFMVVM.ViewModel      
  10. {      
  11.     class SearchEmpVM : INotifyPropertyChanged      
  12.     {      
  13.         List<EmpCls> EmpList = new List<EmpCls>();      
  14.       
  15.       public SearchEmpVM()      
  16.         {      
  17.              // Add sample employee details into employee list    
  18.             EmpList.Clear();       
  19.             EmpList.Add(new EmpCls { EmpNo = 1, Name = "John", Department = "IT", Designation = "Developer" });      
  20.             EmpList.Add(new EmpCls { EmpNo = 2, Name = "Mark", Department = "IT", Designation = "Tester" });      
  21.             EmpList.Add(new EmpCls { EmpNo = 3, Name = "Robert", Department = "IT", Designation = "DB Developer" });      
  22.         
  23.         }      
  24.    
  25.    
  26.         #region properties      
  27.       
  28.         private EmpCls _searchcls = new EmpCls();      
  29.         public EmpCls SearchCls      
  30.         {      
  31.             get { return _searchcls; }      
  32.       
  33.             set      
  34.             {      
  35.                 _searchcls = value;      
  36.       
  37.                 RaisePropertyChanged("SearchCls");      
  38.       
  39.             }      
  40.         }      
  41.       
  42.         private int _empid;      
  43.         public int EmpId      
  44.         {      
  45.             get {      
  46.                 return _empid;      
  47.                   
  48.             }      
  49.       
  50.             set {      
  51.                 _empid = value;      
  52.       
  53.                 RaisePropertyChanged("EmpId");      
  54.                 PopulteEmpDetails(_empid);      
  55.             }      
  56.       
  57.               
  58.         }      
  59.    
  60.    
  61.         #endregion      
  62.       
  63.         private void PopulteEmpDetails(int _empid)      
  64.         {      
  65.                   
  66.                 SearchCls= EmpList.Where(x => x.EmpNo == _empid).Single();      
  67.                     
  68.         }      
  69.    
  70.    
  71.         #region INotifyPropertyChanged      
  72.       
  73.         public event PropertyChangedEventHandler PropertyChanged;      
  74.         public void RaisePropertyChanged(string propertyName)      
  75.         {      
  76.             if (PropertyChanged != null)      
  77.             {      
  78.                 PropertyChanged(thisnew PropertyChangedEventArgs(propertyName));      
  79.             }      
  80.         }      
  81.       #endregion      
  82.           
  83.     }      
  84. }    
Let us understand the code highlighted in the yellow color.

A . Our viewModel should implement interface to notify the client on binded property has changed .For more details

Refer the following link INotifyPropertyChanged.

B. Implement the method "RaisePropertyChanged" of interface "INotifyPropertyChanged" as highlighted in the above code

C. Call the method "RaisePropertyChanged" in the set procedures of all the properties which are binded to the controls.

For example:

Call as mentioned below:
  1. RaisePropertyChanged("EmpId"); //Pass the Property name as parameter  
D. In the set property procedure of "EmpId", Pass the "_empid" to userdefined method "PopulteEmpDetails".

Since we have bind this property to the text box "EmpId" in the xaml file , whenever the user enter the value in the textbox the logic in the set procedure of "EmpId" property will be exited. Hence the Textbox value will be passed to our method ""PopulteEmpDetails" as in the following code.
  1. private int _empid;    
  2. public int EmpId    
  3. {    
  4.     get {    
  5.         return _empid;    
  6.         
  7.     }    
  8.   
  9.     set {    
  10.         _empid = value;    
  11.   
  12.         RaisePropertyChanged("EmpId");    
  13.         PopulteEmpDetails(_empid);    
  14.     }    
  15.   
  16.     
  17. }   
E. The method "PopulteEmpDetails" will search the employee details from the list and set the List item to the property "SearchCls" as in the following code:
  1. private void PopulteEmpDetails(int _empid)    
  2. {    
  3.         
  4.         SearchCls= EmpList.Where(x => x.EmpNo == _empid).Single();    
  5.           
  6. }   
In the Set procedure of the "SearchCls" property , we are assigning the value to the object "_searchcls" (which is the object EmpCls Class) i.e we are storing the searched employee details in the object of the "EmpCls" class.

Since we are binding the properties of the "SearchCls" property (i.e properties of the Class "EmpCls") to the textboxes, whenever the value is set to property ""SearchCls" then the properties of the "EmpCls" will be filled and then the textboxes will be filled with the same values as in the following image.

Output

EmpID

Hence, we implemented the required functionality as shown in the preceding image. Hope this article gives you the understanding on the basic implementation technique.