【问题标题】:How to handle exception in Value converter so that custom error message can be displayed如何处理值转换器中的异常,以便可以显示自定义错误消息
【发布时间】:2011-05-25 11:39:32
【问题描述】:

我有一个文本框,它绑定到一个类型为 Timespan 的属性的类,并编写了一个值转换器将字符串转换为 TimeSpan。

如果在文本框中输入了非数字,我希望显示自定义错误消息(而不是默认的“输入字符串格式错误”)。

转换器代码为:

    public object ConvertBack(
        object value,
        Type targetType,
        object parameter,
        CultureInfo culture)
    {
        try
        {
            int minutes = System.Convert.ToInt32(value);
            return new TimeSpan(0, minutes, 0);
        }
        catch
        {
            throw new FormatException("Please enter a number");
        }
    }

我在 XAML 绑定中设置了“ValidatesOnExceptions=True”。

但是,我遇到了以下 MSDN 文章,它解释了为什么上述方法不起作用:

"数据绑定引擎不会捕获用户提供的转换器抛出的异常。任何由 Convert 方法抛出的异常,或由 Convert 方法调用的方法抛出的任何未捕获的异常,都被视为运行时错误”

我已经读到'ValidatesOnExceptions 确实在 TypeConverters 中捕获了异常,所以我的具体问题是:

  • 什么时候使用 TypeConverter 而不是 ValueConverter
  • 假设 TypeConverter 不是上述问题的答案,我如何在 UI 中显示我的自定义错误消息

【问题讨论】:

  • WPF 数据绑定中的错误应该是透明的,因此一个小错误不会杀死整个应用程序或 UI。您可以记录异常,但尝试执行其他任何操作都会破坏数据绑定的设计。

标签: wpf data-binding ivalueconverter


【解决方案1】:

我会为此使用ValidationRule,这样转换器可以确保转换工作,因为它仅在验证成功时调用,您可以使用附加属性Validation.Errors,它将包含您的错误ValidationRule 如果输入不是您想要的方式,则创建。

例如(注意工具提示绑定

<TextBox>
    <TextBox.Style>
        <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="Background" Value="Pink"/>
                    <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
    <TextBox.Text>
        <Binding Path="Uri">
            <Binding.ValidationRules>
                <vr:UriValidationRule />
            </Binding.ValidationRules>
            <Binding.Converter>
                <vc:UriToStringConverter />
            </Binding.Converter>
        </Binding>
    </TextBox.Text>
</TextBox>

【讨论】:

  • 谢谢 HB,我试试看
  • 不幸的是,这只适用于一种方式。 ValidationRules 仅在返回时运行,从 UI 到数据源。您不能使用它来拦截或处理转换器在 Convert 方法中抛出的异常。
  • @Will:如果您有自定义验证规则,我认为转换器不应该抛出任何异常;当数据来自模型时,它应该是有效的,如果用户输入无效数据,则不应调用转换器,因为 ValidationRule 不允许它通过。
  • @H.B.:但有时当数据来自模型时,它无效有效。如果无法在转换器中处理异常,您必须在 ViewModel 或您的模型中进行与 UI 相关的验证。例如,视图希望将文件显示为 XML 文件,因此必须从文件中读取文本并将其转换为 XmlDocument。但是当文件不是有效的 XML 文件时会发生什么?是否应该将检查视图状态的责任推给视图模型?破坏 MVVM。
  • @Will:看起来问题不大,你仍然可以添加一个ExceptionValidationRule,不是吗?
【解决方案2】:

我使用验证和转换器来接受null 和数字

XAML:

<TextBox x:Name="HeightTextBox" Validation.Error="Validation_Error">
    <TextBox.Text>
        <Binding Path="Height"
                 UpdateSourceTrigger="PropertyChanged" 
                 ValidatesOnDataErrors="True"
                 NotifyOnValidationError="True"
                 Converter="{StaticResource NullableValueConverter}">
            <Binding.ValidationRules>
                <v:NumericFieldValidation />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

代码背后:

private void Validation_Error(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
        _noOfErrorsOnScreen++;
    else
        _noOfErrorsOnScreen--;
}

private void Confirm_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = _noOfErrorsOnScreen == 0;
    e.Handled = true;
}

验证规则:

public class NumericFieldValidation : ValidationRule
{
    private const string InvalidInput = "Please enter valid number!";

    // Implementing the abstract method in the Validation Rule class
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        float val;
        if (!string.IsNullOrEmpty((string)value))
        {
            // Validates weather Non numeric values are entered as the Age
            if (!float.TryParse(value.ToString(), out val))
            {
                return new ValidationResult(false, InvalidInput);
            }
        }

        return new ValidationResult(true, null);
    }
}

转换器:

public class NullableValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (string.IsNullOrEmpty(value.ToString()))
            return null;
        return value;
    }
}

【讨论】:

  • 感谢您提供完整的解决方案!对于无法运行 Validation_Error 的任何人,请确保在 XAML 中包含 NotifyOnValidationErrors。由于我已经有 IDataErrorInfo 样式的错误验证(以及因此 ValidateOnDataErrors),我浏览了 XAML 并错过了这个细节。
  • @Tim 伙计,这是 NotifyOnValidationError ,而不是 NotifyOnValidationErrors
【解决方案3】:

您不应该从转换器中抛出异常。我将实现 IDataErrorInfo 并在其上实现 Error 和 String。请查看https://web.archive.org/web/20110528131712/http://www.codegod.biz/WebAppCodeGod/WPF-IDataErrorInfo-and-Databinding-AID416.aspx。 HTH丹尼尔

【讨论】:

  • 感谢 Daniell,但我想报告异常错误而不是绑定对象中的错误。我相信 IDataErrorInfo 只允许后者
猜你喜欢
  • 2010-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-26
  • 1970-01-01
  • 2013-07-05
  • 2016-03-12
相关资源
最近更新 更多