Form Validation of Input Controls in WPF Applications
Tags: dotnet, csharp, productivity
Published: 2019-12-04 12:53:34

---
title: Form Validation of Input Controls in WPF Applications
published: true
date: 2019-12-03 12:00:25 UTC
tags: dotnet,csharp,productivity
canonical_url: https://www.syncfusion.com/blogs/post/form-validation-of-input-controls-in-wpf.aspx
cover_image: https://www.syncfusion.com/blogs/wp-content/uploads/2019/11/Tile-min-3.jpg
---

Syncfusion WPF input controls allow you to validate user input and display hints if validation fails. If the user input is invalid, a default red border will be shown around the UIElement. This article explains how data validation works in WPF and using built-in validation options such as [IDataErrorInfo](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.idataerrorinfo?view=netframework-4.8), [INotifyErrorInfo](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifydataerrorinfo?view=netframework-4.8), and [ValidationRule](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.validationrule?view=netframework-4.8) while following the MVVM pattern.

We can validate the data in MVVM pattern using one of the following interfaces:

- IDataErrorInfo
- INotifyDataErrorInfo
- ValidationRule

## Using IDataErrorInfo

IDataErrorInfo is an interface used to validate data changes and notify the view if there is any error in the data. This error information can be bound to the UI. This interface has two members, a string indicating what is wrong in the object, and a string indicating what is wrong in the specific property of that object. The following steps explain how to implement the form data validation using IDataErrorInfo.

1. When the value of the property changes, validate it and store the error information (if any).
```csharp
public class DataErrorViewModel : NotificationObject, IDataErrorInfo
{
    public DataErrorViewModel()
    {
        Name = "John";
        Email = "john@hotmail.com";
    }
 
    private string firstName;
    public string Name
    {
        get => firstName;
        set
        {
            firstName = value;
            RaisePropertyChanged("Name");
        }
    }
 
    private string email;
    public string Email
    {
        get => email;
        set
        {
            email = value;
            RaisePropertyChanged("Email");
        }
    }
 
    #region IDataErrorInfo Members
 
    private string _error;
 
    public string Error
    {
        get => _error;
        set
        {
            if (_error != value)
            {
                _error = value;
                RaisePropertyChanged("Error");
            }
        }
    }
 
    public string this[string columnName]
    {
        get
        {
            return OnValidate(columnName);
        }
    }
 
    private string OnValidate(string columnName)
    {
        string result = string.Empty;
        if (columnName == "Name")
        {
            if (string.IsNullOrEmpty(Name))
            {
                result = "Name is mandatory";
            }
            else if (!Regex.IsMatch(Name, @"^[a-zA-Z]+$"))
            {
                result = "Should enter alphabets only!!!";
            }
        }
 
        if (columnName == "Email")
        {
            if (string.IsNullOrEmpty(Email))
            {
                result = "Email Required";
            }
            else if (!Regex.IsMatch(Email, "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9-]+\.[a-zA-Z]{1,4}"))
            {
                result = "Invalid Email ID";
            }
        }
        if (result == null)
        {
            Error = null;
        }
        else
        {
            Error = "Error";
        }
        return result;
    }
 
    #endregion
}
```
<ol start="2"><li> Bind editor to the required property and set **ValidatesOnDataErrors** to true.</li></ol>
```xml
<UserControl x:Class="Validation_sample.DataErrorView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Validation_sample"
             xmlns:syncfusion="http://schemas.syncfusion.com/wpf">
    <UserControl.DataContext>
        <local:DataErrorViewModel/>        
    </UserControl.DataContext>
    <StackPanel>
        <TextBox Text="{Binding Name, 
                       UpdateSourceTrigger=PropertyChanged,
                       ValidatesOnDataErrors=True}" />
 
        <syncfusion:SfMaskedEdit
                 MaskType="RegEx"
                 Mask="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9-]+\.[a-zA-Z]{1,4}"
                 Value="{Binding Email, 
                         Mode=TwoWay, NotifyOnValidationError=True,
                         UpdateSourceTrigger=PropertyChanged,
                         ValidatesOnDataErrors=True}"/>
 
    </StackPanel>
</UserControl>
```
<ol start="3"><li> Allow submission of your form only after all errors have been cleared by disabling the button.</li></ol>
```xml
<Button Content="Submit"
        Grid.Column="2" Grid.Row="5"
        HorizontalContentAlignment="Center" Width="100" Height="25"
        Margin="15">
    <Button.Style>
        <Style TargetType="Button">
            <Setter Property="IsEnabled" Value="False"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Error}" Value="{x:Null}">
                    <Setter Property="IsEnabled" Value="True"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>
```
![Validating user input using IDataErrorInfo.](https://www.syncfusion.com/blogs/wp-content/uploads/2019/11/Validating-user-input-using-IDataErrorInfo.png)<figcaption>Validating user input using IDataErrorInfo</figcaption>

## Using INotifyDataErrorInfo

INotifyDataError is also used to validate the data changes and notify if there is any error in the data. This error information can be bound to UI. This interface notifies the view by raising the ‘ErrorChanged’ event. This interface can also show multiple error information for a single property. The following steps explain how to implement the form data validation using INotifyDataErrorInfo.

1. When the value of the property changes, validate it and store the error information (if any).
```csharp
public class NotifyDataErrorViewModel : NotificationObject, INotifyDataErrorInfo
{
    private Dictionary<string, List<string>> propErrors = new Dictionary<string, List<string>>();
 
    private int? age = 26;
    public int? Age
    {
        get
        {
            return age;
        }
        set
        {
            age = value;
            OnPropertyChanged("Age");
        }
    }
 
    #region INotifyPropertyChanged
 
    public void OnPropertyChanged(string name)
    {
        RaisePropertyChanged(name);
        if (name == "Age")
        {
            ValidateAge();
        }
    }
 
    #endregion
 
    private void ValidateAge()
    {
        ClearErrors(nameof(Age));
        if ((this.Age < 1 || this.Age > 100) || this.Age == null)
        {
            AddError(nameof(Age), "Age should greater than 1 and less than 100");
        }
    }
 
    #region INotifyDataErrorInfo
 
    private void AddError(string propertyName, string error)
    {
        if (!propErrors.ContainsKey(propertyName))
            propErrors[propertyName] = new List<string>();
 
        if (!propErrors[propertyName].Contains(error))
        {
            propErrors[propertyName].Add(error);
            OnErrorsChanged(propertyName);
        }
    }
 
    private void ClearErrors(string propertyName)
    {
        if (propErrors.ContainsKey(propertyName))
        {
            propErrors.Remove(propertyName);
            OnErrorsChanged(propertyName);
        }
    }
 
 
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
 
    private void OnErrorsChanged(string propertyName)
    {
        if (ErrorsChanged != null)
            ErrorsChanged.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
        RaisePropertyChanged("HasErrors");
    }
 
    public System.Collections.IEnumerable GetErrors(string propertyName)
    {
        List<string> errors = new List<string>();
        if (propertyName != null)
        {
            propErrors.TryGetValue(propertyName, out errors);
            return errors;
        }
        Else
        {
            return null;
        }
    }
 
    public bool HasErrors
    {
        get
        {
            try
            {
                var propErrorsCount = propErrors.Values.FirstOrDefault(r => r.Count > 0);
                if (propErrorsCount != null)
                    return true;
                else
                    return false;
            }
            catch { }
            return true;
        }
    }
 
 
    # endregion
 
}
```
<ol start="2"><li>Bind the editor to the required property and set **ValidatesOnNotifyDataErrors** to true. Set the DataContext of this text box to NotifyDataErrorViewModel.</li></ol>
```xml
<UserControl x:Class="Validation_sample.NotifyDataErrorView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:syncfusion="http://schemas.syncfusion.com/wpf">
    <UserControl.DataContext>
        <local:NotifyDataErrorViewModel/>
    </UserControl.DataContext>
    <Grid Name="Grid">
        <syncfusion:IntegerTextBox
                 Height="Auto" Width="200"
                 Value="{Binding Age, Mode=TwoWay,
                                ValidatesOnNotifyDataErrors=True,
                                UpdateSourceTrigger=PropertyChanged,
                                TargetNullValue=''}" />
    </Grid>
</UserControl>
```
<ol start="3"><li> Allow the submission of your form only after all the errors have been cleared by disabling the button.</li></ol>
```xml
<Button Content="Submit"
        Grid.Column="2" Grid.Row="5"
        HorizontalContentAlignment="Center" Width="100" Height="25"
        Margin="15">
    <Button.Style>
        <Style TargetType="Button">
            <Setter Property="IsEnabled" Value="False"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding HasErrors}" Value="False">
                    <Setter Property="IsEnabled" Value="True"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>
```
![Validating user input using INotifyDataErrorInfo.](https://www.syncfusion.com/blogs/wp-content/uploads/2019/11/Validating-user-input-using-INotifyDataErrorInfo.png)<figcaption>Validating user input using INotifyDataErrorInfo</figcaption>

## Using ValidationRule

As well as the interface approaches, which are defined in the ViewModel, you can also define a validation rule and reuse it by specifying the rule in the binding of the required properties. The following steps explain how to implement the form data validation using ValidationRule.

1. Validate the data by deriving a class from the [ValidationRule](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.validationrule?view=netframework-4.8) class and implementing its **Validate** method. In this method, you will get the current value and culture information as method arguments. Once data is validated in this method, it returns any error information as ValidationResult, which contains the result and error text.
```csharp
/// <summary>
/// Rule for age
/// </summary>
public class AgeValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        ValidationResult result = new ValidationResult(true, null);
        int age;
        if (string.IsNullOrEmpty(value.ToString()))
        {
            result = new ValidationResult(false, "Age is mandatory");
        }
        else if (int.TryParse(value.ToString(), out age))
        {
            if (age < 1 || age > 100)
            {
                result = new ValidationResult(false, "Age should greater than 1 and less than 100");
            }
        }
        else
        {
            result = new ValidationResult(false, "Invalid input");
        }
        return result;
    }
}
```
<ol start="2"><li>Then, add the required **ValidationRule** to binding.</li></ol>
```xml
<syncfusion:IntegerTextBox x:Name="age"
                            Height="Auto" Width="200"
                            Margin="5" Grid.Column="2" Grid.Row="2" >
    <syncfusion:IntegerTextBox.Value>
        <Binding Path="Age" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:AgeValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </syncfusion:IntegerTextBox.Value>
</syncfusion:IntegerTextBox>
```
![Clearing error.](https://www.syncfusion.com/blogs/wp-content/uploads/2019/11/Age.png)

<ol start="3"><li>Allow the submission of your form only after all the errors have been cleared by disabling the button.</li></ol>
```xml
<Button Content="Submit">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=name}" Value="False"/>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=age}" Value="False"/>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=dob}" Value="False"/>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=email}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
```
![Validating user input using ValidationRule.](https://www.syncfusion.com/blogs/wp-content/uploads/2019/11/Validating-user-input-using-ValidationRule.png)<figcaption>Validating user input using ValidationRule</figcaption>

## Showing error details in a tooltip

To show error information as a tooltip of the editor, bind the tooltip to ‘Validation.Errors’ as demonstrated in the following code.

```xml
<UserControl.Resources>
    <Style x:Key="errorToolTip" TargetType="Control">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Setter Property="ToolTip"
                        Value="{
                            Binding RelativeSource={x:Static RelativeSource.Self}, 
                            Path=(Validation.Errors)/ErrorContent}"/>
            </Trigger>
        </Style.Triggers>
    </Style>
    <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource errorToolTip}"/>
    <Style TargetType="{x:Type syncfusion:IntegerTextBox}" BasedOn="{StaticResource errorToolTip}"/>
    <Style TargetType="{x:Type syncfusion:SfMaskedEdit}" BasedOn="{StaticResource errorToolTip}"/>
</UserControl.Resources>
```
![Showing error details in a tooltip.](https://www.syncfusion.com/blogs/wp-content/uploads/2019/11/Showing-error-details-in-a-tooltip.png)<figcaption>Showing error details in a tooltip</figcaption>

## Customizing error template to show errors

By default, you can see a red border that appears if there is any error in the input. You can customize the UI to provide visual feedback to inform the user when an invalid value is entered. We can set the desired error template to show the incorrect date by using the [Validation.ErrorTemplate](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.validation.errortemplate?view=netframework-4.8) property of UIElement. The following code example demonstrates this.

```xml
<Style x:Key="errorTemplate" TargetType="{x:Type Control}">
    <Setter Property="Validation.ErrorTemplate">
        <Setter.Value>
            <ControlTemplate>
                <DockPanel>
                    <Border>
                        <AdornedElementPlaceholder x:Name="controlWithError"/>
                    </Border>
                    <Path HorizontalAlignment="Right"
                            VerticalAlignment="Top"
                            Width="10" Height="10"
                            Data="M0,0 L 1,0 1,1z"
                            Margin="-10,0,0,0"
                            Stretch="Fill"
                            Fill="Red"/>
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource errorTemplate}"/>
<Style TargetType="{x:Type syncfusion:IntegerTextBox}" BasedOn="{StaticResource errorTemplate}"/>
<Style TargetType="{x:Type syncfusion:SfMaskedEdit}" BasedOn="{StaticResource errorTemplate}"/>
```

![Customizing error template to show errors.](https://www.syncfusion.com/blogs/wp-content/uploads/2019/11/Customizing-error-template-to-show-errors.png)<figcaption>Customizing error template to show errors</figcaption>

You can try this sample from [GitHub](https://github.com/SyncfusionExamples/form-validation-of-input-control-in-wpf-application)

## Conclusion

Syncfusion provides [90+ custom WPF controls](https://www.syncfusion.com/wpf-ui-controls) such as [DataGrid](https://www.syncfusion.com/wpf-ui-controls/datagrid), [Charts](https://www.syncfusion.com/wpf-ui-controls/charts), [Diagram](https://www.syncfusion.com/wpf-ui-controls/diagram), and [PDF Viewer](https://www.syncfusion.com/wpf-ui-controls/pdf-viewer) for building powerful line-of-business Windows applications to ease the work of developers.

Several controls such as [Integer TextBox](https://help.syncfusion.com/wpf/integer-textbox/getting-started), [Double TextBox](https://help.syncfusion.com/wpf/double-textbox/getting-started), [DateTimePicker](https://help.syncfusion.com/wpf/datetimepicker/getting-started), and [MaskedTextBox](https://help.syncfusion.com/wpf/maskedtextbox/getting-started) support error validation. Apart from these input controls, our [DataGrid](https://help.syncfusion.com/wpf/datagrid/getting-started) and [TreeGrid](https://help.syncfusion.com/wpf/treegrid/getting-started) controls also follow the same standards to validate user input. For more details, refer to the [WPF DataGrid Validation](https://help.syncfusion.com/wpf/datagrid/data-validation#built-in-validation-using-idataerrorinfo--inotifydataerrorinfo) and [WPF TreeGrid Validation](https://help.syncfusion.com/wpf/treegrid/data-validation) documentations.

If you have any questions, please let us know in the comments section below. You can also contact us through our [support forum](https://www.syncfusion.com/forums), [Direct-Trac](https://www.syncfusion.com/account/login), or [feedback portal](https://www.syncfusion.com/feedback/wpf). We are waiting to hear your feedback!

The post [Form Validation of Input Controls in WPF Applications](https://www.syncfusion.com/blogs/post/form-validation-of-input-controls-in-wpf.aspx) appeared first on [Syncfusion Blogs](https://www.syncfusion.com/blogs).