Search code examples
c#wpfdata-bindingsolid-principles

How to separate data model from validations in WPF?


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

Solution

  • 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.