DownLoad Link :: validations-WPF_MVVM.zip
Introduction
In this tip, users will learn simple WPF using MVVM architecture where I will implement simple WPF UserControl
s with the ViewModel-Model class property.
For the UI, I will use textbox
es with ListView DataGrid
buttons in MainWindow.xaml file which later I will bind it with properties of Model
Class.
The application is built with the aim to provide an overview of the many simple best practices used in .NET programming for the newbie developer.
Overview
:::: MVVM Data-Context ::::
One of the very useful features while designing WPF applications is DataContext
. In this application example, I am setting the DataContext
in the code and all the elements in the UI get to access the ViewModel
Class object.
Here I had taken the name of Model
Class as "Model
" and ViewModel
class as "UserViewModel
".
Using the Code
#### MainWindow.xaml.cs ####
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Assignments
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
UserViewModel obj = new UserViewModel();
this.DataContext = obj;
UserGrid.ItemsSource = obj._UsersList;
}
}
}
To understand the concept in a better way, I had taken some property in Model
Class like SapId
, Name
, Gender
, Num
& DOb
with get
-set
Property which I will bind with Data View-Model class through ObservableCollection
by creating its object of Model
Class named as "_UserList
".
Now we will set the Get
-Set
Property of Member Variables with INotifyProperty
changed. INotifyPropertyChanged
is an interface to provide the recent update from ViewModel
to UI in an application.
Command Binding is done with using ICommand
Interface of "Submit Button". Newbies usually get confused in MVVM model with Event Args of any UserControls
Event.
In order to avoid this ambiguity, I am creating an ICommand
Interface where I had binded Submit Button to "ClickCommand
" with Get
-Set
property in which I am calling a respective function to occur on clicking Submit Button.
#### ViewModel.cs ####
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Assignments
{
public class UserViewModel : INotifyPropertyChanged, IDataErrorInfo
{
public ObservableCollection<Model> _UsersList;
public UserViewModel()
{
_UsersList = new ObservableCollection<Model>();
}
private string name;
public string Name
{
get { return name; }
set { name = value; NotifyPropertyChanged("Name"); }
}
private string gender;
public string Gender
{
get { return gender; }
set { gender = value; NotifyPropertyChanged("Gender"); }
}
private string sapid;
public string SapId
{
get { return sapid; }
set { sapid = value; NotifyPropertyChanged("SapId"); }
}
private string num;
public string Num
{
get { return num; }
set { num = value; NotifyPropertyChanged("Num"); }
}
private DateTime? dob;
public DateTime? Dob
{
get { return dob; }
set { dob = value; NotifyPropertyChanged("Dob"); }
}
private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
if( _clickCommand == null)
{
_clickCommand = new CommandHandler(() => MyAction(), true);
}
return _clickCommand;
}
}
public void MyAction()
{
_UsersList.Add(new Model()
{ SapId = SapId, Name = Name, Gender = Gender, Dob = Dob, Num = Num });
Name = string.Empty;
SapId = string.Empty;
Gender = string.Empty;
Num = string.Empty;
}
private ICommand _clickClear;
public ICommand ClickClear
{
get
{
if (_clickClear == null)
{
_clickClear = new CommandHandler(() => MyClear(), true);
}
return _clickClear;
}
}
public void MyClear()
{
Name = string.Empty;
SapId = string.Empty;
Gender = string.Empty;
Num = string.Empty;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public string Error
{
get
{
return this[string.Empty];
}
}
public string this[string columnName]
{
get
{
string result = null;
if (columnName == "Dob")
{
if (Dob == null)
{
result = "Please enter DOB";
return result.ToString();
}
if (Dob == System.DateTime.Now)
{
result = "Please enter valid DOB";
return result;
}
}
if (columnName == "Gender")
{
if (this.Gender == null)
result = "Please enter your Gender";
return result;
}
if (columnName == "SapId")
{
if (this.SapId == null)
{
result = "Please enter sapid";
return result;
}
}
if (columnName == "Name")
{
if (Name == null)
{
result = "Please enter your Name";
return result;
}
if (Name.Length > 50)
{
result = "Name can not be longer than 50 chars";
return result;
}
string st = @"!|@|#|\$|%|\?|\>|\<|\*";
if (Regex.IsMatch(Name, st))
{
result = "Special chars not allowed";
return result;
}
string str = @"^[0-9]+$";
if (Regex.IsMatch(Name, str))
{
result = "Only chars are allowed";
return result;
}
}
if (columnName == "Num")
{
if (this.Num == null)
{
result = "Please enter Mobile Number";
return result;
}
if (this.Num.Length > 10)
return "Number cannot be more than 10 digit";
string str = @"^[0A-Za-z]+$";
if (Regex.IsMatch(Num, str))
{
result = "Only Numbers are allowed";
return result;
}
}
return result;
}
}
}
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}
public class Model
{
public string name;
public string gender;
public DateTime? dob;
public String num;
public string sapid;
public string Name
{
get{return name;}
set{name = value;}
}
public string Gender
{
get{return gender;}
set{gender = value;}
}
public DateTime? Dob
{
get{return dob;}
set{dob = value;}
}
public String Num
{
get{return num;}
set{num = value;}
}
public string SapId
{
get{return sapid;}
set{sapid = value;}
}
} }
In the above application, I took two ICommand
Interfaces - ClickCommand
& ClickClear
.
ClickCommand
is calling MyAction()
where I add data from UI to GridView
.
ClickClear
is calling MyClear()
where I make the values of all textboxes as null
except DOb
.
We can add numerous functions binded with any ICommand
Interface.
For ICommand
Interface to execute, there is a CommandHandler Class
in ViewModel.cs.
Now coming on to Validations, we have to take IDataErrorInfo
Interface with UserViewModel
Class because it is binded with DataContext
& INotifyPropertyChanged
.
In this String
Property, I am checking columnName
with my Property of Member Variables and using Regular Expressions for different Conditions as needed for Validations.
#### MainWindow.xaml ####
<Window x:Class="Assignments.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:Assignments"
Title="MainWindow" Height="463.433" Width="674.254">
-->
<Window.Resources>
<ControlTemplate x:Key="eTemplate">
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right" Foreground="White"
Background="Red" FontSize="13"
Text="{Binding ElementName=adorned,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" >
</TextBlock>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder x:Name="adorned"/>
</Border>
</DockPanel>
</ControlTemplate>
</Window.Resources>
<Grid>
<Label Content="Assignment I --> Registration Form with Validations"
HorizontalAlignment="Left" Margin="10,10,0,0"
VerticalAlignment="Top"/>
<Label Content="Name" HorizontalAlignment="Left"
Margin="180,77,0,0" VerticalAlignment="Top"/>
<TextBox Text="{Binding Name, ValidatesOnDataErrors=true,
UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource
ResourceKey=eTemplate}" HorizontalAlignment="Left" Height="23"
Margin="250,80,0,0" TextWrapping="Wrap"
VerticalAlignment="Top" Width="120"/>
<Label Content="SapId" HorizontalAlignment="Left"
Margin="180,107,0,0" VerticalAlignment="Top"/>
<TextBox Text="{Binding SapId,ValidatesOnDataErrors=true,
UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource
ResourceKey=eTemplate}" HorizontalAlignment="Left" Height="23"
Name="SapId" Margin="250,110,0,0" TextWrapping="Wrap"
VerticalAlignment="Top" Width="120"/>
<Label Content="DOB" HorizontalAlignment="Left"
Margin="180,138,0,0" VerticalAlignment="Top"/>
<TextBox Text="{Binding Dob,ValidatesOnDataErrors=true,
UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource
ResourceKey=eTemplate}" HorizontalAlignment="Left" Height="23"
Name="Dob" Margin="250,142,0,0" TextWrapping="Wrap"
VerticalAlignment="Top" Width="120"/>
<Label Content="Gender" HorizontalAlignment="Left"
Margin="177,177,0,0" VerticalAlignment="Top"
RenderTransformOrigin="0.652,0.516"/>
<TextBox Text="{Binding Gender,ValidatesOnDataErrors=true,
UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource
ResourceKey=eTemplate}" HorizontalAlignment="Left" Height="23"
Name="Gender" Margin="250,180,0,0" TextWrapping="Wrap"
VerticalAlignment="Top" Width="120"/>
<Label Content="Mobile No" HorizontalAlignment="Left"
Margin="173,208,0,0" VerticalAlignment="Top"/>
<TextBox Text="{Binding Num,ValidatesOnDataErrors=true, UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource ResourceKey=eTemplate}"
HorizontalAlignment="Left" Height="23" Name="Num"
Margin="250,211,0,0" TextWrapping="Wrap"
VerticalAlignment="Top" Width="120"/>
<Button Command="{Binding ClickCommand}" Content="Submit"
HorizontalAlignment="Left" Margin="180,255,0,0"
VerticalAlignment="Top" Width="75"/>
<Button Command="{Binding ClickClear}" Content="Reset"
HorizontalAlignment="Left" Margin="312,255,0,0"
VerticalAlignment="Top" Width="75"/>
-->
<ListView Name="UserGrid" ItemsSource="{Binding _UsersList}"
RenderTransformOrigin="0.538,-1.94" Margin="73,285,141,19" >
<ListView.View>
<GridView x:Name="grdTest" AllowsColumnReorder="true">
<GridViewColumn Header="SapId"
DisplayMemberBinding="{Binding SapId}" Width="60"/>
<GridViewColumn Header="Name"
DisplayMemberBinding="{Binding Name}" Width="55" />
<GridViewColumn Header="Gender"
DisplayMemberBinding="{Binding Gender}" Width="45" />
<GridViewColumn Header="DOB"
DisplayMemberBinding="{Binding Dob}" Width="150" />
<GridViewColumn Header="Number"
DisplayMemberBinding="{Binding Num}" Width="120" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
ScreenShots
This is how the application looks like on startup.
Solution Explorer
If you loved the way in which I explained to you, then stay tuned. I will soon be uploading more articles for you!!
I must Serve you to lead all ~ Sumit Anand