如何在ViewModel中获取ValidationResult方法的结果?(对/错)

How to get the result of a ValidationResult method, inside ViewModel? (True / False)

提问人:aca 提问时间:2/24/2023 最后编辑:EldHaspaca 更新时间:2/25/2023 访问量:153

问:

我有一个这样的(部分)文件XAML

                                <TextBox.Text>
                                    <Binding Path="MyProperty"
                                             UpdateSourceTrigger="PropertyChanged"
                                             TargetNullValue="">
                                        <Binding.ValidationRules>
                                            <validation:IntRangeRule Min="-999"
                                                                     Max="999" />
                                        </Binding.ValidationRules>
                                    </Binding>
                                </TextBox.Text>

像这样的班级IntRangeRule

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (value != null)
        {
            var stringToConvert = value as string;

            if (!string.IsNullOrEmpty(stringToConvert))
            {
                Int32 number;

                bool result = Int32.TryParse(stringToConvert, NumberStyles.Integer, cultureInfo, out number);
                if (!result)
                {
                    var localizer = ServiceLocator.Current.GetInstance<IResourceLocalizer>();
                    return new ValidationResult(false, string.Format(localizer["IntValidationError"], stringToConvert, Min, Max));
                }

                if ((number < Min) || (number > Max))
                {
                    var localizer = ServiceLocator.Current.GetInstance<IResourceLocalizer>();
                    return new ValidationResult(false, string.Format(localizer["IntRangeValidationError"], Min, Max));
                }
            }
        }

        return new ValidationResult(true, 0);
    }

由于我意识到当具有第一个参数时,它不会更改属性。ValidationResultfalseMyProperty

因此,我的目标是以某种方式在 ViewModel 中确认是真是假,这样我就可以在我的语句中使用这些信息。到目前为止,我找不到如何做到这一点。ValidationResultif

C# WPF 验证 MVVM

评论

0赞 EldHasp 2/24/2023
是否需要让 ViewModel 知道 TextBox 中是否存在任何验证错误?或者你只对验证器的错误感兴趣,其余的错误应该被忽略?
0赞 aca 2/24/2023
TBH 我不太确定你在问什么,但我会尽量解释。我需要知道我的 TextBox 中何时出现错误(在 UI 上可见),但我需要在 ViewModel 中提供相同的信息,以便在 TextBox 中有无效输入时阻止用户按下按钮。
1赞 BionicCode 2/24/2023
如果不引用控件即可获取实际的 Binding 对象。不建议这样做,因为它会带来几个问题。相反,应实现属性验证(而不是绑定验证)。这很简单。为此,可以在数据源/绑定源(在本例中为视图模型类)上实现 INotifyDataErrorInfo 接口(INotifyPrope4rtyChanged 的常见伴侣)。这样,您的视图模型就可以完全控制验证。这是 MVVM 环境中推荐的验证模式。
0赞 EldHasp 2/24/2023
验证错误状态由整个 UI 元素共享(在一般情况下,由 DependencyObject 共享)。例如,可以在一个绑定中定义多个验证程序,也可以为多个属性定义验证程序绑定。任何验证器中的错误都会为整个 UI 元素设置错误状态。你需要这个条件吗?这个任务相对容易解决。或者是否需要筛选出所有其他验证错误,并仅将“IntRangeRule”验证程序的结果传递给 ViewModel?这是一个已经很难解决的问题。
0赞 XAMlMAX 2/25/2023
是的,您已经确定了验证规则存在的原因。它的存在是为了阻止无效结果进一步发展。如果它允许它通过,那么就不需要它,因为您可以在 VM 中做同样的事情。那么,if 语句在 VM 中的样子如何?

答:

-1赞 Andy 2/24/2023 #1

像这样的验证器在存在 validation.error 时会引发一个路由事件,而在修复时会引发另一个路由事件。正如您所注意到的,没有将数据从视图传输到视图模型。

有一个路由事件引发,您可以在父级中处理该事件。比如说,在网格中或在用户控制级别。

显然,您需要一种方法来告诉视图模型是否存在错误。

在处理事件的父级中,可以设置一个依赖项属性,该属性绑定到视图模型中的属性。

这是一些旨在为您提供想法的旧代码。它可能不会剪切和粘贴,因为它很旧。

在父网格或用户控件中,或者可以通过将此类内容放在 contentcontrol 的模板中来使其更易于重用。然后将 ui 放在该控件中。

下面使用命令。

<Grid>
    <i:Interaction.Triggers>
        <UIlib:RoutedEventTrigger RoutedEvent="{x:Static Validation.ErrorEvent}">
            <e2c:EventToCommand
                 Command="{Binding ConversionErrorCommand, Mode=OneWay}"
                 EventArgsConverter="{StaticResource BindingErrorEventArgsConverter}"
                 PassEventArgsToCommand="True" />

命令的事件来自 mvvm light。我提到不是剪切和粘贴解决方案。

转炉

public class BindingErrorEventArgsConverter : IEventArgsConverter
{
    public object Convert(object value, object parameter)
    {
        ValidationErrorEventArgs e = (ValidationErrorEventArgs)value;
        PropertyError err = new PropertyError();
        err.PropertyName = ((System.Windows.Data.BindingExpression)(e.Error.BindingInError)).ResolvedSourcePropertyName;
        err.Error = e.Error.ErrorContent.ToString();
        // Validation.ErrorEvent fires both when an error is added AND removed
        if (e.Action == ValidationErrorEventAction.Added)
        {
            err.Added = true;
        }
        else
        {
            err.Added = false;
        }
        return err;
    }
}

请注意在添加错误和删除错误时如何命中它。

路由事件触发器。

// This is necessary in order to grab the bubbling routed source changed and conversion errors
public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
{
    RoutedEvent routedEvent;
    public RoutedEvent RoutedEvent
    {
        get
        {
            return routedEvent;
        }
        set
        {
            routedEvent = value;
        }
    }

    public RoutedEventTrigger()
    {
    }
    protected override void OnAttached()
    {
        Behavior behavior = base.AssociatedObject as Behavior;
        FrameworkElement associatedElement = base.AssociatedObject as FrameworkElement;
        if (behavior != null)
        {
            associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
        }
        if (associatedElement == null)
        {
            throw new ArgumentException("This only works with framework elements");
        }
        if (RoutedEvent != null)
        {
            associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(this.OnRoutedEvent));
        }
    }
    void OnRoutedEvent(object sender, RoutedEventArgs args)
    {
        base.OnEvent(args);
        args.Handled = true;
    }
    protected override string GetEventName()
    {
        return RoutedEvent.Name;
    }
}