Enabling Validation in Silverlight 4 with IDataErrorInfo

Wednesday, November 18 2009 - ,

One of the new features of Silverlight 4 Beta is the addition of the IDataErrorInfo interface. In Silverlight 3 we throw exceptions when a property value is invalid. The IDataErrorInfo interface has been around in .NET but is new to Silverlight 4 beta. It allows you to invalidate property values without throwing exceptions.

Implementing this interface is pretty straightforward, though there are several ways to do it. To help you get jumpstarted with this new feature, I included some sample code I wrote that you can use to implement the IDataErrorInfo interface to perform data validation. The controls in Silverlight 4 beta, such as the DataForm, observe the IDataErrorInfo interface so they know how to handle the validation issues. This means that when a validation rule is violated in the IDataErrorInfo implementation for an entity, the controls will display the appropriate invalid state to the user.

The sample code below uses a ValidationHandler class I created which deals with the IDataErrorInfo details. I created this class to help consolidate this logic which will be used in several entities in a project. You can call the ValidateRule method and pass to it the property name, the error message, and a delegate for the rule to check. This can easily be extended to create a canned set of rules.

Here is the class sample showing an entity with some properties and rules. The sample also shows the ValidationHandler utility class. Enjoy!

NOTE: This code is just a starter to get you going that I wrote.


using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.Generic;
namespace EmployeeManager
{
    public class Employee : INotifyPropertyChanged, IDataErrorInfo
    {
        private ValidationHandler validationHandler = new ValidationHandler();
        private string _FirstName;
        public string FirstName
        {
            get { return _FirstName; }
            set 
            { 
                _FirstName = value; 
                NotifyPropertyChanged("FirstName"); 
                bool valid = validationHandler.ValidateRule( "FirstName", "First Name must be at least 5 letters!", () => (value.Length >= 5));
            }
        }
        private float _TaxPercent;
        public float TaxPercent
        {
            get { return _TaxPercent; }
            set
            {
                if (_TaxPercent != value)
                {
                    if (value >= 1)
                        value /= 100;
                    _TaxPercent = value;
                    NotifyPropertyChanged("TaxPercent");
                    bool valid = validationHandler.ValidateRule( "TaxPercent", "The tax has to be positive!", () => (value > 0));
                }
            }
        }
        protected void NotifyPropertyChanged(string PropertyName)
        {
            if (null != PropertyChanged)
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
        public string Error
        {
            get { return null; }
        }
        public string this[string columnName]
        {
            get
            {
                if (this.validationHandler.BrokenRuleExists(columnName))
                {
                    return this.validationHandler[columnName];
                }
                return null;
            }
        }
    }
    public class ValidationHandler
    {
        private Dictionary<string, string> BrokenRules { get; set; }
        public ValidationHandler()
        {
            BrokenRules = new Dictionary<string, string>();
        }
        public string this[string property]
        {
            get
            {
                return this.BrokenRules[property];
            }
        }
        public bool BrokenRuleExists(string property)
        {
            return BrokenRules.ContainsKey(property);
        }
        public bool ValidateRule(string property, string message, Func<bool> ruleCheck)
        {
            if (!ruleCheck())
            {
                this.BrokenRules.Add(property, message);
                return false;
            }
            else
            {
                RemoveBrokenRule(property);
                return true;
            }
        }
        public void RemoveBrokenRule(string property)
        {
            if (this.BrokenRules.ContainsKey(property))
            {
                this.BrokenRules.Remove(property);
            }
        }
    }
}

1 comment(s)

Silverlight 4 provides some very powerful data form capabilities out of the box. You will no longer have