【问题标题】:Data Annotations, IDataErrorInfo and MVVM数据注释、IDataErrorInfo 和 MVVM
【发布时间】:2014-04-17 04:40:03
【问题描述】:

我正在尝试寻找在 MVVM 中验证数据的最佳方法。 目前,我正在尝试使用 MVVM 模式将 IDataErrorInfo 与数据注释一起使用。

但是,似乎没有任何效果,我不确定我做错了什么。我有这样的东西。

型号

public class Person : IDataErrorInfo
{
    [Required(ErrorMessage="Please enter your name")]
    public string Name { get; set; }

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    string IDataErrorInfo.this[string propertyName]
    {
        get
        {
            return OnValidate(propertyName);
        }
    }

    protected virtual string OnValidate(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName))
            throw new ArgumentException("Property may not be null or empty", propertyName);

        string error = string.Empty;

        var value = this.GetType().GetProperty(propertyName).GetValue(this, null);
        var results = new List<ValidationResult>();

        var context = new ValidationContext(this, null, null) { MemberName = propertyName };

        var result = Validator.TryValidateProperty(value, context, results);

        if(!result)
        {
            var validationResult = results.First();
            error = validationResult.ErrorMessage;
        }
        return error;
    }
}

模型代码由How to catch DataAnnotations Validation in MVVM 的解决方案提供(很遗憾,这个答案不符合我的标准。)

视图模型

public class PersonViewModel
{
    private Person _person;

    public string Name
    {
        get
        {
            return _person.Name
        }
        set
        {
            _person.Name = value;
        }
    }
}


查看

<Label Content="Name:" />

<TextBox Text="{Binding UpdateSourceTrigger=LostFocus,
                        Path=Name,
                        ValidatesOnDataErrors=True,
                        NotifyOnValidationError=true}" />


有什么方法可以保持模型、视图和视图模型之间的分离,同时仍然使用数据注释进行 IDataErrorInfo 验证?

【问题讨论】:

    标签: c# wpf validation mvvm data-annotations


    【解决方案1】:

    要保持验证运行,IDataErrorInfo 必须由数据上下文实现,该属性绑定到控件。所以,它应该是这样的:

    public class PersonViewModel : IDataErrorInfo 
    {
        [Required(AllowEmptyStrings = false)]
        public string Name
        {
            get
            {
                 return _person.Name
            }
            set
            {
                 _person.Name = value;
            }
        }    
    
        public string Error
        {
            get { throw new NotImplementedException(); }
        }
    
        string IDataErrorInfo.this[string propertyName]
        {
            get
            {
                return OnValidate(propertyName);
            }
        }
    
        protected virtual string OnValidate(string propertyName)
        {
            /* ... */
        }
    }
    

    没有必要在模型中实现IDataErrorInfo,这是视图模型的责任。通常,IDataErrorInfo 由视图模型的基类实现。

    顺便问一下,为什么OnValidate 受到保护?您如何想象重写此方法?

    【讨论】:

    • 我在模型而不是视图模型中有数据注释的原因是因为我也在使用实体框架来创建我的数据库。实体框架查看模型中的数据注释来设置每个列的属性。 [必需] == NotNull 例如。有什么方法可以将其保留在模型中而不是视图模型中?
    • 这就是为什么我不喜欢 EF 的数据注释方法。它非常适合 MVC,但对于 MVVM,它的行为非常令人困惑……如果您仍想为 EF 使用数据注释,您有两种方法:在视图模型中克隆数据注释,或直接绑定到模型的属性。两种方式对我来说都很有味道(尽管直接与模特签约通常很方便)。
    【解决方案2】:

    将您在 XAML notifyonvalidation error 和 validatesondata errors 中的定义设置为 true。并且在 VM 中使用简单的 Viewmodel,它对所需属性的 setter 函数进行了验证,如果验证失败,它应该抛出验证错误,并且 xaml 会知道它是无效的。

    public class PersonViewModel
    {
        private Person _person;
    
        public string Name
        {
            get
            {
                return _person.Name
            }
            set
            {
                if(value == string.empty)
                   throw new ValidationException("Name cannot be empty");
                _person.Name = value;
            }
        }
    }
    

    现在您需要在 xaml 中处理此问题并显示异常中的错误文本

    【讨论】:

    • WPF 允许通过多种方式验证数据。 OP 询问其中一个,这不是基于异常的验证。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多