Enabling Validation in Silverlight 4 with IDataErrorInfo | John Papa

John Papa

Evangelist on the loose

Enabling Validation in Silverlight 4 with IDataErrorInfo

...

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);
            }
        }
    }
}
tags: Silverlight
  • http://www.wintellect.com/CS/blogs/jlikness/archive/2009/11/20/rich-data-forms-in-silverlight-4-beta.aspx Anonymous

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

  • Paras Sharma

    Hi, I want to implement a Text Box which could be made required. But the problem is that if their is no Text entered in the text box it doesn’t go to the view model to set the associated property hence i cant throw an exception so as to show that it is required.

  • Suketu

    Hi John,
    Thanks for the useful article. I was just wondering if this ValidationHandler class can be used with MVVM & RIA services where I don’t create Entity classes by hand.
    Thanks

  • Patrick

    The validationHandler is private to your class. How do you set the validationHandler?

%d bloggers like this: