Click here to Skip to main content
15,880,469 members
Articles / Desktop Programming / XAML

Validation in Silverlight

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
26 Apr 2010CPOL5 min read 33.2K   13   2
Getting started with the basics of validation in Silverlight

Getting Started with the Basics

Validation in Silverlight can get very complex pretty easily. 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 exactly 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.

image

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, an ValidationException 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.

XML
<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.

C#
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 PropertyChangedEventHandler PropertyChanged=delegate { };
}

The last thing that has to be done is to allow binding an instance of the PersonData class to the DataContext of the control. This is done in the code behind file.

C#
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 a case. With a few changes to the XAML, an error summary like below can be added.

image

First, add a namespace to the XAML so the control can be used. Add the following line to the header of the .xaml file.

XML
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 shown 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.

XML
<Controls:ValidationSummary Margin="8"/> 

The ValidationSummary control has to be notified that an ValidationException 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.

XML
<TextBox Width="150"
    x:Name="Name"
    Text="{Binding Name, 
                   Mode=TwoWay, 
                   ValidatesOnExceptions=True, 
                   NotifyOnValidationError=True}"/> 

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 always stays 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:

C#
[Required]
public string Name
{
  get { return _name; }
  set
  {
    if (_name != value)
    {
      Validator.ValidateProperty(value, 
              new ValidationContext(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 ValidationContext class 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:

RequiredAttribute

Specifies that a value must be provided

RangeAttribute

The provided value must fall in the specified range

RegularExpressionAttribute

Validates the value matches the regular expression

StringLengthAttribute

Checks if the number of characters in a string falls between a minimum and maximum amount

CustomValidationAttribute

Use a custom method to validate the value

DataTypeAttribute

Specify a data type using an enum or a custom data type

EnumDataTypeAttribute

Makes sure the value is found in an enum

ValidationAttribute

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.

C#
[Required]
[Range(0,125,ErrorMessage = "Value is not a valid age")]
public int 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: 

C#
[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.

Delayed Validation

Having properties marked as required can be very useful. The only downside to the technique described earlier is that you have to change the value in order to get it validated. What if you start out with empty an empty entry form? All fields are empty and thus won’t be validated. With this small trick, you can validate at the moment the user clicks the submit button.

XML
<TextBox Width="150"
         x:Name="NameField"
         Text="{Binding Name, 
                        Mode=TwoWay, 
                        ValidatesOnExceptions=True,
                        NotifyOnValidationError=True, 
                        UpdateSourceTrigger=Explicit}"/> 

By default, when a TwoWay bound control loses focus the value is updated. When you added validation like I’ve shown you earlier, the value is validated. To overcome this, you have to tell the binding update explicitly by setting the UpdateSourceTrigger binding property to Explicit:

C#
private void SubmitButtonClick(object sender, RoutedEventArgs e)
{
  NameField.GetBindingExpression(TextBox.TextProperty).UpdateSource();
} 

This way, the binding is in two direction but the source is only updated, thus validated, when you tell it to. In the code behind, you have to call the UpdateSource method on the binding expression, which you can get from the TextBox

Conclusion

Data validation is something you’ll probably want on almost every entry form. I always thought it was hard to do, but it wasn’t. If you can throw an exception, you can do validation.

If you want to know anything more in depth about something I talked about in this article, let me know. I might write an entire post.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Velicus B.V.
Netherlands Netherlands
Microsoft MVP Client Dev . Founder of http://StoreAppsUG.nl, the Dutch Windows Store apps and Windows Phone apps usergroup. XAML / HTML5 developer. Writer. Composer. Musician.

Twitter
@Sorskoot

Awards / Honers
• October 2010,2011,2012,2013: Awarded Microsoft Expression Blend MVP
• June 2009: Second Place in the WinPHP challenge
• February 2009: Runner-up in de Mix09 10k Challenge
• June 2008: Winner of the Microsoft expression development contest at www.dekickoff.nl

Bio
I started programming around 1992, when my father had bought our first home computer. I used GWBasic at that time. After using QBasic and Pascal for a few years I started to learn C/C++ in 1996. I went to the ICT Academy in 1997 and finnished it in 2002. Until December 2007 I worked as a 3D specialist. Besides modelling I worked on different development projects like a 3D based Scheduler and different simultion tools in C# and Java. Though out the years I've gained much experience with ASP.NET, Silverlight, Windows Phone and WinRT.

Comments and Discussions

 
GeneralMy vote of 5 Pin
rzvdaniel30-Dec-11 21:19
rzvdaniel30-Dec-11 21:19 
GeneralCustom Validation in RegistrationData.cs Pin
SethJam6-Jan-11 9:59
SethJam6-Jan-11 9:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.