Data Validation in Silverlight


In this blog, I will show you three approaches to do data validation in Silverlight.

Sample Scenario:

Let’s say I have a UI for users to enter their registration information for my website. When user input the email address in the UI below, I want to check if the format is valid or not. If not valid, we should give proper visual clues (error message) to help user to fix it.

image

 


Throw Exception in Property Setter

The idea of throwing exceptions from the property setters and reporting back to the UI was introduced in Silverlight 3. In this example, we will do the validation directly in the setter of the Email property. See the code snippet below.  

C#

public class User

{       

    private static string EmailPattern = @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";

    private string email;

    public string UserName

    {

        get;

        set;

    }

    public string Email

    {

        get

        {

            return email;

        }

        set

        {

            if (String.IsNullOrWhiteSpace(value))

            {

                throw new ArgumentException("Email address should not be empty.");

            }

            string input = value.Trim();

            if (!Regex.IsMatch(input, EmailPattern, RegexOptions.IgnoreCase))

            {

                throw new ArgumentException("Invalid email address format.");

            }

            this.email = input;

        }

    }

}

VB

Public Class User

    Private Shared EmailPattern As String = "^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"

    Private m_email As String

 

    Private _UserName As String

    Public Property UserName() As String

        Get

            Return _UserName

        End Get

        Set(ByVal value As String)

            _UserName = value

        End Set

    End Property

 

    Public Property Email() As String

        Get

            Return m_email

        End Get

        Set(ByVal value As String)

            If [String].IsNullOrWhiteSpace(value) Then

                Throw New ArgumentException("Email address should not be empty.")

            End If

            Dim input As String = value.Trim()

            If Not Regex.IsMatch(input, EmailPattern, RegexOptions.IgnoreCase) Then

                Throw New ArgumentException("Invalid email address format.")

            End If

            Me.m_email = input

        End Set

    End Property

End Class

 

In the Xaml, set the ValidatesOnExceptions property to true for the Email textbox. By setting it to true, the binding engine will catch all exceptions that are thrown when updating the source object using user input. If error occurs, the error message of the exception will be displayed in the UI. (Note: if you are using Drag-and-Drop Data Binding feature in Visual Studio, the following piece will be generated automatically)

<TextBox Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Name="emailTextBox" Text="{Binding Path=Email, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />

Hit F5 to run the application. You will see the following behavior:

image

image

 

 

Use Data Annotations

Starting from Silverlight 3, we can also use data annotations to do validations. First we need to add a reference to System.ComponentModel.DataAnnotations for the Silverlight client project.

Next, add Required and RegularExpression attribute to the Email property. And then call Validator  to validate the property in the setter.

C#

public class User

{      

    public string UserName

    {

        get;

        set;

    }

    /// <summary>

    /// Email is a required field. It should be provided with valid format.

    /// </summary>

    private string email;

    [Required]

    [RegularExpression(@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")]

    public string Email

    {

        get

        {

            return email;

        }

        set

        {

            Validator.ValidateProperty(value,

                new ValidationContext(this, null, null) { MemberName = "Email" });

            this.email = value;

        }

    }

}

VB

Public Class User

    Private _UserName As String

    Public Property UserName() As String

        Get

            Return _UserName

        End Get

        Set(ByVal value As String)

            _UserName = value

        End Set

    End Property

 

    ”’ <summary>

    ”’ Email is a required field. It should be provided with valid format.

    ”’ </summary>

    Private m_email As String

    <Required()> _

    <RegularExpression("^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")> _

    Public Property Email() As String

        Get

            Return m_email

        End Get

        Set(ByVal value As String)

            Validator.ValidateProperty(value, New ValidationContext(Me, Nothing, Nothing))

            Me.m_email = value

        End Set

    End Property

End Class

In the Xaml, set the ValidatesOnExceptions property to true for the Email textbox.

<TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="emailTextBox" Text="{Binding Path=Email, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />

 

Hit F5 to run the application. You will see the similar behavior:

image

image

More information can be found at: http://msdn.microsoft.com/en-us/library/dd901590(VS.95).aspx

 

 

Implement IDataErrorInfo 

The IDataErrorInfo idea was first introduced in Windows Forms, and then added into WPF 3.5. Now it is available in Silverlight 4! In this example, we will make the User class to implement the IDataErrorInfo interface.

The Error property should provide an error message indicating what is wrong with this object.  In this example, we just return null (or nothing in VB). In the Item property, we implement the logic to check the value for the specific column and return validation error message. See the code snippet below for the validation logic.

C#

public class User : System.ComponentModel.IDataErrorInfo

{

    private static string EmailPattern = @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";

    public string UserName

    {

        get;

        set;

    }

    public string Email

    {

        get;

        set;

    }

    public string Error

    {

        get { return null; }

    }

    public string this[string columnName]

    {

        get

        {                                               

            Debug.Assert(columnName != null, "columnName should not be null");

            if (columnName.Equals("Email", StringComparison.Ordinal))

            {

                if (String.IsNullOrWhiteSpace(this.Email))

                {

                    return "Email address should not be empty.";

                }

                if (!Regex.IsMatch(this.Email.Trim(), EmailPattern, RegexOptions.IgnoreCase))

                {

                    return "Invalid email address format.";

                }

            }

            return null;

        }

    }

}

VB

Public Class User

    Implements System.ComponentModel.IDataErrorInfo

    Private Shared EmailPattern As String = "^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"

 

    Private _UserName As String

    Public Property UserName() As String

        Get

            Return _UserName

        End Get

        Set(ByVal value As String)

            _UserName = value

        End Set

    End Property

 

    Private _Email As String

    Public Property Email() As String

        Get

            Return _Email

        End Get

        Set(ByVal value As String)

            _Email = value

        End Set

    End Property

 

    Public ReadOnly Property [Error]() As String

        Get

            Return Nothing

        End Get

    End Property

 

    Default Public ReadOnly Property Item(ByVal columnName As String) As String

        Get

            Debug.Assert(columnName IsNot Nothing, "columnName should not be null")

            If columnName.Equals("Email", StringComparison.Ordinal) Then

                If [String].IsNullOrWhiteSpace(Me.Email) Then

                    Return "Email address should not be empty."

                End If

                If Not Regex.IsMatch(Me.Email.Trim(), EmailPattern, RegexOptions.IgnoreCase) Then

                    Return "Invalid email address format."

                End If

            End If

            Return Nothing

        End Get

    End Property

End Class

 

In the Xaml, set the ValidatesOnErrors property to true instead of the ValidationOnExceptions.

<TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="emailTextBox" Text="{Binding Path=Email, Mode=TwoWay, ValidatesOnDataErrors=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />

Hit F5 to run the application. You will see the similar behavior:

image

image

 

Conclusion

Silverlight provides many different ways to do data validation, which is really handy when building business applications. With the power of Silverlight styles and control templates, we can go further to customize the way to display visual cues to the user.

Enjoy!


Comments (5)

  1. Mahesh says:

    Hi,

    Can you use same code for combobox instead of textbox for data validation?

    Thanks,

    Mahesh.

  2. XiaoyingGuo says:

    Hi Mahesh,

    Yes. The validation code works for all the controls that support validation. Please feel free to let me know if you meet with any problems.

    Thanks,

    Xiaoying Guo

    Program Manager, Visual Studio Business Applications Tooling

  3. dsully says:

    Thanks for the information.

    I get the data from a database using WCF and update or add back to database through WCF.

    How do I add to a service those requirements for validation?

    DSully

  4. Shichao Hu says:

    Hi DSully,

    If you are using WCF, then you will get the service code generated in the [Service Reference] directory. Looking at those generated classes, you will see that they are all in partial classes. So in this case, you can use the "IDataErrorInfo" approach described in this blog — means you can add another partial class into your project, and make it implement IDataErrorInfo.

    Hope this helps.

    Thanks,

    -Shichao

  5. DEBAL says:

    HI

    the code is very nice but whenever i'm doing work on the validation code i'm getting an Runtime  error Saying that ValidationException was unhandled by code .

    Press to the Continue icon in VS2010 silverlight Application it's doing nice.

    pl suggest me