Data Validation in Silverlight DataGrid


One of the features added to datagrid in Silverlight 3 Beta is Validation.  This can be done


-          Once we modify the content of a particular cell (cell validation)


-          Once we modify the content of a particular datagrid row (would like to commit changes to row) (Row Validation)


In this blog, I will try to give an intro both cell validation and row validation by using examples.


 


Cell Validation


Cell Validation can be done in two ways


-          Raising ValidationException in the property setter


-          Using ValidationAttributes and calling ValidateProperty in property setter


Cell Validation by throwing ValidationException in the property setter


In order to understand this concept, let’s consider that our datagrid is populated with a collection of Employee (with the following properties) objects  on which we want to do Cell Validation


        public String firstName;


        public String lastName;


        public int age;


        public String phone;


        public String city;


        public String state;


The validations that we want to do on these properties are


-          Firstname, lastname,  phone, city, state should not be null or empty


-          Age has to be in the range  18 to 50


We define validation rules for these properties (in the setter properties) in the following way.  The ValidationException (belonging to System.ComponentModel.DataAnnotations ) thrown is displayed as Cell Validation Error.


        public string LastName


        {


            get { return lastName; }


            set


            {


                if (value != lastName)


                {


                    if (value == null || value == string.Empty)


                    {


                        throw new ValidationException("Last Name cannot be empty");


                    }


                    lastName = value;


                    NotifyPropertyChanged("LastName");


                }


            }


        }


 cellvalidation1


        public int Age


        {


            get { return age; }


            set


            {


                if (value != age)


                {


                    if (value < 18 || value > 50 )


                    {


                        throw new ValidationException("Age should be between 18 and 50");


                    }


                    age = value;


                    NotifyPropertyChanged("Age");


                }


            }


        }


 cellvalidation2


Using Validation Attributes and calling ValidateProperty in property setter


The properties on which we want to do validation are decorated by validation attributes and we call the validationobject.validateproperty method in the setter of the property.  This tells the validator to verify on the decorated validation attribute when validateProperty is called. 


In the following code snippet,  the Required, Range and RegularExpression validation attributes are used.  The image below them shows the validation error when a validation rule is not met


        [Required]


        public string FirstName


        {


            get { return firstName; }


            set


            {


                if (value != firstName)


                {


                    Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "FirstName" });


                    firstName = value;


                    NotifyPropertyChanged("FirstName");


                }


            }


        }


 cellvalidation3


 


        [Required]


        [Range(18,50)]


        public int Age


        {


            get { return age; }


            set


            {


                if (value != age)


                {


                    Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Age" });


                    age = value;


                    NotifyPropertyChanged("Age");


                }


            }


        }


cellvalidation4 


 


        [Required]


        [RegularExpression("\\d{3}[-]\\d{3}[-]\\d{4}")] // (e.g - "999-999-1234")


        public string Phone


        {


            get { return phone; }


            set


            {


                if (value != phone)


                {


                    Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Phone" });


                    phone = value;


                    NotifyPropertyChanged("Phone");


                }


            }


        }


cellvalidation5 


Row Validation


In addition to doing validation when we edit a particular cell, we can perform validation when we commit a particular row or entity in the datagrid.  In order to do this,we decorate our BusinessObject class with the CustomValidation attribute that specifies the Validation class and the method that are used for validation. The row validation errors are shown at the bottom of the data grid in a error listbox.  Clicking on an error in the listbox focuses on the cell that that has validation error. Resolving the validation error dynamically removes the error from the listbox.


In addition to specifying the CustomValidation attribute on the business object, we can also use the validation attributes on the Properties to show invalid entries as Row Validation errors.

        [Required]


        public string FirstName


        {


            get { return firstName; }


            set


            {


                if (value != firstName)


                {


                    firstName = value;


                    NotifyPropertyChanged("FirstName");


                }


            }


        }


I will use the Employee class with the following properties as an example.  Note that I also show the decorated validation attributes on the properties of Employee just for demo purpose (In actuality the property definition looks similar to the above).


        [Required]


        public string FirstName


 


        [Required]


        public string LastName


 


        [Required]


        public DateTime? BirthDate


 


        [Required]


        [Range(18,50)]


        public int? Age


 


        [Required]


        public String City


 


        [Required]


        public String State


 


        [Required]


        [RegularExpression("\\d{3}[-]\\d{3}[-]\\d{4}")] // (e.g - "999-999-1234")


        public string Phone


 


Please note that we are not explicity calling the Validator.ValidateObject method or throwing ValidationExceptions in the setter for invalid values (Doing so will show cell validation errors).


The business object Employee class is decorated with the following customvalidation attributes


    [CustomValidation(typeof(EmployeeValidator), "IsValidBirthDay")]


    [CustomValidation(typeof(EmployeeValidator), "IsValidBirthDayAge")]


    public class Employee : INotifyPropertyChanged


The EmployeeValidator Class is static and we define validation methods inside it.  The class looks like below for this particular example.


    public static class EmployeeValidator


    {


        public static bool IsValidBirthDay(object employeeObject, ValidationContext context, out ValidationResult validationResult)


        {


            validationResult = null;


            Employee employee = employeeObject as Employee;


            DateTime date = employee.BirthDate.Value;


            int dateComparison = date.CompareTo(DateTime.Today);


            if (dateComparison > 1)


            {


                List<string> properties = new List<string>() { "BirthDate" };


                validationResult = new ValidationResult("Birthday cannot be further than today!", properties);


            }


 


            return !(dateComparison > 1);


        }


 


        public static bool IsValidBirthDayAge(object employeeObject, ValidationContext context, out ValidationResult validationResult)


        {


            validationResult = null;


            Employee employee = employeeObject as Employee;


            DateTime date = employee.BirthDate.Value;


            int age = DateTime.Today.Year - date.Year;


            if (age != employee.Age)


            {


                List<string> properties = new List<string>() { "Age", "BirthDate" };


                validationResult = new ValidationResult("Age does not match with Birthday! Your age should be " + age, properties);


            }


            return (age == employee.Age);


        } 


    }


If you observe the IsValidBirthDay validation method above, this checks if the propertry “Birthdate” is not further from today.     In the following code snippet


List<string> properties = new List<string>() { "BirthDate" };


                validationResult = new ValidationResult("Birthday cannot be further than today!", properties);


 


rowvalidation1


we tell the validator that in this validationmethod, we are checking the property BirthDate only.  We can check more than one property and associate them with a validation error.  This is done for example in the IsValidBirthDayAge  where the (Age,BirthDate) properties are checked for which the code which does this looks like below.    When we click on the validation error in the listbox, we toggle between the properties (Age, BirthDate).


                List<string> properties = new List<string>() { "Age", "BirthDate" };


                validationResult = new ValidationResult("Age does not match with Birthday! Your age should be " + age, properties);


rowvalidation2


As you can see, developers can use these validation features that datagrid supports to develop compeling apps.


Comments (11)
  1. Satish says:

    Hi Jeneate, please let me know the problem you are facing.  

  2. Satish says:

    Hi Jeneate, please let me know the problem you are facing.  

  3. Grouping data in Silverlight DataGrid

  4. I got this question on how do you add grouping to the DataGrid in Silverlight without using the RIA Services

  5. samcov says:

    Why don’t you attach the project to this article?

  6. Sagar Date says:

    Hi Satish,

    Nice article,

    All the ways of validations are collated

    It will be gerat if you add the code along with

    For the third method you have suggested ‘Row Validation’ Can you please add the code required to display the validation summery and also xamal code for same.

    I tried with first and second approach it works fine.But raising the exception on validation is not digesting thing. Can you give more details on third method.

  7. Balakrishna Yeluvolu says:

    Can you share the code, that would be great!!

    Thanks in advance.

    Regards,

    Bala.

  8. Womb1e says:

    Excellent article, helped me loads.

    I tried your code for the row validation but it didn’t work. I kept getting the following error:

    Code: 4004    

    Category: ManagedRuntimeError      

    Message: System.InvalidOperationException: The CustomValidationAttribute method ‘IsValidBirthday’ in type ‘EmployeeValidator’ must return System.ComponentModel.DataAnnotations.ValidationResult.  Use System.ComponentModel.DataAnnotations.ValidationResult.Success to represent success.

    I think the problem might be because you used Silverlight Beta 3 and I am using the now official Silverlight 3 release. Anyway, to get this to work for me I had to alter the EmployeeValidator class as shown below. The static functions must return a ValidationResult not a bool.

       public static class EmployeeValidator

       {

           public static ValidationResult IsValidBirthDay(object employeeObject, ValidationContext context)

           {

               ValidationResult retval;

               Employee employee = employeeObject as Employee;

               DateTime date = employee.BirthDate.Value;

               int dateComparison = date.CompareTo(DateTime.Today);

               if (dateComparison > 1)

               {

                   retval = new ValidationResult("Birthday cannot be further than today!", new List<string>() { "BirthDate" });

               }

               else

                   retval = ValidationResult.Success;

               return result

           }

           public static bool IsValidBirthDayAge(object employeeObject, ValidationContext context, out ValidationResult validationResult)

           {

               ValidationResult  retval;

               Employee employee = employeeObject as Employee;

               DateTime date = employee.BirthDate.Value;

               int age = DateTime.Today.Year – date.Year;

               if (age != employee.Age)

               {

                   retval = new ValidationResult("Age does not match with Birthday! Your age should be " + age, new List<string>() { "Age", "BirthDate" });

               }

               else

                   retval = ValidationResult.Success;

               return retval;

           }

       }

    Regards,

    Womb1e

  9. Nirmal says:

    Hai,

        i am using radgridview. While editing the cell details i am using radGridView_CellValidating event.

    In that,

    void radGridView_CellValidating (object sender, Telerik.Windows.Controls.GridViewCellValidatingEventArgs e)

    {

    e.IsValid = false;

    e.ErrorMessage ="Invalid Data(Some Message)";

    }

    It shows the error message when mouse over on the right top corner of tht red indication. But i need when focusing on that cell or immediate when error occurs(doesn’t need tooltipservice). How can i do this?

  10. Manoj says:

    Suppose there is Save Button Below Grid.  If I Want to Save Information How to Handle Validations On save Button Click….

    Data Grid Give Gives validation but It Completes Save Action Too…

    Help….Please…

Comments are closed.

Skip to main content