5

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

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

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

如何让视图知道发生了“ValidatesOnExceptions”样式错误。Josh Smith 的做法似乎依赖于将每个 ViewModel 属性设为字符串并滚动您自己的异常检查,这似乎需要做很多额外的工作。我还开始研究 Karl Shifflett 的实现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) 中找不到确切的等价物。任何帮助表示赞赏!

4

1 回答 1

3

我有一个订阅 Validation.ErrorEvent 路由事件的 View 的基类

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

以及由 AddUIValidationError 和 RemoveUIValidationError 通知的 ViewModel = DataErrorInfoViewModelBase 的基类

此外,我所有的 ValidationRule 类都实现了 IUiValidation,它仅用于将类标记为参与 UI 错误传播(无成员)。(您可以将属性用于相同目的)。

于 2010-10-18T21:47:57.707 回答