Thursday, March 13, 2014

WPF - Multiple Validation on Single Control

Introduction
Implementing multiple validation rules on a single control is bit difficult but not impossible. Every form has one or more controls which required to be validation on different set of logic. Since this is a very basic dependency of code that every developer has to do, this tip is dedicated only to this.

It would be an easy task if we have set of multiple validation like required, numeric, minimum character length, folder exists, numeric range rule and we just apply one or more than one rule just by putting comma or | between the rules in our XAML file. To elaborate more, the issue lets see a situation.

Assume one textbox control value needs to be validated with the below conditions:

It has to be a required field.
It has to be a numeric field.
It should be between ranges of 1 to 100.

Or:
It has to be a required Field
Input value should have minimum 3 characters.

Or:

It has to be a required field.
Input value should be a valid directory.

Now one way is to create a class and club all rules into one and then use that one rule, but isn't it is a time consuming job and difficult to manage at the later stage of project? Imagine how many combination of rules we will have to make and if there is any logic change, we need to go back and manage each rule with the new changes.

Background
Continue to my validation segment, previously I wrote a tip where I highlighted how to implement maximum length validation on controls, now I moved to other validation but with addition of how to implement multiple validation on the same control.

<TextBox Text="{binding:RuleBinding Path=Book.Pages, 
        ValidationList=RequiredRule|NumericRule|RangeRule,  MinValueRange=0, MaxValueRange=999,        UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True , Mode=TwoWay}"
        Grid.Column="1" Grid.Row="6" HorizontalAlignment="Stretch"/> 

First, we will introduce our two generic classes which would allow us to bind these multiple rules and then these rules would be set at run time.

   [MarkupExtensionReturnType(typeof(object))]
  public abstract class BindingDecoratorBase : MarkupExtension
  {
    /// <summary>
    /// The decorated binding class.
    /// 
    private Binding binding = new Binding();
 
  public override object ProvideValue(IServiceProvider provider)
    {
      //create a binding and associate it with the target
      return binding.ProvideValue(provider);
    }
 
protected virtual bool TryGetTargetItems(IServiceProvider provider, out DependencyObject target, out DependencyProperty dp)
    {
    }
}

Read more: Codeproject