Understanding Validation in Silverlight
Hi Friends,
In
this article i will tell you 4 types of validations in silverlight in brief.
There are 4 types of validation in silverlight 4.0.
1.The basic validation
Validation
in Silverlight can get very complex and easy. The DataGrid
control is the only control that does data validation automatically, but often
you want to validate your own entry form. Values a user may enter in this form
can be restricted by the customer and have to fit an exact fit to a list of
requirements or you just want to prevent problems when saving the data to the
database. Showing a message to the user when a value is entered is pretty
straight forward as I’ll show you in the following example.
This
(default) Silverlight textbox is data-bound to a simple data class. It has to
be bound in “Two-way” mode to be sure the source value is updated when the
target value changes. The INotifyPropertyChanged
interface must be implemented by the data class to get the notification system
to work. When the property changes a simple check is performed and when it
doesn’t match some criteria anValidationException
is thrown. The ValidatesOnExceptions
binding attribute is set to True to tell the textbox it should handle the
thrown ValidationException.
Let’s have a look at some code now.
The
xaml should contain something like below. The most important part is inside the
binding. In this case the Text property is bound to the “Name” property in TwoWay mode. It is also told to validate on
exceptions. This property is false by default.
<StackPanel
Orientation="Horizontal">
<TextBox
Width="150"
x:Name="Name"
Text="{Binding Path=Name,
Mode=TwoWay,
ValidatesOnExceptions=True}"/>
<TextBlock
Text="Name"/>
</StackPanel>
The
data class in this first example is a very simplified person class with only
one property: string Name. The INotifyPropertyChanged
interface is implemented and the PropertyChanged
event is fired when the Name property changes. When the property changes a
check is performed to see if the new string is null or empty. If this is the
case a ValidationException
is thrown explaining that the entered value is invalid.
public class
PersonData:INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
if(string.IsNullOrEmpty(value))
throw new
ValidationException("Name is required");
_name = value;
if (PropertyChanged != null)
PropertyChanged(this, new
PropertyChangedEventArgs("Name"));
}
}
}
public event
PropertyChangedEventHandlerPropertyChanged=delegate { };
}
The last thing that has to be done is letting binding an instance of the PersonData class to the DataContext of the control. This is done in the code behind file.
public partial class Demo1 :
UserControl
{
public Demo1()
{
InitializeComponent();
this.DataContext = new
PersonData() {Name = "Johnny Walker"};
}
}
Error Summary
In
many cases you would have more than one entry control. A summary of errors
would be nice in such case. With a few changes to the xaml an error summary,
like below, can be added.
First,
add a namespace to the xaml so the control can be used. Add the following line
to the header of the .xaml file.
xmlns:Controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input"
Next,
add the control to the layout. To get the result as in the image showed
earlier, add the control right above the StackPanel
from the first example. It’s got a small margin to separate it from the textbox
a little.
<Controls:ValidationSummary
Margin="8"/>
The ValidationSummary
control has to be notified that anValidationException occurred. This can be
done with a small change to the xaml too. Add the NotifyOnValidationError
to the binding expression. By default this value is set to false, so nothing
would be notified. Set the property to true to get it to work.
<TextBox
Width="150"
x:Name="Name"
Text="{Binding Name,
Mode=TwoWay,
ValidatesOnExceptions=True,
NotifyOnValidationError=True}"/>
2.Data annotation
Validating
data in the setter is one option, but not my personal favorite. It’s the
easiest way if you have a single required value you want to check, but often
you want to validate more. Besides, I don’t consider it best practice to write
logic in setters. The way used by frameworks like WCF Ria Services
is the use of attributes on the properties. Instead of throwing exceptions you
have to call the static method ValidateProperty
on the Validator
class. This call stays always the same for a particular property, not even when
you change the attributes on the property.
To
mark a property “Required” you can use the RequiredAttribute.
This is what the Name property is going to look like:
[Required]
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
Validator.ValidateProperty(value,
newValidationContext(this,
null, null){ MemberName = "Name" });
_name = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
The ValidateProperty
method takes the new value for the property and an instance of ValidationContext.
The properties passed to the constructor of the ValidationContextclass
are very straight forward. This part is the same every time. The only thing
that changes is the MemberName
property of the ValidationContext.
Property has to hold the name of the property you want to validate. It’s the
same value you provide the PropertyChangedEventArgs
with.
The System.ComponentModel.DataAnnotation contains eight different
validation attributes including a base class to create your own.
They
are:
Specifies
that a value must be provided.
|
|
The
provide value must fall in the specified range.
|
|
Validates
is the value matches the regular expression.
|
|
Checks
if the number of characters in a string falls between a minimum and maximum
amount.
|
|
Use
a custom method to validate the value.
|
|
Specify
a data type using an enum or a custom data type.
|
|
Makes
sure the value is found in aenum.
|
|
A
base class for custom validation attributes
|
All of
these will ensure that an validation exception is thrown, except the DataTypeAttribute.
This attribute is used to provide some additional information about the
property. You can use this information in your own code.
[Required]
[Range(0,125,ErrorMessage
= "Value is not a valid age")]
publicint Age
{
It’s
no problem to stack different validation attributes together. For example, when
an Age is required and must fall in the range from 0 to 125:
[Required,
StringLength(255,MinimumLength = 3)]
public string Name
{
Or in
one row like this, for a required Name with at least 3 characters and a maximum
of 255:
3. IDataErrorInfo
I have
used ‘IDataErrorInfo’ interface which is newly provided in Silverlight 4.0
under System.ComponentModelnamepsace. This interface needs to be implemented by
the data entity class which helps in defining custom validations for data to be
entered using Silverlight 4.0 UI controls.
The IDataErrorInfo
interface came with Silverlight 4. If we want implement validation with this
interface we should implement it in our ViewModel (one property and one
method). Usually developers write own class handler, which store validation
errors)
publicclassEmployee
: INotifyPropertyChanged, IDataErrorInfo
{
int
_EmpNo;
publicintEmpNo
{
get
{
return _EmpNo;
}
set
{
_EmpNo = value;
ChangeValue("EmpNo");
}
}
string
_EmpName;
publicstringEmpName
{
get
{
return _EmpName;
}
set
{
_EmpName = value;
ChangeValue("EmpName");
}
}
publiceventPropertyChangedEventHandlerPropertyChanged;
publicvoidChangeValue(stringPropName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, newPropertyChangedEventArgs(PropName));
}
}
string
err;
publicstring
Error
{
get { return err; }
}
publicstringthis[stringcolumnName]
{
get
{
stringmsg = null;
if (columnName == "EmpNo")
{
if (EmpNo<= 0 || EmpNo.ToString().Length
> 5)
{
msg = "EmpNo must not be Negative or Lenght
must not be more than 5.";
}
}
if (columnName == "EmpName")
{
if (EmpName.Equals(string.Empty))
{
msg = "EmpName is must,Please enter Correct
Value.";
}
}
returnmsg;
}
}
}
In
XAML
<TextBoxGrid.Row="1"Height="23"
HorizontalAlignment="Left"Margin="148,21,0,0"
Name="txtEno"
Text="{Binding
Path=EmpNo,Mode=TwoWay,ValidatesOnDataErrors=True}"
VerticalAlignment="Top"Width="120"/>
<TextBoxGrid.Row="1"Height="23"HorizontalAlignment="Left"
Margin="148,66,0,0"Name="txtEname"
Text="{Binding
Path=EmpName,Mode=TwoWay,ValidatesOnDataErrors=True}"
VerticalAlignment="Top"Width="120"
/>
The INotifyDataErrorInfointerface came with
Silverlight 4 too. The main advantage of this interface you can do synchronous
(like in previous samples) and asynchronous validation too. You can wait
validation from server, and only after that tell to interface that all ok or
some validation error occurred. I like this way of validation more than other
publicIEnumerableGetErrors(stringpropertyName)
{
if (_errorMessages.ContainsKey(propertyName))
return _errorMessages[propertyName];
returnnewstring[0];
}
publicboolHasErrors
{
get { return _errorMessages.Count> 0; }
}
Happy Programming ! !RegardsSujeet Bhujbal--------------------------------------------------------------------------------------------------------------------Personal Website :-http://sujitbhujbal.wordpress.com/Facebook :-www.facebook.com/sujit.bhujbalCodeProject:-http://www.codeproject.com/Members/Sujit-BhujbalLinkedin :-http://in.linkedin.com/in/sujitbhujbalStack-Exchange: http://stackexchange.com/users/469811/sujit-bhujbalTwitter :-http://twitter.com/SujeetBhujbalJavaTalks :-http://www.javatalks.com/Blogger/sujit9923/--------------------------------------------------------------------------------------------------------------------
No comments:
Post a Comment