需要从 ValidationBaseClass 公开 HasError 属性以查看具有流畅验证的模型

问题描述

希望大家都平安。

我需要帮助实现 INotifyDataErrorInfo 接口,并将 SfTextBoxEx 放置在 SfTextInputLayout 中。

WPF 和 MVVM 使用 Caliburn.Micro 框架。

请找到以下项目结构以通过问题来理解。

1) 文件名称:基础设施 文件:ValidatedPropertyChangedBase.cs

--它包含 INotifyDataErrorInfo 的实现。

2) 文件名称:型号 文件:TestModel.cs -- 包含两个继承自 ValidatedPropertyChangedBase 的属性 -- 还包含使用 FluentValidation 验证属性的类

4) 文件名称:查看 文件:HomeView.xaml --带有两个SfTextInputLayout和SfTextBoxExt的标准窗口

4) 文件名称:视图模型 文件:Homeviewmodel.cs -- 标准视图模型,模型作为属性,带有验证触发。 -- 在这里,如果我在验证方法上放置断点,我可以看到返回的错误是正确的,但不知何故它不会触发 UI 以显示错误消息。 -- 我已经在将属性与文本框绑定时设置了 ValidatesOnNotifyDataError=true。

如果有什么问题,请检查并指导我。 注意:我使用的是同步融合控件,但我也尝试使用标准文本框,它不会触发 errorchanged 事件。

我还使用了 IntoifyDataError 实现:https://www.thetechgrandma.com/2017/05/wpf-prism-inotifydataerrorinfo-and.html

--ValidatedPropertyChangedBase

public abstract class ValidatedPropertyChangedBase : PropertyChangedBase,INotifyDataErrorInfo
{
    private readonly Dictionary<string,List<string>> _errors = new Dictionary<string,List<string>>();

    


    public void SetError(string propertyName,string errorMessage)
    {
        if (!_errors.ContainsKey(propertyName))
            _errors.Add(propertyName,new List<string> { errorMessage });

        raiseerrorsChanged(propertyName);
    }

    protected void ClearError(string propertyName)
    {
        if (_errors.ContainsKey(propertyName))
            _errors.Remove(propertyName);

        raiseerrorsChanged(propertyName);
    }

    protected void ClearallErrors()
    {
        var errors = _errors.Select(error => error.Key).ToList();

        foreach (var propertyName in errors)
            ClearError(propertyName);
    }
    public void raiseerrorsChanged(string propertyName)
    {
        ErrorsChanged(this,new DataErrorsChangedEventArgs(propertyName));
    }

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged = delegate { return; };


    public bool HasErrors
    {
        get { return _errors.Any(x => x.Value != null && x.Value.Count > 0); }
    }
    public IEnumerable GetErrors(string propertyName)
    {
        if (String.IsNullOrEmpty(propertyName) ||
           !_errors.ContainsKey(propertyName)) return null;
        return _errors[propertyName];
    }

}

--视图模型

public class Homeviewmodel : ValidatedPropertyChangedBase
{

    private TestModel _model;
    public TestModel Model
    {
        get { return _model; }
        set
        {
            if (_model != value)
            {
                _model = value;
                NotifyOfPropertyChange(() => Model);
            }
        }
    }

    public Homeviewmodel()
    {
        Model = new TestModel();
    }

    public void ValidateData()
    {
        ClearallErrors();
        var validator = new TestModelValidation();
        FluentValidation.Results.ValidationResult result = validator.Validate(Model);
        foreach (var error in result.Errors)
        {
            SetError(error.PropertyName,error.ErrorMessage);
        }

        if (result.IsValid)
        {
            MessageBox.Show("Data good to save !");
        }

    }
}

--查看

<Window
x:Class="ValidationDemo.Views.HomeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:convertor="clr-namespace:ValidationDemo.Infrastructure"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ValidationDemo.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sf="http://schemas.syncfusion.com/wpf"
Title="HomeView"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.Resources>
    <Style
        targettype="sf:SfTextInputLayout">
        <Setter Property="Width" Value="200" />
    </Style>
</Window.Resources>
<StackPanel
    HorizontalAlignment="Center"
    VerticalAlignment="Center"
    Orientation="Vertical">
    <sf:SfTextInputLayout
        Hint="First Name">
        <sf:SfTextBoxExt
            Text="{Binding Path=Model.FirstName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,ValidatesOnNotifyDataErrors=True}" />
    </sf:SfTextInputLayout>
    <sf:SfTextInputLayout
        Hint="Last Name">
        <sf:SfTextBoxExt
            Text="{Binding Path=Model.FirstName,ValidatesOnNotifyDataErrors=True}" />
    </sf:SfTextInputLayout>
    <TextBox
            Text="{Binding Path=Model.FirstName,ValidatesOnNotifyDataErrors=True}" />
    <TextBox
            Text="{Binding Path=Model.FirstName,ValidatesOnNotifyDataErrors=True}" />
    <Button
        x:Name="ValidateData"
        Content="Validate Data" />
</StackPanel>

--实现了 Fluent 验证的模型:

public class TestModel : ValidatedPropertyChangedBase
{

    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (_firstName != value)
            {
                _firstName = value;
                NotifyOfPropertyChange(() => FirstName);
            }
        }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set
        {
            if (_lastName != value)
            {
                _lastName = value;
                NotifyOfPropertyChange(() => LastName);
            }
        }
    }
}

public class TestModelValidation:AbstractValidator<TestModel>
{
    public TestModelValidation()
    {
        RuleFor(t => t.FirstName)
            .NotEmpty()
            .WithMessage("Please enter first name");

        RuleFor(t => t.FirstName)
            .NotEmpty()
            .WithMessage("Please enter last name");
    }
}

解决方法

能够找出问题所在,是通过控件从视图模型中公开 HasError。

ErrorText="{Binding RelativeSource={RelativeSource Mode=Self},Path=InputView.(Validation.Errors),Converter={StaticResource EC}}"
        HasError="{Binding RelativeSource={RelativeSource Mode=Self},Converter={StaticResource ECO}}"

在带有转换器的控件上添加了属性并解决了问题。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...