WPF Validation with Attributes and IDataErrorInfo interface in MVVM

WPF provides validation infrastructure for binding scenarios through IDataErrorInfo interface. Basically you have to implement the Item[columnName] property putting the validation logic for each property in your Model (or ModelView) requiring validation. From XAML you need to set ValidatesOnDataErrors to true and decide when you want the binding invoke the validation logic (through UpdateSourceTrigger).

The idea of this post is try to generalize the validation logic in IDataErrorInfo.Item[] using the validation attributes in System.ComponentModel.DataAnnotations assembly.

First, we decorate each property needing validation with one or more validation attributes (An explanation of each validation attribute is out of the scope of this post) depending on the validation rules. For example if we have a property named Range we can add RangeAttribute to validate that the property value is between the boundaries:

[Required(ErrorMessage = "Field 'Range' is required.")]

[Range(1, 10, ErrorMessage = "Field 'Range' is out of range.")]

public int Range

{

    get

    {

        return this.range;

    }

    set

    {

        if (this.range != value)

        {

            this.range = value;

            this.OnPropertyChanged("Range");

        }

    }

}

Now, we need a few code to get the validation attributes and the value getters for each property requiring validation, just a couple of simple LINQ queries:

private static readonly Dictionary<string, Func<ValidationModelView, object>>

    propertyGetters = typeof(ValidationModelView).GetProperties()

                      .Where(p => GetValidations(p).Length != 0)

                      .ToDictionary(p => p.Name, p => GetValueGetter(p));

 

private static readonly Dictionary<string, ValidationAttribute[]> validators =

    typeof(ValidationModelView).GetProperties()

    .Where(p => GetValidations(p).Length != 0)

    .ToDictionary(p => p.Name, p => GetValidations(p));

 

private static ValidationAttribute[] GetValidations(PropertyInfo property)

{

    return (ValidationAttribute[])property

        .GetCustomAttributes(typeof(ValidationAttribute), true);

}

 

private static Func<ValidationModelView, object> GetValueGetter(PropertyInfo property)

{

    var instance = Expression.Parameter(typeof(ValidationModelView), "i");

    var cast = Expression.TypeAs(

        Expression.Property(instance, property),

        typeof(object));

    return (Func<ValidationModelView, object>)Expression

        .Lambda(cast, instance).Compile();

}

It is important emphasize that in order to improve the performance in the validation we use static dictionaries and Lamda expressions to generate the value getters. The validation attributes are cached in other dictionary in order to improve the performance too.

Finally we need implement the Item[columnName] property which is the part of code that really do the validation. It is very simple, WPF send the name of the property in the columnName argument, then all you have to do is get the value of the property using the propertyGetters dictionary and test this value against the validation attributes in the validators dictionary.

public string this[string columnName]

{

    get

    {

        if (propertyGetters.ContainsKey(columnName))

        {

            var value = propertyGetters[columnName](this);

            var errors = validators[columnName].Where(v => !v.IsValid(value))

                .Select(v => v.ErrorMessage).ToArray();

            return string.Join(Environment.NewLine, errors);

        }

 

        return string.Empty;

    }

}

All of this returns the list of message errors that will be shown in the UI.

You can do download a complete sample here.

Published Friday, April 17, 2009 11:49 AM by marianor
Filed under:

Comments

# WPF Validation with Attributes and IDataErrorInfo interface in MVVM - Unknown Recipes

Pingback from  WPF Validation with Attributes and IDataErrorInfo interface in MVVM - Unknown Recipes

# WPF Validation with Attributes and IDataErrorInfo interface in MVVM - Mariano Omar Rodriguez

Friday, April 17, 2009 6:33 PM by DotNetShoutout

Thank you for submitting this cool story - Trackback from DotNetShoutout

# re: WPF Validation with Attributes and IDataErrorInfo interface in MVVM

Monday, June 29, 2009 6:18 AM by Adam

How can you bind the Validation.HasError to your ViewModel so you can determine if it is valid inside the ViewModel?

# re: WPF Validation with Attributes and IDataErrorInfo interface in MVVM

Wednesday, July 01, 2009 8:05 PM by marianor

I don't think you can do that, but I believe that is not necessary. If you need the login error you can get it by the Error property.

The conversion error basically never go to the ViewModel, but there is no problem there becouse the button is disabled.

# re: WPF Validation with Attributes and IDataErrorInfo interface in MVVM

Tuesday, September 15, 2009 2:52 PM by Chad McCallum

Great article!  I've actually modified your code a bit to be in a separate class and use a Generic so it's easily usable by any model class with properties & data annotations (more or less just replacing ValidationModelView with T) and it's working great inside my project!  I wouldn't have been able to do it without your source though, so much appreciated.

# re: WPF Validation with Attributes and IDataErrorInfo interface in MVVM

Tuesday, November 10, 2009 4:20 AM by Michael Sync

That's good one.

# re: WPF Validation with Attributes and IDataErrorInfo interface in MVVM

Saturday, January 09, 2010 6:06 AM by Ian Mac

Hi Chad, can you give an idea of how you did that? Struggling with this a bit!

# re: WPF Validation with Attributes and IDataErrorInfo interface in MVVM

Tuesday, June 29, 2010 11:33 PM by Steve

That's some hot code ! !

Would love to see something equally cool for whole-object validation.

# Attributes-based Validation in a WPF MVVM Application&nbsp;|&nbsp;Technology Articles

Pingback from  Attributes-based Validation in a WPF MVVM Application&nbsp;|&nbsp;Technology Articles

# re: WPF Validation with Attributes and IDataErrorInfo interface in MVVM

Tuesday, August 03, 2010 6:20 AM by Gishu

Thanks... this was a missing piece. I was struggling for some guidance on how to drive validations and resultant errors from the ViewModel

Leave a Comment

(required) 
(required) 
(optional)
(required)