Background

ValidationRules

When you use the WPF data binding model, you can associate ValidationRules with your binding object. To create custom rules, make a subclass of this class and implement the Validate method. The binding engine checks each ValidationRule that is associated with a binding every time it transfers an input value, which is the binding target property value, to the binding source property.

IDataErrorInfo

From the original blog post of Marianor about using attributes with IDataErrorInfo interface:

WPF provides another validation infrastructure for binding scenarios through IDataErrorInfo interface. Basically, you have to implement the Item[columnName] property putting the validation logic for each property requiring validation. From XAML, you need to set ValidatesOnDataErrors to true and decide when you want the binding invoke the validation logic (through UpdateSourceTrigger).

Combining IDataErrorInfo and attributes

In this article, we use a technique which combines validation attributes (an explanation of each validation attribute is out of the scope of this article) and the IDataErrorInfo interface.

Overall Design

Here is the class diagram of the application’s classes:

There is nothing really new here. The MainWindow’s Content is set to the MainFormView view. The associated ViewModel, MainFormViewModel manages a set of FormViewModel which is the base ViewModel class for each tab in the View.

In order to specify to the WPF engine how to render a FormViewModelBase, all we need to do is to create a DataTemplate and gives the correct TargetType. For example, in order to associate the ProfileFormViewModel with the ProfileFormView, we create this DataTemplate:

Then the DataBinding does everything to populate the content of the TabControl using this very simple XAML:

<TabControlItemsSource="{Binding Forms}"/>

This is very similar to an approach I blogged a couple of months ago (see here for more details). The new stuff resides in the ValidationViewModelBase class which is the new base class I’m introducing for ViewModel classes which need to support validation. That’s the goal of the next section of this article.

Attribute-based Validation and the IDataError Interface

The solution I’m using here to combine attributes and IDataError interface is based on the work of Marianor (full article here). I tweaked a little bit of his code in order to have a generic solution (and that’s the goal of the ValidationViewModelBase class). The basic idea is to be able to implement the IDataErrorInfo interface (and its 2 properties) in a generic way using attributes in System.ComponentModel. The class uses extensively LINQ in order to perform the validation.

Please note I’m also exposing the number of valid properties and the total number of properties with validation (this is used in order to compute the value of the progress bar). From the developer point of view, using this class in an existing ViewModel is very straightforward: Inherit from the new ValidationViewModelBase class instead of your traditional ViewModelBase class and then add validation attributes on the properties which requires validation.

Available Attributes (from the System.ComponentModel.DataAnnotations namespace)

Specifies a custom validation method to call at run time (you must implement the IsValid() method)

Dealing with Validation Exceptions

As I was working with this new approach based on attributes, I faced a problem: how to deal with validation exception. A validation exception happens when the user input is incorrect, for example if a TextBox has its Text property to an int property, then an input like "abc" (which cannot be converted of course to an int) will raise an exception.

The approach I'm proposing is based on a behavior. A complete description of what behaviors are is out of the scope of this article. For a nice description, you can check out this article.

The behavior I'm proposing must be attached to the parent UI elements which contain the input controls that can raise exception. These are a couple of lines in the XAML:

When this behavior is loaded, it adds an handler for the ValidationError.ErrorEvent RoutedEvent so that it is notified each time a validation error occurs. When this happens, the behavior calls a method on the ViewModel (through a simple interface in order to limit coupling) so that the ViewModel can track the number of validation errors. Here is the code of the behavior:

Progress Reporting

One of my requirements was “When a tab is fully completed, it goes from red: to green: ”. In order to realize this particular feature, I added an “IsValid” property to the FormViewModelBase class (which is the base class for all ViewModels in the TabControl). This property is updated whenever a PropertyChanged occurs by looking if the Error property (of the IDataErrorInfo interface) is empty:

Points of Interest

The goal of this technique as I said in the introduction is to have a replacement for the traditional ValidationRules approach which complicates the XAML a lot. Using LINQ and Attributes is a nice way to implement this new possibility. While approaching the end of the writing of this article, I noticed that a similar solution is available in a famous MVVM frameworks made by Mark Smith (the MVVM Helpers).

Acknowledgment

I would like to profusely thank people who helped me to review this article: my co-worker Charlotte and Sacha Barber (CodeProject and Microsoft MVP).

Hi Jerremy, thanks for this great code (5 from me). One thing I do not understand. If I remove ErrorMessage from Attribute declaration, validation errors would not occur at all. Why is this happening? I am using a localization that doesn't use resource files (for some specific requirements), so I use Custom attributes for validation, where I localize messages.
So, when I remove ErrorMessage, validation stops. Do you know why?

Not sure but I guess the string this[string propertyName] property returns an empty string if the ErrorMessage property is not set. In this case, the IDataErrorInfo might not works... Maybe you could try returns " " instead...

I jjust needed to go with GetFormattedMessage instead of ErrorMessage, and it started working. THe last problem I face is that this does not work with reference properties that contain null as initial value. An example would be that I have a ComboBox bound to some list, and SelectedValue to the foreign key property for this reference. UI never gets infored about validation errors, because this[string PropertyName] never gets fired for reference property (probably because its null). Do you know any workaround for this problem?