通知 ViewModel ValidatesOnExceptions 输入错误

发布于 2024-09-27 15:47:24 字数 1569 浏览 0 评论 0原文

在我的应用程序中,我有绑定到文本框的数字(双精度或整数)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 的实现这里,但当将此代码放入视图的代码隐藏文件中时,我似乎无法捕获我期望的路由事件:

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) 中找不到完全相同的事件。任何帮助表示赞赏!

In my application I have numerical (double or int) ViewModel properties that are bound to TextBoxes. The ViewModel implements IDataErrorInfo to check if the values entered fall within acceptable ranges for the 'business logic' (e.g. height can't be a negative value). I have a number of TextBoxes per page and have a button (think 'next' in a wizard) thats enabled property is bound to a ViewModel boolean that specifies whether there are any errors on the page as a whole. The enable/disable state of the button is properly updated with valid/invalid values according to the IDataErrorInfo rules I've written.

However, there is no way to let my viewmodel know when an exception has been thrown because an input value does not convert (i.e. "12bd39" is not a valid double) and as a result in the case of conversion exceptions my 'next' button will remain enabled despite bad input. The GUI however properly reflects the error with an adorner because of my binding:

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

How can I let the view know that a 'ValidatesOnExceptions' style error has occured. Josh Smith's take here seems to rely on making every ViewModel property a string and rolling your own exception checking which seems like a lot of additional work. I additionally began looking into Karl Shifflett's implementation here, but I cannot seem to capture the routed event I would expect when putting this code into the view's codebehind file:

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 appears to have an event that you can subscribe too, but I cannot find the exact equivalent in WPF (3.5). Any help is appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

做个ˇ局外人 2024-10-04 15:47:24

我有一个订阅 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));
        }
    }

和一个 ViewModel = DataErrorInfoViewModelBase 的基类,由
AddUIValidationError 和 RemoveUIValidationError

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

I have a base class for the View that subscribes to Validation.ErrorEvent routed event

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

and a base class for the ViewModel = DataErrorInfoViewModelBase that is informed by
AddUIValidationError and RemoveUIValidationError

Also all my ValidationRule classes implement IUiValidation which is used just to mark the class as taking part of the UI errors propagation(no members). (you can use an attribute for the same purpose).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文