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
------------------------------------------------------------------------------------------------------------
Personal Website :-http://sujitbhujbal.wordpress.com/
Facebook :-www.facebook.com/sujit.bhujbal
CodeProject:-http://www.codeproject.com/Members/Sujit-Bhujbal
Linkedin :-http://in.linkedin.com/in/sujitbhujbal
Stack-Exchange: http://stackexchange.com/users/469811/sujit-bhujbal
Twitter :-http://twitter.com/SujeetBhujbal
JavaTalks :-http://www.javatalks.com/Blogger/sujit9923/
------------------------------------------------------------------------------------------------------------
Employees = DBHelper.getData();
ReplyDeletegetting error for DBHelper...
plz explain.
U sir are a star. Simple and to the point! Thanx again
ReplyDelete