如何运行 IDataErrorInfo 验证代码,当我的 IValueConverter 引发异常时

本文关键字:IValueConverter 我的 异常 代码 何运行 运行 验证 IDataErrorInfo | 更新日期: 2023-09-27 18:36:24

我在 WPF 窗口中验证整数时遇到问题。 我的业务对象具有Age:int属性。 我想验证该Age >= 5. 我了解如何使用IDataErrorInfo并将ValidatesOnDataErrors设置为 true。 如果我输入一个数字,那行得通。 但是如果我输入一个空字符串或"abc",则不会调用验证代码。 这是一个问题,因为我有一个按钮,只有在验证代码成功时才希望启用该按钮。

根据我的输出窗口,问题是默认转换器在 ConvertBack 方法中抛出FormatException。 这可以防止代码调用 IDataErrorInfo.this[string columnName] 方法。 (我目前正在使用默认的int转换器)

我已经读过一些解决方案,但它们要么不起作用,要么看起来很笨拙:

  1. 使用 Nullable。 这不会阻止异常。
  2. 使用字符串而不是 int。 这将起作用,但它不允许我利用内置的 WPF 功能。 感觉就像一个黑客。
  3. 我以为我可以使用自己的IValueConverter来拦截 ConvertBack 调用,但我需要向转换器授予对我的业务对象的访问权限,以便它可以设置某种IsValid:bool属性。 我不知道如何为转换器提供对我的业务对象的引用。

ConvertBack引发异常(例如,用户输入空字符串)时,如何验证我的业务对象?


这是我的业务对象:

class DContext : INotifyPropertyChanged, IDataErrorInfo
{
    public DContext()
    {
        this._submit = new Commands.btnSubmit(this);
    }
    private readonly ICommand _submit;
    public ICommand Submit { get { return this._submit; } }
    private int _age;
    public int Age
    {
        get { return this._age; }
        set
        {
            if (this._age != value)
            {
                this._age = value;
                this.OnPropertyChanged();
            }
        }
    }
    private string _error;
    public string Error
    {
        get { return this._error; }
    }
    public string this[string columnName]
    {
        get 
        {
            this._error = null;
            if (columnName == "Age" && this._age < 5)
                this._error = "Age must be >= 5";
            return this._error;
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute]string propertyName = "")
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

这是我的 WPF:

<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Top">
    <TextBlock Text="Age" />
    <TextBox Width="100" Text="{Binding Age,ValidatesOnDataErrors=True}" />
    <Button Content="Submit" Command="{Binding Submit}" />
</StackPanel>

有趣的是,我注意到ICommand.CanExecute方法在IDataErrorInfo.this[string columnName]方法之前被调用。 这意味着ICommand正在使用尚未验证的值。 这意味着我将不得不复制我的错误检测代码。

如何运行 IDataErrorInfo 验证代码,当我的 IValueConverter 引发异常时

我认为解决方案必须是#2或#3。 我倾向于#3,因为它不会给您的视图模型带来任何混乱。 让"ConvertBack"方法尝试解析输入,如果解析失败,则返回无效值(可能是 0 或 -1)。

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string input = value as string;
        int validNumber;
        if (input != null && int.TryParse(input, out validNumber))
            return validNumber;
        else
            return 0;
    }

您的验证应该与此一起使用,没有其他更改。 我可以看到使用 #2 的唯一原因是,如果您想要不同的错误消息,例如"年龄字段是必需的"和"年龄字段必须是有效数字"。

这意味着 ICommand 正在使用尚未验证的值。这意味着我将不得不复制我的错误检测代码。

我不确定为什么这是必要的。 您不能在验证运行时引发"Command.CanExecuteChanged"吗? 如果没有,那么您可能需要考虑使用 INotifyDataErrorInfo 而不是 IDataErrorInfo ,因为它允许您引发"ErrorsChanged"事件来触发验证。