视图模型是否实现了IDataErrorInfo以进行验证?

时间:2013-07-23 14:59:00

标签: wpf validation mvvm idataerrorinfo

我有一个使用MVVM模式的应用程序,我想在用户填写信息时实现验证。

我想使用IDataErrorInfo,但我不知道我的视图模型是否实现了该接口,或者我创建新类是否更好。使用IDataErrorInfo和MVVM模式实现验证的最佳方法是什么?

编辑:我看到在某些例子中,实现是在模型中(它与视图模型不同),但在我的情况下,模型基本上是我创建时从数据库创建的POCO实体带有实体框架的edmx模型,所以我想避免修改这个实体所需要的,因为如果我不需要更新我的模型,我将不得不重新开始工作。

感谢。

4 个答案:

答案 0 :(得分:2)

如果您拥有保存数据的实体或自定义类型(如Person,Student等),则必须在Entity或Customtype中实现IDataErrorInfo。假设您有一个允许输入学生数据的View,并且您拥有ViewModel StudentViewModel,并且此ViewModel具有Student类型的属性Student,其属性(如Name,Age等)绑定到View of Controls。要激活验证和更改以反映在UI上,您必须在学生中不在ViewModel 中实现IDataErrorInfo,并且您还必须在此类中实现 INotifyPropertyChanged 即可。所以我的理解是,如果你的ViewModel中有很少的属性,类型(字符串和值类型)并绑定到View,并且你想对它们应用Validations,那么你必须在ViewModel中实现IDataErrorInfo。如果您有CustomType / Entity,那么您必须在不在ViewModel中的那些类中实现接口。

  

我的理解不是必须在类中实现IDataErrorInfo和INotifyPropertyChanged,如果你想要激活验证,EndProperties(如Name,Age of Student)绑定到View的控件。

    //Interface which has fields of Student class on which ValidationAttribute are to be applied
public interface IStudent
{
    [Required(ErrorMessage = "Name is required")]
    string Name { get; set; }

    [Range(10, 90, ErrorMessage = "Age should be between 10 and 90")]
    int Age { get; set; }
}
//Partial Class to implement IStudent
public partial class Student : IStudent
{

}

//POCO
public partial class Student : INotifyPropertyChanged
{
    private string name;
    private int age;

    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;

            Notify("Name");
        }
    }

    public int Age
    {
        get
        {
            return age;
        }
        set
        {
            age = value;

            Notify("Age");
        }
    }
    private void Notify(string propName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

答案 1 :(得分:2)

将验证逻辑与UI分开始终是个好主意。这样,使用IDataErrorInfo是正确的。

在视图模型和模型之间,我更喜欢在视图模型上实现IDataErrorInfo,因为UI使用此接口。您可以通过直接在测试代码中调用索引器来模拟UI,但如果您真的需要在业务逻辑层中使用验证逻辑,那么这样的调用没有多大意义。

在我们的项目中,验证是一个更独立的组件,可以通过配置由表示层和业务逻辑层使用。从视图模型的角度来看,它非常薄,只包含一个调用并在索引器中构建验证结果。

另外,另一个考虑因素是由.Net 4.5和Silverlight提供的INotifyDataErrorInfo。它提供了来自一个属性的更多验证结果和用于耗时验证的异步验证,这是我们计划更新到.Net 4.5之后的预期。

希望它可以帮到你。

答案 2 :(得分:2)

我同意绝大多数有关此主题的评论,但我正在回答为此界面提供“升级”。

我在IDataErrorInfo界面看到的问题是它一次只能解决一个错误。因此,我在BaseDataType类中添加了一个额外的字段(所有数据类型的基类):

protected ObservableCollection<string> errors = new ObservableCollection<string>();

然后我添加了以下属性:

// this just enables me to add into the error collection from outside this class
public ObservableCollection<string> ExternalErrors
{
    get { return externalErrors; }
}

public override ObservableCollection<string> Errors
{
    get
    {
        errors = new ObservableCollection<string>();
        // add properties to validate
        errors.AddUniqueIfNotEmpty(this["Property1ToValidate"]);
        errors.AddUniqueIfNotEmpty(this["Property2ToValidate"]);
        errors.AddUniqueIfNotEmpty(this["Property3ToValidate"]);
        // add external errors (from view models)
        errors.AddRange(ExternalErrors);
        return errors;
    }
}

public virtual bool HasError
{
    get { return Errors != null && Errors.Count > 0; }
}

AddUniqueIfNotEmpty方法是一种扩展方法,我相信你们都可以猜到它的作用。

使用它,我可以直接绑定到视图中的错误集合,甚至更好,使用HasError绑定到BoolToVisibilityConverter属性,以隐藏显示错误的控件收集是空的。

答案 3 :(得分:1)

<TextBox Text="{Binding Path=MyCoolProperty, ValidationOnDataErrors=true}"

也许我会错过一些东西,但是如果你有这样的绑定 - 你的“MyCoolProperty”类必须实现INotifyPropertyChanges和IDataErrorInfo - 否则它将不起作用。

所以我想问的问题不是:“应该实现IDataErrorInfo”但是也许如何实现IDataErrorInfo