Basically it is a step by step process,
1. Creation of Model
2. Creation of View Model Base
3. Creation Of View Model
4. Creation of Relay Command
5. Creation Of User Control (XAML)
6. Creation of View (XAML)
1. Creation of Model:
Model is nothing but a business entity and it acts as a layer to transmit data to the database/any data source. It is completely UI independent.
Below given the sample entity of member detail,
namespace WindowsApp
{
public class MemberDetail : INotifyPropertyChanged
{
private string _firstName;
public string FirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
OnPropertyChanged("FirstName");
}
}
private string _lastName;
public string LastName
{
get
{
return _lastName;
}
set
{
_lastName = value;
OnPropertyChanged("LastName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler eventHandler = PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
2. Creation of View Model Base:
It is the best approach to have “ViewModelBase” as base class for all the ViewModels by inheriting it. So that the common methods for all the ViewModels will be present in this Base Class.
Here the “ViewModelBase” Implemented the Interface “INotifyPropertyChanged” to get the notification whenever the property values get changed.
namespace WindowsApp.ViewModel
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
3. Creation Of View Model:
· “ViewModel” creates data of a “Model” type in order to bind it in the view.
· The Property which holds the data should be marked as “Public” to expose and bind it to view.
· It also inherits “ViewModelBase” to notify whenever property values get changed. To do this “PropertyChanged” event should call whenever setting a value to a property.
namespace WindowsApp.ViewModel
{
public class MemberDetailUserControlViewModel : ViewModelBase
{
public ICommand AddNewMemberCommand { get; set; }
public ObservableCollection<MemberDetail> MemberDetailList { get; set; }
public MemberDetailUserControlViewModel()
{
BindCommand();
MemberDetailList = new ObservableCollection<MemberDetail>
{
new MemberDetail()
{
FirstName = "First Name",
LastName = " Last Name"
}
};
}
private void BindCommand()
{
try
{
AddNewMemberCommand = new RelayCommand(AddNewMemberDetail);
}
catch (Exception)
{
throw;
}
}
private void AddNewMemberDetail(object parameter)
{
try
{
//Message
MemberDetailList.Add(new MemberDetail()
{
FirstName = FirstName,
LastName = LastName
});
FirstName = "";
LastName = "";
}
catch (Exception)
{
throw;
}
}
private string firstName;
public string FirstName
{
get
{
return firstName;
}
set
{
firstName = value;
OnPropertyChanged("FirstName");
}
}
private string lastName;
public string LastName
{
get
{
return lastName;
}
set
{
lastName = value;
OnPropertyChanged("LastName");
}
}
}
}
4. Creation of Relay Command:
Here created a custom class named “RelayCommand” to invoke an event present in the “ViewModel” whenever command gets triggered from the view. Basically “Commands” bounds like data to input bindings, button, and checkbox/ radio buttons.
On user action, view executes commands which are implemented in the view model. Below given the code of “RelayCommand” which implements the “ICommand” interface
namespace WindowsApp.Helper
{
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
public RelayCommand(Action<object> execute) : this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if(execute==null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
}
}
5. Creation Of User Control (XAML):
MemberDetailUserControl:
Basically user controls are created to reuse it in many Views. Below created “MemberDetailUserControl” which will be used in the View. Here, Commands and Bindings mentioned in the “MemberDetailUserControlViewModel” are binded here to display the data and to invoke the events on user action.
<UserControl x:Class="WindowsApp.UserControl.MemberDetailUserControl"
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="372" d:DesignWidth="658">
<Grid>
<Grid.RowDefinitions>
<RowDefinition x:Uid="ColumnDefinition_1" Height="Auto" />
<RowDefinition x:Uid="ColumnDefinition_2" Height="Auto" />
<RowDefinition x:Uid="ColumnDefinition_3" Height="Auto" />
<RowDefinition Height="103*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition x:Uid="ColumnDefinition_1" Height="Auto" />
<RowDefinition x:Uid="ColumnDefinition_2" Height="Auto" />
<RowDefinition x:Uid="ColumnDefinition_3" Height="Auto" />
</Grid.RowDefinitions>
<Label Content="First Name" Height="28" HorizontalAlignment="Left" Margin="10,11,0,0" Name="LblName" VerticalAlignment="Top" ClipToBounds="False" FontWeight="Bold" />
<Label Content="Last Name" Height="28" HorizontalAlignment="Left" Margin="11,40,0,0" Name="LblPassword" VerticalAlignment="Top" ClipToBounds="False" FontWeight="Bold" />
<TextBox Name="TxtFirstName" Height="23" HorizontalAlignment="Left" Margin="82,11,0,0" Text="{Binding FirstName}" VerticalAlignment="Top" Width="120" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="82,40,0,0" Name="TxtLastName" Text="{Binding LastName}" VerticalAlignment="Top" Width="120" />
<Button Content="Add" Command="{Binding AddNewMemberCommand}" Height="23" HorizontalAlignment="Left" Margin="82,69,0,0" Name="BtnSubmit" VerticalAlignment="Top" Width="40" Foreground="DarkSlateGray" ForceCursor="True" Background="AntiqueWhite" FontWeight="Bold" />
</Grid>
<ScrollViewer Grid.RowSpan="3" Grid.Row="1" Height="150" HorizontalAlignment="Left" Margin="10,10,0,0" Name="ScrollViewer1" VerticalAlignment="Top" Width="208">
<DataGrid Name="memberDataGrid" AutoGenerateColumns="False" ItemsSource="{Binding MemberDetailList}"
HorizontalAlignment="Left" VerticalAlignment="Top" Width="192" Grid.Row="1" GridLinesVisibility="None" AlternatingRowBackground="BlanchedAlmond" AreRowDetailsFrozen="True" RowHeight="20" FontFamily="Vrinda" FontSize="12" CanUserResizeRows="False" CanUserSortColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding FirstName}" Header="First Name" />
<DataGridTextColumn Binding="{Binding LastName}" Header="Last Name" />
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
</Grid>
</UserControl>
MemberDetailUserControl.cs:
For DataContext, user control class will create an instance of “MemberDetailUserControlViewModel” to access all the data/properties which are exposed in the ViewModel.
namespace WindowsApp.UserControl
{
/// <summary>
/// Interaction logic for MemberDetailUserControl.xaml
/// </summary>
public partial class MemberDetailUserControl : System.Windows.Controls.UserControl
{
private readonly MemberDetailUserControlViewModel _memberDetailUserControlViewModel;
public MemberDetailUserControl()
{
InitializeComponent();
_memberDetailUserControlViewModel = new MemberDetailUserControlViewModel();
this.DataContext = _memberDetailUserControlViewModel;
}
}
}
6. Creation of View (XAML):
Here created a view which is using “MemberDetailUserControl” UI. There will not be any code logic in the code behind file of “View”. Only the implemented “UserControl” will create the DataContext of a “ViewModel”.
<Window x:Class="WindowsApp.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:memberDetailUserControl="clr-namespace:WindowsApp"
xmlns:userControl="clr-namespace:WindowsApp.UserControl"
Title="Member Detail" Height="350" Width="282">
<Grid Width="488">
<userControl:MemberDetailUserControl x:Uid="memberDetailUserControl:MemberDetailUserControl1" Margin="12,12,244,12" />
</Grid>
</Window>
Benefits of MVVM Pattern:
1. ViewModel may have any number of models that need to be binded in view.
2. Because Views and ViewModel are loosely coupled, View models can be reused in many views.
3. This pattern is an example for Test Driven Development as we can test the “ViewModels” without considering any views.
4. The Views can be developed standalone by specialised UI designers by agreeing the fields and naming alone. This will speed up the development cycle.