Skip Navigation LinksHome > View Post

New in WPF 3.5: 2. Support for IDataErrorInfo

In my last post I started a short series looking at some of the new features for WPF in .NET 3.5. In that post we ended by pointing out the new ValidatesOnDataErrors property of a binding and promised to explain its purpose in the next post. So here goes...

We've already explained how validation works and, at the end of Reason 10. Validation (of the series:10 reasons to consider WPF for your next desktop application), we created a CustomValidationRule.

The example gave the code for a StringLengthValidationRule that validated the length of a string (does what it says on the tin). This could be added to our collection of Binding ValidationRules in Xaml as follows:

<TextBox>
    <TextBox.Text>
        <Binding Path="PostCode">
            <Binding.ValidationRules>
             <src:StringLengthValidationRule MinLength="6" MaxLength="7" />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

This scores on a couple of fronts, not least its reusability. However, what I don't like about this approach is that the UI now contains the logic to validate the state of the bound object. It would make much more sense if this were in some way connected to the object in question and could therefore be reused anywhere in the stack (maybe even on the server, if you're sharing types:).

Since .NET 1.1 the System.ComponentModel namespace has offered an interface called IDataErrorInfo for just this purpose. Let's take a look:

// Summary:
// Provides the functionality to offer custom error
// information that a user interface can bind to.
public interface IDataErrorInfo
{
    // Summary:
    // Gets an error message indicating what is wrong with this object.
    // Returns:
    // An error message indicating what is wrong with this object.
    // The default is an empty string ("").
    string Error { get; }

    // Summary:
    // Gets the error message for the property with the given name.
    // Parameters:
    // columnName:
    // The name of the property whose error message to get.
    // Returns:
    // The error message for the property.
    // The default is an empty string ("").
    string this[string columnName] { get; }
}

Personally, I think this 'API' feels a little clunky and dated in the contemporary surroundings of WPF but this is explained when you know that the first class to implement this interface was DataRowView of DataSet infamy (In fact, as far as I can tell this is still the only class in the whole BCL that implements IDataErrorInfo).

Nonetheless, this doesn't mean that we can't use IDataErrorInfo as part of our own objects. Not least because WPF 3.5 now supports IDataErrorInfo out of the box.

Time for a demonstration. First, we need a type that needs some validation so we'll go for something like simple like this:

public class Employee
{
    public string EmployeeId { get; set; }
    public string Name { get; set; }
}

And the logic we're going to apply is to ensure that the EmployeeId property has exactly 9 characters. We could have done this in the UI using our existing StringLengthValidationRule with the following settings:

<src:StringLengthValidationRule MinLength="9" MaxLength="9" />

But we want this logic associated with the class in question, so let's implement IDataErrorInfo;

public class Employee : IDataErrorInfo
{
    public string EmployeeId { get; set; }
    public string Name { get; set; }

    string IDataErrorInfo.Error
    {
        get { return null; }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get
        {
            // Here's the 'magic'
            if (columnName == "EmployeeId")
            {
                if (string.IsNullOrEmpty(EmployeeId) ||
                    EmployeeId.Length != 9)
                {
                    return "The Employee Id must be 9 characters long";
                }
            }
            return null;
        }
    }
}

Note, I wouldn't recommend an actual implementation that looks like this and would suggest you look at something like the Validation Applicaiton Block to implement the validation logic - this example is the minimum required for a working example.

Finally, to get this working in WPF we need to add the DataErrorValidationRule which we can do in a verbose way...

<TextBox>
    <TextBox.Text>
        <Binding Path="EmployeeId">
            <Binding.ValidationRules>
                <DataErrorValidationRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

.. or the short way thanks to the new ValidatesOnDataErrors property:

<TextBox Text="{Binding EmployeeId, ValidatesOnDataErrors=True}" />

And that closes the 'cliffhanger' from the last post. Next, we'll take a look at some of the enhanced debugging features.

Tags: WPF

 
Josh Post By Josh Twist
11:16 AM
21 Jan 2008

» Next Post: Powershell to test your XPath
« Previous Post: New in WPF 3.5: 1. Neater syntax for core Validation Rules

Comments are closed for this post.

Posted by Pete w @ 21 Jan 2008 3:57 PM
Hi Josh!

It is a funny coincidence on the timing of your posting, I've been mulling the issue of databinding and validation in WPF just this afternoon.

I must say that WPF presents some new and interesting UI programming techniques, but I have been disappointed with validation! For example, WPF swallows binding and property setting exceptions as a default behavior (to the output console), who would want to swallow exceptions like this as default behavior?

I have a scenario where I have "smart" business objects that handle their own validation logic. PostSharp allows me to inject validators on my properties at compile time. If I try to set a property with something invalid, they throw an exception before the property setter executes.

I want a WPF layer that binds to properties in these objects, if the user attempts to pass invalid data, the exception is caught, perhaps a MessageBox appears with the formatted Exception message, and the control change is rolled back to its consistent state.
My business objects are finished. I have little interest in redesigning and implementing IDataErrorInfo all over the place.

I havent found a simple configuration with WPF to just catch exceptions and bring them directly to the user. Maybe there is some way to implement IDataErrorInfo at compile time? I dont know, but I must say that WPF is full of surprises, good and bad.

© 2005 - 2014 Josh Twist - All Rights Reserved.