Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it a good idea that the view model implements the IDataErrorInfo for validation?

i have an application that use the MVVM pattern and I would like to implement validation when the user is fill the information.

I would like to use the IDataErrorInfo, but I don't know if it is a good idea that my view model implements that interface or if it is better that I create a new class. How is the best way to imlpement validantion with IDataErrorInfo and the MVVM pattern?

EDIT: I see that in some examples the implementation is in the model (it is not the same than the view model), but in my case the model basically is the POCO entities that I create from my database when I create my edmx model with entity framework, so I would like to avoid the needed to modify this entities because if I need no update my model, I would have to do the work again.

Thanks.

like image 769
Álvaro García Avatar asked Jul 23 '13 14:07

Álvaro García


4 Answers

It is always a good idea to separate validation logic from UI. In this way, using IDataErrorInfo is correct.

Between view model and model, I prefer implementing IDataErrorInfo on view model since this interface is used by UI. You can simulate UI by calling indexers directly in your test code but if you really need validation logic in your business logic layer, such a call does not make much sense.

In our project, validation is an more independent component, which can be used by both presentation layer and business logic layer by configuration. From view model's perspective, it is very thin, containing only a call and constructing validation result inside indexer.

Also, another consideration is INotifyDataErrorInfo, which provided by .Net 4.5 and Silverlight. It provides more validation results from one property and asynchronous validation for a time consuming validation, which is what we want after we planned to update to .Net 4.5.

Hope it can help you.

like image 173
Bill Zhang Avatar answered Nov 07 '22 16:11

Bill Zhang


I would agree with the vast majority of comments on this subject, but am answering to offer my 'upgrade' to this interface.

The problem that I see with the IDataErrorInfo interface is that it only addresses one error at a time. Therefore, I added an extra field in my BaseDataType class (base class for all of my data types):

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

I then added the following properties:

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

The AddUniqueIfNotEmpty method is an extension method and I'm sure you can all guess what it does.

Using this, I can bind directly to the collection of errors in the views and even better, bind to the HasError property using a BoolToVisibilityConverter in order to hide the control that displays the errors when the collection is empty.

like image 44
Sheridan Avatar answered Nov 07 '22 17:11

Sheridan


If you have an Entity or Custom Type (like Person,Student etc) that holds the data then it is must that you implement IDataErrorInfo in your Entity or Customtype. Suppose you have a View that allows to enter Student data and you have its ViewModel StudentViewModel and this ViewModel has property Student of type Student whose property (like Name,Age etc) are binded to Controls of View. For Validations to fire and changes to reflect on UI you must implement IDataErrorInfo in this Student class not in your ViewModel and also you will have to implement INotifyPropertyChanged in this class. So my understanding is if you have few Properties in your ViewModel, that are of type (string and ValueTypes) and are binded to View and you want to apply Validations on them then you must Implement IDataErrorInfo in you ViewModel. And if you have CustomType /Entity then you must implement interface in those classes not in ViewModel .

Its not my understanding it is must to implement IDataErrorInfo and INotifyPropertyChanged in the class whose EndProperties(like Name,Age of Student ) are binded to View's Controls if you want Validations to fire.

    //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;
}
like image 2
yo chauhan Avatar answered Nov 07 '22 16:11

yo chauhan


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

maybe i miss something, but if you have bindings like this - your class with the "MyCoolProperty" have to implement INotifyPropertyChanges AND IDataErrorInfo - otherwise it would not work.

so i would say the question is not: "should implement IDataErrorInfo" but maybe how to implement IDataErrorInfo

like image 1
blindmeis Avatar answered Nov 07 '22 16:11

blindmeis