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

4

7

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.

Overrefinement answered 23/7, 2013 at 14:58 Comment(2)
I'd say it is very much a good idea for the VM to implement IDataErrorInfo. That interface pretty much "assists" with passing information to the User(View) for background errors(Errors in Data). that's exactly what the VM is for and it'd be perfectly valid to have it there. Comments in this answer and the one below it argue with having it in the Model. Having it defined in another class is than the Model and the VM wouldn't be "wrong" either for abstraction but might just not be worth it.Sitter
..cont'd. If what you're checking for with the IDataErrorInfo is such complicated logic that you'd want to re-use it, then I'd literally move those functional checks into a service and then have the VM implement the interface and in the VM use the service to access the complicated validation logic. That way you got your code-reuse and sharing and also stay clean and simple with each VM just implementing the IDataErrorInfo themselvesSitter
T
2

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.

Thusly answered 23/7, 2013 at 15:42 Comment(0)
P
2

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;
}
Pandorapandour answered 23/7, 2013 at 15:39 Comment(5)
I understand the idea. Then how could I implement validation in my POCO entities? this are generated by T4 template from my edmx model that is created from my database. If I update my database and I need to create again the entities, I lost all changes (validation in this case). Is there any way to implement the validation in the entities that are generated from the dataBase?Midwife
Are you using Attribute based Validations?Pandorapandour
By the mnoment I don't use any kind of validation, I am trying to decide the best option.Midwife
It is not easy work to apply Validations on POCO's that are generated using T4 template. I also had same kind of problem few months back .I solved that problem like the code i updated to answer but using this way you will have to create ValidationAttributes.Pandorapandour
I created POCO as partial and then Created a Partial class to thatPOCO and created Interface that has the fields of POCO on which Validations are to be applied and applied Attribute on these interface members . I hope you got my idea.Pandorapandour
T
2

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.

Thusly answered 23/7, 2013 at 15:42 Comment(0)
A
2

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.

Astute answered 23/7, 2013 at 16:32 Comment(0)
F
1
<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

Firry answered 25/7, 2013 at 5:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.