WPF and DataAnotations

A few weeks ago I took MVC 3 course at E4D with Eyal Vardi.

www.slideshare.net/EyalV/aspnet-mvc-30-validation

One of the subjects we learned is how to validate Object or property-using validation attributes.

First thing I thought about is why WPF does not support Data Annotations validation?

Validation and WPF:

  1.    The Classic way:

Throw an error exception from the property set method.

For example:

    private string _albumName;
    public string AlbumName
	{
		get {
            return _albumName;
        }
		set
        {

            if (string.IsNullOrEmpty(value))
            {
                throw new ArgumentException("Album name must be specified");
            }
            else
            {
                _albumName = value;
                OnPropertyChanged("AlbumName");
            }
        }
	}

This validation logic is not the best practice to validate property because we don’t want to throw exception each time the user entered not valid input.

2.     Validation Rules:

Validation Rules is the WPF data binding built in validation mechanism. By this mechanism, we need to create distinct class like value converter that implement the validation logic and throw exception for invalid data.

For example:

public class AlbumValidationRule : ValidationRule

{

public override validationResult Validate(object value, CultureInfo cultureInfo)

{

                 if(string.IsNullOrEmpty(value))
{

                 throw new ValidationResult(false,“Album name must be specified”);
}

}

}

this mechanism gives us more flexibility and code reuse but it’s very complicated to implement and this mechanism does not support the MVVM pattern because we put logic into the UI.

3.     IDataErrorInfo:

This interface exists since .NET Framework version 1 released. The interface exposes two properties Error and Item the item.

Error property present the validation error message, Item property Invoke each time the binding engine triggered the validation engine.

Validation by DataAnotations and IDataErrorInfo:

By validation attributes, we can minimize the validation code, we can reuse the validation logic and we keep the validation process simple.

This pattern hide all the validation rules and give us very clean business view models,  each property get set of validation attributes defining the validation rules.

To support this pattern I need to add reference to (System.ComponentModel.DataAnnotations namespace) and use the Validator class to verify whether a property is valid.

Let’s look at the Base View Model.

My base view model implements the IdataErrorInfo to support data binding validation:

Base View Model:

public class ViewModelBase:INotifyPropertyChanged, IDataErrorInfo {
   public ViewModelBase()
        {
            ErrorMessage = string.Empty;

        }
        #region Properties

        public string ErrorMessage { get; set; }

        #endregion

}
public string Error
{
      get { return ErrorMessage; }
}

public string this[string columnName]
{
     get { return ErrorMessage; }
}

The SetPropertyValue method invokes each time new data comes to the setter method of the property,

The method sets the property value and check the validation rule to the property.

protected void SetPropertyValue(String propertyName, ref T current    alue, T newValue)
{
   if (currentValue == null)
   {
      if (newValue == null)
                    return;
   }
   else if (newValue != null && currentValue.Equals(newValue))
   {
        return;
   }
       currentValue = newValue;
       ValidateProperty(propertyName, newValue);
       OnPropertyChanged(propertyName);
   }

}

The code bellow responsible for the validation of the given property, the ValidateProperty method gets the property name and his value, by using the TryValidatePropert method of the Validator class we can validate the property.

 protected void ValidateProperty(string propertyName, object value)
 {

    var vrs = new List();
    ErrorMessage =  string.Empty;

      if (!Validator.TryValidateProperty(value, new ValidationContext(this, null, null) { MemberName = propertyName }, vrs))
    {
                IsValid = false;
                foreach (var item in vrs)
                {
                  ErrorMessage =  string.Join(Environment.NewLine, vrs.Select(x => x.ErrorMessage));
                }
            }
            else
            {
                IsValid = true;
            }

        }

View Model:

Album view model inherits from BaseViewModel.

Above each property, we put a set of validation attributes and by SetPropertyValue method we set the property value

public class AlbumViewModel : ViewModelBase
{
    private int _length;

    [Required(ErrorMessage = "Length must be specified")]
    [Range(0, 200)]
    public int Length
    {
       get
       {
         return _length;
       }
       set
       {
         this.SetPropertyValue("Length", ref _length, value);
       }
    }
}

View:

 <TextBox Text="{Binding Path=Length, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
                        ValidatesOnDataErrors=True,
                        ValidatesOnExceptions=True,
                        NotifyOnValidationError=True}"
           Validation.ErrorTemplate="{StaticResource validationTemplate}"         
           Grid.Column="2"
           Grid.Row="3"/>

To indicate the user when his input is invalid we need to set NotifyValidationError to true, this property activate the validation engine of the data binding, we set also the ValidatesOnDataErrors and ValidatesOnExceptions to support all validation implementation ways.

As you can see, using Data Anotations validation gives us elegant and clean way to support validation rules on property. With this pattern we can create custom attributes to support more complex validation rules, and if we want we can use our attributes collection in any other project.

Available validation frameworks:
1.     Validation Toolkit : http://validationtoolkit.codeplex.com/ 
Validation Toolkit for WPF & Silverlight displays automatically validation errors coming from both Data Annotations on the View Model and Asynchronous calls to Web Services. The View Model is wrapped into an object that supplies all needed interface implementations.

2.     WPF Application Framework: http://waf.codeplex.com/
The WPF Application Framework (WAF) is a lightweight Framework that helps you to create well structured WPF Applications. It supports you in applying a Layered Architecture and the Model-View-ViewModel (aka MVVM, M-V-VM, PresentationModel) pattern.

3.     Microsoft Enterprise Library :  http://entlib.codeplex.com/
This framework including the Validation Application Block uses the same general approach—validating an object against a set of
rules defined using attributes (data annotations) or an external XML file.
Advertisements

About Idan Reuven

Idan is Microsoft Certified Proffesional Developer (MCPD) Idan Working As Senior Software developer. and specialize in professional application development with WPF, WCF, Entity Framework, XAML, HTML 5, Java Script , jQuery, MVC, MVVM, C#, C++, SQL Server Technologies.
This entry was posted in .NET, WPF. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s