65.9K
CodeProject is changing. Read more.
Home

WPF Validation

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.26/5 (9 votes)

Jan 30, 2012

CPOL

3 min read

viewsIcon

82002

downloadIcon

2779

This article describes the Validation process in WPF

Validation2.jpg

Validation3.jpg

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 TextBoxes t1 and t2 are bound to the properties FirstNumber and SecondNumber respectively. The error templates for the two textboxes 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 textboxes 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 textboxes 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