-1

I think my problem is fairly simple to describe - as I use database first approach using EF - I deffinitely don't want to have any extra code in my Model classes because it disappears when updating database in edmx file (and to be independed of EF).

I do not want also to have in my ViewModel a lots of properties which are the same as in the model therfore I always use complex types such as let say Customer

    public partial class Customer
    {

        public int ID{ get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
}

public class AddCustomerViewModel:ViewModelBase
{
        public Customer Customer
        {
            get { return customer; }
            set { customer = value; RaisePropertyChanged(); }
        }
}

How to validate Customer class in ViewModel using IDataErrorInfo and CustomerValidator (FluentValidation Framework) - or in another way using DataAnnotation - without any additional code in Customer model.

Thank you in advance for pointing a way to solve this problem!

1 Answers1

0

You could wrap the model and implement the validation logic in the view model:

public class AddCustomerViewModel : ViewModelBase, INotifyDataErrorInfo
{
    private readonly Dictionary<string, ICollection<string>> _validationErrors 
        = new Dictionary<string, ICollection<string>>();
    private readonly Customer _customer;

    public AddCustomerViewModel(Customer customer)
    {
        _customer = customer;
    }

    [Required(ErrorMessage = "You must enter a name.")]
    public string Name
    {
        get { return _customer.Name; }
        set { _customer.Name = value; ValidateModelProperty(value, nameof(Name)); }
    }

    //+ ID and Address

    private void ValidateModelProperty(object value, string propertyName)
    {
        if (_validationErrors.ContainsKey(propertyName))
            _validationErrors.Remove(propertyName);

        ICollection<ValidationResult> validationResults = new List<ValidationResult>();
        ValidationContext validationContext =
            new ValidationContext(this, null, null) { MemberName = propertyName };
        if (!Validator.TryValidateProperty(value, validationContext, validationResults))
        {
            _validationErrors.Add(propertyName, new List<string>());
            foreach (ValidationResult validationResult in validationResults)
            {
                _validationErrors[propertyName].Add(validationResult.ErrorMessage);
            }
        }
        RaiseErrorsChanged(propertyName);
    }

    #region INotifyDataErrorInfo members
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    private void RaiseErrorsChanged(string propertyName) =>
        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));

    public System.Collections.IEnumerable GetErrors(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName)
            || !_validationErrors.ContainsKey(propertyName))
            return null;

        return _validationErrors[propertyName];
    }

    public bool HasErrors => _validationErrors.Count > 0;
    #endregion

}

By the way, you should prefer INotifyDataErrorInfo over IDataErrorInfo since .NET Framework 4.5.

mm8
  • 163,881
  • 10
  • 57
  • 88