Home > Uncategorized > Combining WPF Validation Rules and IDataErrorInfo to Resolve Conversion Errors

Combining WPF Validation Rules and IDataErrorInfo to Resolve Conversion Errors

January 8th, 2009

This article discusses a few approaches to overcome binding conversion errors in WPF by combining model validation (through IDataErrorInfo) and WPF validation rules. Practically, I’m going to outline three approaches to the same solution:

  • Inline declaration
  • Using attached properties
  • Using custom binding classes

 

image

The Problem

WPF validation through IDataErrorInfo is a great feature if you already have validation logic in you model. However: There is a problem if the user enters a value that cannot be written to model due to value conversion errors. Let’s start with a simple sample:

  • A TextBox is bound to a numeric Age property of your model.
  • As soon as the user enters a value in the Textbox, the property on the model is updated. The model then validates whether the entered value is valid (range from 1 to 130 years).
  • However: If the user enters a string rather than a number (e.g. “30a”), the value conversion to an integer fails. In this case, WPF does not show an error at all:

image

 

Karl Shifflet recently updated his article on this very subject, where he outlines an MVVM-based approach to the problem (highly recommended reading material!).

In my case, however, I was looking for a simpler solution. I had validation and views already in place and just wanted a visual representation of invalid input that cannot be bound to the model.

 

WPF Validation Rules to the Rescue

And this is where the good old WPF Validation Rules come back into play:

  1. A binding with ValidatesOnDataErrors=True ensures that the model validation logic is being invoked.
  2. Additional WPF Validation Rules take care of invalid input that can not be bound to the model.

 

<TextBox x:Name="txtAge">
  
  <TextBox.Text>
    <Binding Path="Age" ValidatesOnDataErrors="True">
      <Binding.ValidationRules>
        <rules:NumericRule />
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>

</TextBox>

 

That’s it already! An invalid numeric value (below minimum, above maximum) is handled by the model, everything else is caught be the NumericRule (see attached sample for the sources).

image

 

Simplify Markup 1: Attached Properties

The above sample has one catch – it forces me to write rather verbose XAML. This is where attached properties come to the rescue. Here’s the same thing using an attached property:

 

<TextBox x:Name="txtAge"
  Text="{Binding Path=Age, ValidatesOnDataErrors=True}"
  rules:Editors.TextRule="{StaticResource numericRule}"  
/>

 

In the sample above, I declared an attached property of type ValidationRule that points to by custom rule. However, depending on your case, you can make your attached property as simple/complex as you need. A great article on this subject was published by WPF master Josh Smith on CodeProject, where he outlines this exact pattern.

 

Simplify Markup 2: Custom Binding Classes

As an alternative to attached properties – especially in case you want to define multiple parameters – a custom binding expression might be a simpler approach. If you use a simple Decorator helper class, creating your custom binding class is a breeze:

 

<TextBox x:Name="txtCustomBinding"
  Text="{local:RuleBinding Path=Age, MinValueOverride=20}"
/>

 

Here’s my custom binding class, derived from BindingDecoratorBase:

using System;
using System.Windows.Controls;
using System.Windows.Data;
using Hardcodet.Wpf.ValidationRules;

namespace Hardcodet.Wpf.CustomBinding
{
  /// <summary>
  /// A binding extension that checks for a given
  /// numeric value.
  /// </summary>
  public class RuleBinding : BindingDecoratorBase
  {
    /// <summary>
    /// An optional override for the minimum value,
    /// that can be used to narrow the allowed range.
    /// </summary>
    public int? MinValueOverride { get; set; }


    /// <summary>
    /// Creates a new instance of the binding with default values.
    /// </summary>
    public RuleBinding()
    {
      //set default binding directives
      ValidatesOnDataErrors = true;
      UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    }


    /// <summary>
    /// This method is being invoked during initialization.
    /// </summary>
    /// <param name="provider">Provides access to the bound items.</param>
    /// <returns>The binding expression that is created by
    /// the base class.</returns>
    public override object ProvideValue(IServiceProvider provider)
    {
      //create the validation rule
      ValidationRule rule;
      if (MinValueOverride.HasValue)
      {
        //create a rule that also narrows the minimum value
        rule = new MinNumericRule() {MinValue = MinValueOverride.Value};
      }
      else
      {
        //just make sure the value is numeric
        rule = new NumericRule();
      }

      Binding.ValidationRules.Add(rule);

      //delegate binding creation etc. to the base class
      object val = base.ProvideValue(provider);
      return val;
    }
  }
}

 

The attached sample shows you all the techniques I described above.

Download sample project: validationrules.zip

kick it on DotNetKicks.com


Author: Categories: Uncategorized Tags: ,
  1. February 5th, 2009 at 14:58 | #1

    Thanks for this sample!

  2. shane
    March 19th, 2009 at 20:22 | #2

    Thanks for the sample. I’d also like to be able to bind the MaxValueOverridevalue but BindingDecorator base is not derived from DependencyObject so I have not SetValue/GetValue to implement MaxValueOverrideas a DependencyProperty. Do you have any suggestions for this? I’d Like to do this:

    Text=”{binding:IntMinMaxRuleBinding Path=CurrentPage, MaxValueOverride={Binding Path=TotalPageCount}, MinValueOverride=1}”

  3. Raj
    June 10th, 2009 at 15:43 | #3

    Wow..! its helpful

  4. ADH
    October 2nd, 2009 at 14:19 | #4

    Very helpful, but if using custom binding class in XAML, how would I specify a StringFormat or Converter to format the text? Because “Text={Binding” is not used?

  5. October 2nd, 2009 at 14:26 | #5

    ADH,

    The BindingDecoratorBase base class provides all the goodies of a regular binding. So you do indeed have all these properties.

  6. El Guapo
    October 18th, 2009 at 05:14 | #6

    Excellent post. Custom Binding classes are a very nice tool and this is a great application of them.

  7. September 3rd, 2010 at 15:37 | #7

    nice sample,

    could you declare a license (preferably MIT/X11) so that I can copy/paste snipets for my own use?

    Thanks.

  8. Gishu
    September 24th, 2010 at 06:39 | #8

    Nice intro. I keep coming back to you and then delve into Karl S and Josh Smith’s articles… Thanks for spending the time and jotting this down.

  9. October 30th, 2010 at 09:34 | #9

    @Jay R. Wren
    This is just a snippet – use it as you please :)

  10. October 30th, 2010 at 09:35 | #10

    @Gishu
    Thanks for your kind feedback – it’s highly appreciated!

  11. Sys
    February 7th, 2011 at 03:42 | #11

    Hi

    Your example app works fine but when i use it on my user control the validation rule doesn’t trigger. In my user control there’s only a template and textbox.

    Here’s the xaml:

  12. Sys
    February 16th, 2011 at 08:39 | #12

    Btw i found out i have to explicitely set the mode=twoway when binding against user control.

  13. Juan Francisco
    June 5th, 2011 at 12:01 | #13

    Hello, is it posible to apply this technique to a combobox?

    Thanks a lot.

  14. enlightened
    March 12th, 2013 at 09:52 | #14

    Great article – very informative and has certainly clarified all of my confusion regarding implementation of custom validation.

    Best Regards.

  1. May 26th, 2009 at 20:08 | #1