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.
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:
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:
More information can be found at: https://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:
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
Anonymous
June 08, 2010
Hi, Can you use same code for combobox instead of textbox for data validation? Thanks, Mahesh.Anonymous
June 17, 2010
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 ToolingAnonymous
September 02, 2010
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? DSullyAnonymous
September 04, 2010
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, -ShichaoAnonymous
November 26, 2010
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