Monday, August 8, 2011

Validation Rules in WPF


WPF data binding model provides ability to validate user input. You can associate Validation Rule with your Binding as well with MultiBinding.  Binding engine automatically checks whether any ValidationRule associated or not if yes then every time value passes to the source it will applies validation. Validation applies only when target value updates source value (i.e. with TwoWay or OneWayToSource binding modes).

To create validation rule you need to inherit ValidationRule class. This class is abstract class and has abstract method named Validate which returns ValidationResult type.

Below example explains how to associate validation rule to data binding.

<Window x:Class="WpfApplication1.ValidationRuleDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="Validation Rule" Height="130" Width="280">
<Window.Resources>
<local:Employee x:Key="EmployeeInformation" />
<local:AgeRangeValidationRule x:Key="ageRangeValidation" />
<local:OnlyDigitsValidationRule x:Key="onlyDigitsValidation" />
<local:NameValidationRule x:Key="nameValidation" />
       
<Style TargetType="{x:Type TextBox}">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip"
                Value="{Binding RelativeSource=
                           {x:Static RelativeSource.Self},
                Path=(Validation.Errors)[0].ErrorContent}" />
        </Trigger>
    </Style.Triggers>
</Style>
</Window.Resources>
<Grid Margin="5">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="0.5*" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition  Height="0.20*"/>
        <RowDefinition Height="0.20*" />
        <RowDefinition Height="0" />
    </Grid.RowDefinitions>
       
    <TextBlock Text="Enter Name: " Grid.Column="0"
                Grid.Row="0" Margin="3"/>
    <TextBox Name="Name" Grid.Column="1"
                Grid.Row="0" Height="30" Margin="3">
        <TextBox.Text>
            <Binding Source="{StaticResource EmployeeInformation}"
                        Path="Name">
                <Binding.ValidationRules>
                    <local:NameValidationRule />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
    <TextBlock Text="Enter Age: " Grid.Column="0"
                Grid.Row="1" Margin="3"/>
    <TextBox Name="Age" Grid.Column="1"
                Grid.Row="1" Height="30" Margin="3">
        <TextBox.Text>
            <Binding Source="{StaticResource EmployeeInformation}"
                        Path="Age">
                <Binding.ValidationRules>
                    <local:OnlyDigitsValidationRule />
                    <local:AgeRangeValidationRule />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
</Grid>
</Window>

Code Behind
public class Employee : INotifyPropertyChanged
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; OnPropertyChanged("Name"); }
    }
    private int age;
    public int Age
    {
        get { return age; }
        set { age = value; OnPropertyChanged("Age"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

Validation Rule classes
public class NameValidationRule :ValidationRule
{
    public override ValidationResult Validate(object value,
        System.Globalization.CultureInfo cultureInfo)
    {
        string name = value.ToString();
        if (name.All(c=> char.IsLetter(c) || c== ' '))
            return new ValidationResult(true, null);
        return new ValidationResult(false, "Please enter only alphabets");
    }
}
public class AgeRangeValidationRule: ValidationRule
{
    public override ValidationResult Validate(object value,
        System.Globalization.CultureInfo cultureInfo)
    {
        int age = int.Parse(value.ToString());
           
        if (age >= 18 && age <= 35)
        {
            return new ValidationResult(true, null);
        }
           
        return new ValidationResult(false,
                      "Please enter Age between 18 to 35");
    }
}

public class OnlyDigitsValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value,
        System.Globalization.CultureInfo cultureInfo)
    {
        if (!value.ToString().All(c => char.IsDigit(c)))
            return new ValidationResult(false,
                          "Please enter only digits");

        return new ValidationResult(true, null);
    }
}














In above example, Name and Age textbox are bound with Name and Age property of Employee class. Name property implements NameValidationRule and Age property implements two validation rules first one is OnlyDigitsValidationRule and second AgeRangeValidationRule.

NameValidationRule allows only alphabets and space it means you can’t enter other than alphabets inside Name textbox. While AgeRangeValidationRule allows age between 18 to 35 and OnlyDigitsValidationRule allows only digits to Age textbox.

Age property implements two validation rules so when multiple validation rules are associated with binding then they are validated in sequence means as per the association order. As per above example OnlyDigitsValidationRule validates first and followed by AgeRangeValidationRule. 

Related links -

7 comments:

  1. i want source code file of this validation urgently

    ReplyDelete
  2. Hello Lalit,

    I have uploaded all the code required for validating WPF fields on this post itself. I don't have any separate solution for the same.

    ~Mitesh

    ReplyDelete
  3. This is really very helpful for me and also who does't know about WPF. Can you please provide the solution for red border is showing while the window is loading but i need it only after the button is clicked..And no need of disabling the button using WPF MVVM.

    ReplyDelete
  4. Driver Toolkit 9.9 Crack is can assist you in putting in the drivers for your portable computer that ar the foremost applicable to instal. Driver Toolkit License Key

    ReplyDelete
  5. Private Messenger 5.96.2 (x86) (Android 5.0+) APK Download by Wickr Inc - APKMirror Free and safe Android APK downloads.Wickr Me Apk

    ReplyDelete