WPF Validation






3.26/5 (9 votes)
This article describes the Validation process in WPF

Introduction
In this article, I have discussed the validation process in WPF. For understanding the validation process, I have created a simple application which divides numbers entered in text boxes and displays the result in a label. If the user enters invalid data, it displays the appropriate error messages.
Background
While dividing two numbers, the most likely issues can be related to handling of non-numeric data and dividing by zero. In this article, I have described how to do data validation for such errors. In this application, I have validated that the user does not enter non-numeric data and zero in the textboxes. I have developed the application using Microsoft Visual C# 2010 Express Edition (Microsoft .NET Framework Version 4.0.21006).
Using the Code
To use the validator function, we must first declare the namespace
where it will be found. This is done by adding an attribute for the root Window
element as follows:
xmlns:local="clr-namespace:ValidationExample"
The complete XAML code for the window
element is as follows:
<Window x:Class="ValidationExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ValidationExample"
Title="Number Division" Height="300" Width="300"
Loaded="Window_Loaded">
In the above code, the Window Loaded event called Window_Loaded
is added to initialize our data
object with initial values. The code-behind code for the Window_Loaded
event is as follows:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MyData data = new MyData("", "");
t1.DataContext = data;
t2.DataContext = data;
}
The MyData
class represents our data. It consists of three properties FirstNumber
, SecondNumber
and Division
. Its code is as follows:
public class MyData
{
public object FirstNumber // FirstNumber Property
{
get;
set;
}
public object SecondNumber // SecondNumber Property
{
get;
set;
}
public object Division // Division Property
{
get
{
try
{
double n1 = Convert.ToDouble(FirstNumber.ToString());
double n2 = Convert.ToDouble(SecondNumber.ToString());
double n3 = n1 / n2;
return n3;
}
catch (Exception)
{
return null;
}
}
}
public MyData(object FirstNumber, object SecondNumber) // Constructor
{
this.FirstNumber = FirstNumber;
this.SecondNumber = SecondNumber;
}
}
To display the result of division, I have created a template with a key called myTemplate
as follows:
<Window.Resources>
<DataTemplate x:Key="myTemplate" DataType="ValidationExample.MyData">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Division: "/>
<TextBlock Text="{Binding Path=Division}"/>
</StackPanel>
</DataTemplate>
The above code displays the result of division by binding the Division
property to a TextBlock
. To display error if any validation error occurs, I have created a control template with a key called errorTemplate
as follows:
<ControlTemplate x:Key="errorTemplate">
<StackPanel>
<TextBlock Foreground="Red">Invalid Value!!!</TextBlock>
<AdornedElementPlaceholder/>
</StackPanel>
</ControlTemplate>
</Window.Resources>
In the above code, the AdornedElementPlaceholder
element is used to display the error message. The user interface to accept two numbers from the user and display the result of division is created as follows:
<Canvas>
<Label Canvas.Left="10" Canvas.Top="40" Content="Enter First Number: "/>
<TextBox x:Name="t1" Canvas.Left="135" Canvas.Top="40" Width="100"
Height="30" Validation.ErrorTemplate="{StaticResource errorTemplate}"
Validation.Error="NumberError">
<Binding Path="FirstNumber" NotifyOnValidationError="True">
<Binding.ValidationRules>
<local:NumberValidator/>
</Binding.ValidationRules>
</Binding>
</TextBox>
<Label Canvas.Left="10" Canvas.Top="80" Content="Enter Second Number: "/>
<TextBox x:Name="t2" Canvas.Left="135" Canvas.Top="80" Width="100"
Height="30" Validation.ErrorTemplate="{StaticResource errorTemplate}"
Validation.Error="NumberError">
<Binding Path="SecondNumber" NotifyOnValidationError="True">
<Binding.ValidationRules>
<local:NumberValidator/>
</Binding.ValidationRules>
</Binding>
</TextBox>
<Button Name="b1" Canvas.Left="10" Canvas.Top="120" Width="225"
Content="Divide" Click="b1_Click"/>
<Label x:Name="lblResult" Canvas.Left="10"
Canvas.Top="160" ContentTemplate="{StaticResource myTemplate}"/>
</Canvas>
</Window>
In the above code, the Canvas
element is used as a container. Two TextBox
es t1
and t2
are bound to the properties FirstNumber
and SecondNumber
respectively. The error templates for the two textbox
es are specified using the Validation.ErrorTemplate
attribute.
The <Binding>
child element of the textbox
is used to bind the textbox
to its corresponding data property (FirstNumber
and SecondNumber
). The custom validation class is specified by the <local:NumberValidator/>
element. The Button b1
is used to divide the numbers and the result is displayed in a label
called lblResult
. The template for the label
is specified using the ContentTemplate
attribute.
The problem with error template is that it always displays a generic error message. To display specific error as a tooltip, the Validation.Error
attribute is used. The Validation.Error
attribute is used to link the textbox
es to the error
function called NumberError
. The code-behind code for the NumberError
function is as follows:
private void NumberError(object sender, ValidationErrorEventArgs e)
{
if (e.Action == ValidationErrorEventAction.Added) // Validation Error Occurred
{
((Control)sender).ToolTip = e.Error.ErrorContent.ToString();
}
else // No Error
{
((Control)sender).ToolTip = "";
}
}
The above code checks if invalid data is entered in the textbox
es and displays the error message in the form of a tooltip and resets the tooltip if the error is removed.
The code for the Validation
function is as follows:
public class NumberValidator : ValidationRule
{
public override ValidationResult Validate
(object value, System.Globalization.CultureInfo cultureInfo)
{
double number = 0;
try
{
number = Convert.ToDouble(value.ToString()); // Check for numeric value
}
catch (Exception)
{
return new ValidationResult(false, "Value must be numeric");
}
if (number == 0) // Check for non-zero value
{
return new ValidationResult(false, "Value must be non-zero");
}
return new ValidationResult(true, null);
}
}
}
The custom validation class must inherit from the ValidationRule
class and it must override the Validate
method. The Validate
method takes two parameters. The first parameter is the object to be validated. The second parameter is of the type System.Globalization.CultureInfo
. In this case, the Validate
function checks whether the value is numeric and non-zero and returns a ValidationResult
object. The first parameter of the ValidationResult
constructor is boolean and indicates that the data is valid if it is true
and invalid otherwise. The second parameter is the error
message string
in case of invalid data and null
otherwise.
Points of Interest
I hope that this article will help in understanding the basics of WPF validation in a simple way.
History
- 30th January, 2012: Initial version