代码之家  ›  专栏  ›  技术社区  ›  astonish

通知ViewModel ValidateNextExceptions输入错误

  •  5
  • astonish  · 技术社区  · 15 年前

    在我的应用程序中,我有绑定到文本框的数字(double或int)viewModel属性。ViewModel实现IDataErrorInfo以检查输入的值是否在“业务逻辑”的可接受范围内(例如,高度不能为负值)。我每页有许多文本框,并且有一个按钮(在向导中考虑“下一步”)它的启用属性绑定到一个viewModel布尔值,该布尔值指定页面整体上是否有任何错误。根据我编写的IDataErrorInfo规则,按钮的启用/禁用状态用有效/无效值正确更新。

    但是,由于输入值未转换(即“12bd39”不是有效的双精度值),因此无法让我的ViewModel知道何时引发了异常,因此在转换异常的情况下,尽管输入错误,我的“下一步”按钮仍将保持启用状态。但是,由于我的绑定,GUI正确地反映了修饰器的错误:

    <TextBox Text="{Binding Temperature, Mode=TwoWay, ValidatesOnExceptions=True, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
    

    如何让视图知道发生了“validateNextExceptions”样式错误。乔希·史密斯 here 似乎依赖于使每个ViewModel属性都成为一个字符串,并滚动您自己的异常检查,这看起来像是许多额外的工作。我还开始研究卡尔·希夫莱特的实现 here ,但在将此代码放入视图的代码隐藏文件时,我似乎无法捕获预期的路由事件:

    public ViewClass()
    {
     this.InitializeComponent();
            this.AddHandler(System.Windows.Controls.Validation.ErrorEvent, new RoutedEventHandler(ValidationErrorHandler));
    }
    
    private void ValidationErrorHandler(object sender, RoutedEventArgs e)
    {
        var blah = e as System.Windows.Controls.ValidationErrorEventArgs;
        if (blah.Action == ValidationErrorEventAction.Added)
        {
        }
        else if (blah.Action == ValidationErrorEventAction.Removed)
        {    
        }
    }
    

    Silverlight似乎有一个您也可以订阅的事件,但我在WPF(3.5)中找不到完全等效的事件。感谢您的帮助!

    1 回复  |  直到 13 年前
        1
  •  3
  •   Claudiu Mihaila    15 年前

    我有一个订阅validation.ErrorEvent路由事件的视图的基类

    public class MVVMViewBase : UserControl
        {
            private RoutedEventHandler _errorEventRoutedEventHandler;
            public MVVMViewBase()
            {
                Loaded += (s, e) =>
                    {
                        _errorEventRoutedEventHandler = new RoutedEventHandler(ExceptionValidationErrorHandler);
                        AddHandler(Validation.ErrorEvent, _errorEventRoutedEventHandler);
                    };
    
                Unloaded += (s, e) =>
                    {
                        if (_errorEventRoutedEventHandler != null)
                        {
                            RemoveHandler(Validation.ErrorEvent, _errorEventRoutedEventHandler);
                            _errorEventRoutedEventHandler = null;
                        }
                    };
            }
    
            private void ExceptionValidationErrorHandler(object sender, RoutedEventArgs e)
            {
                ValidationErrorEventArgs args = (ValidationErrorEventArgs) e;
                if (!(args.Error.RuleInError is IUiValidation)) return;
    
                DataErrorInfoViewModelBase viewModelBase = DataContext as DataErrorInfoViewModelBase;
                if(viewModelBase == null) return;
    
                BindingExpression bindingExpression = (BindingExpression) args.Error.BindingInError;
                string dataItemName = bindingExpression.DataItem.ToString();
                string propertyName = bindingExpression.ParentBinding.Path.Path;
    
                e.Handled = true;
                if(args.Action == ValidationErrorEventAction.Removed)
                {
                    viewModelBase.RemoveUIValidationError(new UiValidationError(dataItemName, propertyName, null));
                    return;
                }
    
                string validationErrorText = string.Empty;
                foreach(ValidationError validationError in Validation.GetErrors((DependencyObject) args.OriginalSource))
                {
                    if (validationError.RuleInError is IUiValidation)
                    {
                        validationErrorText = validationError.ErrorContent.ToString();
                    }
                }
                viewModelBase.AddUIValidationError(new UiValidationError(dataItemName, propertyName, validationErrorText));
            }
        }
    

    以及一个viewModel=dataErrorInfoViewModelBase的基类,它由 添加uivalidationError并删除uivalidationError

    另外,我的所有validationRule类都实现了IUivalidation,它只用于将类标记为参与UI错误传播(没有成员)。(可以将属性用于相同的目的)。

    推荐文章