Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Binding - How to determine object is invalid to prevent Save

Tags:

.net

binding

wpf

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

like image 556
Dave Barker Avatar asked Mar 13 '09 02:03

Dave Barker


2 Answers

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.

like image 91
Matt Hamilton Avatar answered Sep 28 '22 07:09

Matt Hamilton


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.

like image 34
Robert Macnee Avatar answered Sep 28 '22 08:09

Robert Macnee