来自属性setter函数的WPF数据验证

时间:2010-08-02 07:34:28

标签: c# wpf validation exception idataerrorinfo

我有一个绑定到GUI元素的类,如下所示:

<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>

MaxDistance属性的setter在这里实现:

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;
  }
}

问题是,当我在TextBox中输入无效值时,出现的工具提示显示“调用目标已抛出异常”,而不是“最大距离必须大于最小距离”。

我应该怎样做才能让工具提示读取ArgumentException的字符串? 注意:标准类型转换异常也必须正确显示(即如果我输入字符串而不是浮点数,则仍应出现标准错误消息。)

我无法将异常移动到IDataErrorInfo接口中,因为如果对象无效,则不能在对象上设置数据,并且由于属性与对象的其他属性相互依赖,因此无法进行此验证通过转换器或典型的验证规则......

在上面的例子中,验证在那里并且有效,它只是没有向用户提供有用的信息。

感谢您的帮助

1 个答案:

答案 0 :(得分:2)

似乎解决此问题的唯一方法是使工具提示绑定更加智能。

我将工具提示上的绑定更改为:

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

按如下方式实施转换器:

    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
    }