views:

238

answers:

2

I'm trying to find a simple way of binding a single control (eg. TextBlock or ListBox) to list all the validation errors on a WPF form. Most source code examples I have been able to find just bind a control to (Validation.Errors)[0].ErrorContent which only shows a single validation error.

I'm currently using ValidationRule classes, though I'm open to using IDataErrorInfo, or building a custom validator. I'm just not sure how to accomplish what I would expect to be a common use-case.

How do I list all validation errors in one control on a WPF form?

+1  A: 

I don't think you can do anything like this using (Validation.Errors) binding. The reason is that Validation attached property provides one-to-one relationship between a bound control and an adorner site, so you just cannot combine validation errors from different controls in one adorner - the last one would always "take over" the site. BTW, I have no idea why Validation.Errors is an array - maybe for multiple errors from the same control?

But there is still hope - you have at least two ways to solve this, without using validation adorners.

The first one is simple as a nail - if you use IDataErrorInfo, you have some mechanism for checking the bound values of your object for validity. You could then write something along the lines of

public IEnumerable<string> CombinedErrors
{
    get { 
           if (FirstValErrror) yield return "First value error"; 
           if (SecondValErrror) yield return "Second value error"; 
        }
}

and bind some ItemsControl to the CombinedErrors property

The second one would involve setting NotifyOnValidationError=True on each binding (to raise Validation.Error routed event) and catch this event on the top container:

public List<ValidationError> MyErrors { get; private set; }

private void Window_Error(object sender, 
    System.Windows.Controls.ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
        MyErrors.Add(e.Error);
    else
        MyErrors.Remove(e.Error);
}

then you can bind these similarly to any ItemsControl.

Sergey Aldoukhov
He-he :). You were first, Sergey. One more way to go here might be a custom binding converter ( http://msdn.microsoft.com/en-us/library/ms752347.aspx#data_conversion ).
Anvaka
Thanks Sergey! I opted for the second method you suggested and just a couple minor adjustments were required to make it work:a. Using a List<> to contain the ValidationError objects almost worked but the ListView control doesn't get updated automatically. Swapping it for an ObservableCollection or BindingList did the trick.b. Probably obvious, but I needed to use an ItemTemplate on my ListView to display the ErrorContent property of the ValidationError.
Diametric
A: 

Diametric,

It is quite possible to do this by implementing your own ValidationRule with the help of some added Behaviours.

The idea is to manage your own list of ValidationResult in your code-behind / ViewModel and pass it into the TextBoxes that you wish to extract errors from. Again, using the same collection, bind it to your ListBox or TextBlock to retrieve the errors.

I've written an article on how you can go about creating you own validation error tracker, or feel free to download the source code and use it as is.

Hope that helps.

Tri Q