views:

68

answers:

1

Hi There,

I have a class that is bound to GUI elements as follows:

<TextBox Style="{StaticResource ValidatedTextBox}" 
  Text="{Binding MaxDistance, ValidatesOnExceptions=True}" >
  <TextBox.Style>
    <Style TargetType="TextBox" >
      <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
          <Setter Property="ToolTip">
            <Setter.Value>
              <Binding Path="(Validation.Errors).CurrentItem.ErrorContent"
                RelativeSource="{RelativeSource Self}" />
            </Setter.Value>
          </Setter>
        </Trigger>
      </Style.Triggers>
    </Style>
  </TextBox.Style>
</TextBox>

The setter for the MaxDistance property is implemented here:

public float MaxDistance
{
  get { return m_maxDistance; }
  set
  {
    // Check for valid values
    if (value < MinDistance)
      throw new ArgumentException(
        "Max distance must be greater than min distance");

    m_maxDistance = value;
  }
}

The trouble is, when I enter an invalid value into the TextBox, the tooltip that appears says "Exception has been thrown by the target of an invocation" instead of "Max distance must be greater than min distance".

What should I be doing to get the tooltip to read the ArgumentException's string? NOTE: Standard type conversion exceptions must still display properly too (i.e. If I enter a string instead of a float the standard error message should still appear).

I can't move the exceptions into an IDataErrorInfo interface, as the data mustn't be set on the object if it is invalid, and due to the property's interdependance on other properties of the object this validation can't be done via converters or typical validation rules...

In the above example, the validation is there and working, it just isn't presenting useful information to the user.

Thanks for the help

A: 

It appears the only way to get around this problem is to make the tooltip binding smarter.

I changed the binding on the tooltip to be this:

<Binding Path="(Validation.Errors)[0]"
     RelativeSource="{RelativeSource Self}"
     Converter="{StaticResource ValidationExceptionConverter}"/>

And implemented the converter as follows:

    public class ValidationExceptionConverter : IValueConverter
    {
        #region IValueConverter Members

        // From string to 
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            ValidationError error = value as ValidationError;
            if (error == null)
                return null;

            Exception exception = error.Exception;
            if (exception == null)
            {
                return error.ErrorContent;
            }
            else
            {
                // Find the innermost exception
                while (exception.InnerException != null)
                    exception = exception.InnerException;

                // Use it's message as output
                return exception.Message;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
JoshG