Search code examples
wpfdata-annotationsidataerrorinfo

Combining DataAnnotations and IDataErrorInfo for WPF


I am writing a WPF application and I want to use Data Annotations to specify things like Required Fields, Range, etc.

My ViewModel classes use the regular INotifyPropertyChanged interface and I can validate the entire object easily enough using the C# 4 Validator, but I would also like the fields to highlight red if they do not validate properly. I found this blog post here (http://blogs.microsoft.co.il/blogs/tomershamam/archive/2010/10/28/wpf-data-validation-using-net-data-annotations-part-ii.aspx) that talks about how to write your base view model to implement IDataErrorInfo and simply use the Validator, but the implementation doesn't actually compile nor can I see how it would work. The method in question is this:

    /// <summary>
    /// Validates current instance properties using Data Annotations.
    /// </summary>
    /// <param name="propertyName">This instance property to validate.</param>
    /// <returns>Relevant error string on validation failure or <see cref="System.String.Empty"/> on validation success.</returns>
    protected virtual string OnValidate(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            throw new ArgumentException("Invalid property name", propertyName);
        }

        string error = string.Empty;
        var value = GetValue(propertyName);
        var results = new List<ValidationResult>(1);
        var result = Validator.TryValidateProperty(
            value,
            new ValidationContext(this, null, null)
            {
                MemberName = propertyName
            },
            results);

        if (!result)
        {
            var validationResult = results.First();
            error = validationResult.ErrorMessage;
        }

        return error;
    }

The problem is GetValue is not provided. He could be talking about the GetValue that comes when you inherit DependencyObject, but the syntax still doesn't work (it expects you to pass DependencyProperty as a parameter) but I'm using regular CLR properties with OnPropertyChanged("MyProperty") being invoked on the setter.

Is there a good way to connect the validation to the IDataErrorInfo interface?


Solution

  • Using your above code as a starting point I got this working through IDataErrorInfo.

    Your problem centred around getting the value of the property when you only have the property name, reflection can help here.

    public string this[string property]
    {
       get
       {
          PropertyInfo propertyInfo = this.GetType().GetProperty(property);
          var results = new List<ValidationResult>();
    
          var result = Validator.TryValidateProperty(
                                    propertyInfo.GetValue(this, null),
                                    new ValidationContext(this, null, null)
                                    {
                                      MemberName = property
                                    }, 
                                    results);
    
          if (!result)
          {
            var validationResult = results.First();
            return validationResult.ErrorMessage;
          }
    
          return string.Empty;
       }
    }