6
votes

I have a textbox in a WPF application bound to a property on a Linq to Entities class that implements IDataErrorInfo. The textbox binding has ValidatesOnExceptions=True and ValidatesOnDataErrors=True. When the textbox is bound to an integer property and the user enters text then the textbox outline displays as red as I haven't set up a custom style.

In my Save method how do I know the object can't be saved as it's invalid? I'd prefer the user clicks the Save button and I can notify them of a problem rather than disabling the Save button.

Cheers,

Dave

2

2 Answers

5
votes

I haven't found an easy way to do it. I found some code around the traps to recurse through all the controls on the form and determine if any of them have validation errors. I ended up turning it into an extension method:

// Validate all dependency objects in a window
internal static IList<ValidationError> GetErrors(this DependencyObject node)
{
    // Check if dependency object was passed
    if (node != null)
    {
        // Check if dependency object is valid.
        // NOTE: Validation.GetHasError works for controls that have validation rules attached 
        bool isValid = !Validation.GetHasError(node);
        if (!isValid)
        {
            // If the dependency object is invalid, and it can receive the focus,
            // set the focus
            if (node is IInputElement) Keyboard.Focus((IInputElement)node);
            return Validation.GetErrors(node);
        }
    }

    // If this dependency object is valid, check all child dependency objects
    foreach (object subnode in LogicalTreeHelper.GetChildren(node))
    {
        if (subnode is DependencyObject)
        {
            // If a child dependency object is invalid, return false immediately,
            // otherwise keep checking
            var errors = GetErrors((DependencyObject)subnode);
            if (errors.Count > 0) return errors;
        }
    }

    // All dependency objects are valid
    return new ValidationError[0];
}

So then when the user clicks the Save button on a form, I do this:

var errors = this.GetErrors();
if (errors.Count > 0)
{
    MessageBox.Show(errors[0].ErrorContent.ToString());
    return;
}

It's a lot more work than it should be, but using the extension method simplifies it a bit.

3
votes

You could set NotifyOnValidationError to true on your Bindings, then add a handler for the Error event on some parent element. The event will fire whenever an error is added or removed.