当我的IValueConverter抛出异常时,如何运行IDataErrorInfo验证代码?

时间:2015-01-06 18:39:34

标签: c# wpf validation icommand

我在WPF窗口中对整数进行验证时遇到问题。我的业务对象具有Age:int属性。我想验证Age >= 5。我看到如何使用IDataErrorInfo并将ValidatesOnDataErrors设置为true来执行此操作。如果我输入一个数字,这是有效的。但是如果我输入一个空字符串或"abc",验证码就不会被调用。这是一个问题,因为我有一个按钮,只有在验证代码成功时我才能启用它。

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

我已经阅读过有关这方面的几个解决方案,但他们要么不工作,要么看起来很蠢:

  1. 使用Nullable< int> 。这并不能防止异常。
  2. 使用字符串而不是int 。这可行,但它不允许我利用内置的WPF功能。感觉就像是黑客。
  3. 我以为我可以使用自己的IValueConverter 来拦截ConvertBack调用,但我需要让转换器访问我的业务对象,以便它可以设置一些IsValid:bool属性。我不知道如何为转换器提供对业务对象的引用。
  4. 如果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正在使用尚未验证的值。这意味着我必须复制我的错误检测代码。

1 个答案:

答案 0 :(得分:1)

我认为解决方案必须是#2或#3。我会倾向于#3,因为它不会在视图模型中引入任何混乱。拥有&#34; ConvertBack&#34;方法尝试解析输入,并在解析失败时返回无效值(可能为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的唯一原因是,如果您想要不同的错误消息,例如&#34;年龄字段是必需的&#34;和&#34;年龄字段必须是有效数字&#34;。

  

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

我不确定为什么这是必要的。你不能只提出'#34; Command.CanExecuteChanged&#34;验证运行时?如果没有,那么您可能需要考虑使用INotifyDataErrorInfo代替IDataErrorInfo,因为它允许您引发&#34; ErrorsChanged&#34;触发验证的事件。