Using IDataErrorInfo for Validation

I read an article on CodeProject titled Total View Validation where the author complains that IDataErrorInfo is inadequate for WPF validation.  The assumption he makes is that all the validation code needs to go into the IDataErrorInfo.this[string] property as such:

publicstringthis[string name]
{
   get
    {
        string result = null;
        if (name == "Age")
        {
            if (this.age < 0 || this.age > 150)
            {
                result = "Age must not be less than 0 or greater than 150.";
            }
        }
        return result;
    }
}


This should not be the way that IDataErrorInfo is used as it puts business logic in the model, as the author points out.  His solution though was to create another mechanism to notifiy the user of validation errors and to not use IDataErrorInfo at all.

A solution I would propose though would be to follow how DataTables and DataTables use IDataErrorInfo by implementing methods to set and clear the objects error information:

public SomeClass() : IDataErrorInfo
    {
 
        publicstring Name { get; set; }
 
        publicstring Age { get; set; }
 
        #region Data Error Info
 
        private Dictionary<string, string> _propertyErrors;
 
        privatevoid InitDataErrorInfo()
        {
            var properties = this.GetType().GetProperties();
 
            _propertyErrors = new Dictionary<string, string>();
 
            // This will act as an overall error message for the entire object.
            _propertyErrors.Add(this.GetHashCode().ToString(), string.Empty);
 
            foreach (var propertyInfo in properties)
            {
                _propertyErrors.Add(propertyInfo.Name, string.Empty);
            }
        }
 
        publicvoid ClearDataErrorInfo()
        {
            foreach (var property in _propertyErrors.Keys)
            {
                _propertyErrors[property] = string.Empty;
            }
        }
 
        publicvoid ClearDataErrorInfo(string propertyName)
        {
            AssertThisHasPropertyWithName(propertyName);
            _propertyErrors[propertyName] = string.Empty;
        }
 
        publicvoid SetError(string error)
        {
            SetError(this.GetHashCode().ToString(), error);
        }
 
        publicvoid SetError(string propertyName, string error)
        {
            AssertThisHasPropertyWithName(propertyName);
            _propertyErrors[propertyName] = string.Format("{0}{1}{2}", _propertyErrors[propertyName]
                , Environment.NewLine,  error);
        }
 
        publicstringthis[string propertyName]
        {
            get
            {
                AssertThisHasPropertyWithName(propertyName);
                return _propertyErrors[propertyName];
            }
        }
 
        publicstring Error
        {
            get
            {
                var errors = new StringBuilder();
                foreach (var propertyError in _propertyErrors)
                {
                    if (string.IsNullOrEmpty(propertyError.Value)) continue;
 
                    errors.AppendLine(propertyError.Value);
                }
 
                return errors.ToString().Trim();
            }
        }
 
        protectedvoid AssertThisHasPropertyWithName(string propertyName)
        {
            if (!_propertyErrors.ContainsKey(propertyName))
            {
                thrownewArgumentException(string.Format("No property named {0} on {1}."
                    , propertyName, this.GetType().FullName));
            }
        }
 
        #endregion
    }



Note that there is no validation here, only reporting if the object has errors.  Using this takes advantage of the already existing validation notification built into WPF as well as WinForms.

  1. No comments yet.

You must be logged in to post a comment.

  1. No trackbacks yet.