0

I used the below code for implementing Model in WPF. But the Problem is that it violates Solid Principle [Design Pattern] because model and validation code both are in the same code. Help me out to separate them.

Employee Model-

public class EmployeeModel : Model
{
    #region Fields
    private int employeeId;
    private string employeeCode;
    private string firstName;
    private string lastName;
    private DateTime? dateOfJoining;
    private DateTime dob;
    private string email;
    private int? departmentId;
    private string departmentName;
    private string password;
    private string role;
    #endregion

    #region Public Properties
    public int EmployeeId
    {
        get
        {
            return employeeId;
        }
        set
        {
            if (value != this.employeeId)
            {
                employeeId = value;
                SetPropertyChanged("EmployeeId");
            }
        }
    }
    public string EmployeeCode
    {
        get
        {
            return employeeCode;
        }
        set
        {
            if (value != this.employeeCode)
            {
                employeeCode = value;
                SetPropertyChanged("EmployeeCode");
            }
        }
    }
    public DateTime? DateOfJoining
    {
        get
        {
            return dateOfJoining;
        }
        set
        {
            if (value != this.dateOfJoining)
            {
                dateOfJoining = Convert.ToDateTime(value);
                SetPropertyChanged("DateofJoining");
            }
        }
    }
    public string FirstName
    {
        get
        {
            return firstName;
        }
        set
        {
            if (value != this.firstName)
            {
                firstName = value;
                SetPropertyChanged("FirstName");
            }
        }
    }
    public string LastName
    {
        get
        {
            return lastName;
        }
        set
        {
            if (value != this.lastName)
            {
                lastName = value;
                SetPropertyChanged("LastName");
            }
        }
    }
    public string FullName
    {
        get
        {
            return string.Join(" ", new[] { firstName, lastName });
        }
    }
    public int? DepartmentId
    {
        get
        {
            return departmentId;
        }
        set
        {
            if (value != this.departmentId)
            {
                departmentId = value;
                SetPropertyChanged("DepartmentId");
            }
        }
    }
    public string DepartmentName
    {
        get
        {
            return departmentName;
        }
        set
        {
            if (value != this.departmentName)
            {
                departmentName = value;
                SetPropertyChanged("DepartmentName");
            }
        }
    }
    public DateTime DOB
    {
        get
        {
            return dob;
        }
        set
        {
            if (value != this.dob)
            {
                dob = Convert.ToDateTime(value);
                SetPropertyChanged("DateofBirth");
            }
        }
    }
    public string Email
    {
        get
        {
            return email;
        }
        set
        {
            if (value != this.email)
            {
                email = value;
                SetPropertyChanged("Email");
            }
        }
    }
    public string Password
    {
        get
        {
            return password;
        }
        set
        {
            if (value != this.password)
            {
                password = value;
                SetPropertyChanged("Password");
            }
        }
    }
    public string Role
    {
        get
        {
            return role;
        }
        set
        {
            if (value != this.role)
            {
                role = value;
                SetPropertyChanged("Role");
            }
        }
    }
    #endregion

    #region Private Methods
    private bool IsValid(string emailaddress)
    {
        try
        {
            MailAddress m = new MailAddress(emailaddress);

            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }
    #endregion

    #region Public Methods
    public override string GetErrorForProperty(string propertyName)
    {
        string retErrorMsg = string.Empty;
        switch (propertyName)
        {
            case "EmployeeCode":
                if (EmployeeCode == null || EmployeeCode.Length < 2)
                {
                    retErrorMsg = AppConstants.EmpCodeError;
                }
                break;
            case "FirstName":
                if (FirstName == null || FirstName == string.Empty)
                {
                    retErrorMsg = AppConstants.FNameError;
                }
                break;
            case "LastName":
                if (LastName == null || LastName == string.Empty)
                {
                    retErrorMsg = AppConstants.LNameError;
                }
                break;

            case "DepartmentId":
                if (DepartmentId == null || DepartmentId < 1)
                {
                    retErrorMsg = AppConstants.DepartmentError;
                }
                break;
            case "DOB":
                if (DOB.AddYears(60).Date < DateTime.Now.Date || DOB.AddYears(18).Date > DateTime.Now.Date)
                {
                    retErrorMsg = AppConstants.DOBError;
                }
                break;
            case "DateOfJoining":
                if (DateOfJoining == null || DateOfJoining > DateTime.Now)
                {
                    retErrorMsg = AppConstants.DOJError;
                }
                break;

            case "Role":
                if (!(Role == "A" || Role == "U"))
                {
                    retErrorMsg = AppConstants.RoleError;
                }
                break;

            case "Email":
                if (!IsValid(Email))
                {
                    retErrorMsg = AppConstants.EmailError;
                }
                break;
            case "Password":
                if ((Password == null || Password.Length < 8))
                {
                    retErrorMsg = AppConstants.PasswordError;
                }
                break;
        }
        return retErrorMsg;
    }
    #endregion
}

Base Class[Model.cs]

public abstract class Model : INotifyPropertyChanged, IDataErrorInfo
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void SetPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public string Error
    {
        get { return string.Empty; }
    }
    public string this[string propertyName]
    {
        get
        {
                return GetErrorForProperty(propertyName);
        }
    }
    public abstract string GetErrorForProperty(string propertyName);
}
Ashok Rayal
  • 405
  • 3
  • 16
  • 1
    When using MVVM, you put a ViewModel between your Model and your View. Validation code would then be put into the ViewModel. For example, on entering input in the UI, you would check it in your ViewModel and if it's invalid, you could show an error to the user and not propagate the value to the model. – GeorgDangl Oct 09 '15 at 06:18
  • Can you explain with Code? Because I am using Binding and if data has any error it shows error at the binding time. – Ashok Rayal Oct 09 '15 at 06:45

2 Answers2

2

If you're worried about the S in Solid (Single Responsibility Principle), you should take a look at this answer: https://stackoverflow.com/a/597222/1685167

Basically, "The ViewModel single responsibility is to provide the View the information it needs." Personally I think you should be concerned with how the DataModel is unaware of the View more than anything else.

Community
  • 1
  • 1
Tyress
  • 3,573
  • 2
  • 22
  • 45
1

Here's a small example in code:

public class EmployeesEditViewModel : INotifyPropertyChanged
{
    public string UserInputNewName
    {
        get
        {
            return Model.EmployeName;
        }
        set
        {
            if (ValidateValue(value))
            {
                Model.EmployeName = value;
                ValidationResult = string.Empty;
                OnPropertyChanged("UserInputNewName");
            }
            else
            {
                ValidationResult = "Error, name must not be empty.";
            }
        }
    }

    private bool ValidateValue(string value)
    {
        return !string.IsNullOrWhiteSpace(value);
    }

    private string _ValidationResult;

    public string ValidationResult
    {
        get
        {
            return _ValidationResult ?? string.Empty;
        }
        set
        {
            _ValidationResult = value;
            OnPropertyChanged("ValidationResult");
        }
    }

    private EmployeeModel Model { get; set; }
}

public class EmployeeModel
{
    public int EmployeeId { get; set; }

    public string EmployeName { get; set; }
}

Explanation:

  1. You have an EmployeeModel, this is the real model that describes an employee. Your view (for example a WPF Windows with user input fields) does not know about the model - there's no direct contact between model an view.
  2. The view only knows about a view model. Suppose this is a mask that allows you to modify employees, then we'll use the EmployeesEditViewModel for that. The ViewModel exposes the properties needed for the view, in this simple case it's just the name of the employee and a valiation result (which could be just displayed in another text field). When the user enters a value, you can check if it's valid and then either update the actual model or tell the user what's wrong.

Ideally, you would probably have some validation logic on the model itself and have the ViewModel only transform this result into something that the user can see. This would keep all the responsibility (like validation) on the model where it belongs, but you'd still have a ViewModel that can translate and forward this to the View.

GeorgDangl
  • 2,146
  • 1
  • 29
  • 37