如何在WPF中将数据模型与验证分开?

时间:2015-10-09 06:06:13

标签: c# wpf data-binding solid-principles

我使用下面的代码在WPF中实现Model。但问题在于它违反了Solid Principle [Design Pattern],因为模型和验证代码都在相同的代码中。 帮我把它们分开。

员工模型 -

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
}

基类[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);
}

2 个答案:

答案 0 :(得分:2)

如果你担心S in Solid(单一责任原则),你应该看一下这个答案:https://stackoverflow.com/a/597222/1685167

基本上,“ViewModel的唯一责任是提供查看所需的信息。”就个人而言,我认为你应该关注DataModel如何不了解View而不是其他任何东西。

答案 1 :(得分:1)

这是代码中的一个小例子:

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

说明:

  1. 您有一个EmployeeModel,这是描述员工的真实模型。您的视图(例如,带有用户输入字段的WPF Windows)不了解该模型 - 模型与视图之间没有直接联系。
  2. 视图只知道视图模型。假设这是一个允许您修改员工的掩码,那么我们将使用EmployeesEditViewModel。 ViewModel公开了视图所需的属性,在这个简单的例子中,它只是雇员的名字和valiation结果(可以只显示在另一个文本字段中)。当用户输入值时,您可以检查它是否有效,然后更新实际模型或告诉用户错误。
  3. 理想情况下,您可能在模型本身上有一些验证逻辑,并且ViewModel只将此结果转换为用户可以看到的内容。这将使所有责任(如验证)保留在它所属的模型上,但您仍然拥有可以将其转换并转发到View的ViewModel。