Jim Rogers

Lives in Baton Rouge, LA, with two dogs, one cat, and one lovely wife. I'm a lead developer for GCR Incorporated.

Katrin and Jim

Month List

WPF Validation Exceptions

by Jim Mar 15, 2009 5:01 PM

The MSDN binding validation sample would have you bind your validation error messages like so:

<Trigger Property="Validation.HasError" Value="true">
<
Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</
Trigger>

This code will flood your output window with exceptions – and if you have the “break when exception is thrown” option turned on, you'll be doing a whole lot of stepping through these.

A first chance exception of type 'System.FormatException' occurred in mscorlib.dll A first chance exception 
of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll A first chance exception of type
'System.Reflection.TargetInvocationException' occurred in mscorlib.dll System.Windows.Data Error: 16 :
Cannot get 'Item[]' value (type 'ValidationError') from '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1').
BindingExpression:Path=(0).[0].ErrorContent; DataItem='TextBox' (Name='textBox1'); target element is 'TextBox'
(Name='textBox1'); target property is 'ToolTip' (type 'Object')

TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target
of an invocation. ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and
less than the size of the collection.
Parameter name: index at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument,
ExceptionResource resource)
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)
at System.Collections.ObjectModel.ReadOnlyCollection`1.get_Item(Int32 index)
--- End of inner exception stack trace ---
. . . at MS.Internal.Data.PropertyPathWorker.RawValue(Int32 k)'

The problem appears to be that when the error is cleared (and HasError is false,) the binding is trying to evaluate again anyway. So the index of zero is out of range.

Josh Smith has a workaround for this that involves a content and data presenter. It’s a little heavy for my taste.

However that solution and this post detailing Microsoft’s failure to fix this known issue started me on the following solution:

<Setter Property="ToolTip" 
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors).CurrentItem,
Converter={StaticResource ValidationErrorConverter}}"/>

The CurrentItem property is null if there is nothing in the collection – so no exceptions are thrown evaluating it if there are no errors. It is an instance of ValidationError, however, and doesn't have a useful ToString() override. So I'm using an IValueConverter to get the error message. Here it is in its entirety:

/// <summary> 
///
Helps with avoiding of exceptions when setting a tooltip to the validation error
/// </summary>
/// <remarks>
///
Bind to Path=(Validation.Errors).CurrentItem, and use this converter
/// </remarks>
public class ValidationErrorConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { var error = value as ValidationError; // If we have an error, return its content if (error != null) return error.ErrorContent; else return ""; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { // Can't convert back to a ValidationError throw new Exception("The method or operation is not implemented."); } }

Tags:

Code

Comments (2) -

6/1/2011 10:02:42 AM #

skidaddy

This solution is clean and simple!  I love it, good work.

skidaddy United States

12/7/2011 5:11:51 PM #

Tim Murphy

Perfect! Thank you.

Tim Murphy Australia

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading