将验证传递给DelegateCommand

时间:2017-07-11 20:47:22

标签: c# wpf mvvm

我有DelegateCommand看起来像这样:

public class DelegateCommand : ICommand
{
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<object> execute)
        : this(execute, null)
    {   
    }

    public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

我有一个允许用户注册到数据库的进程。但是,我需要添加一些验证,例如,用户名是否已经存在,密码是否匹配规则等。这是注册命令:

#region RegisterCommand

private DelegateCommand _registerCommand;
public ICommand RegisterCommand
{
    get
    {
        _registerCommand = new DelegateCommand(param => Register());
        return _registerCommand;
    }
}

private bool CanRegister()
{
    return true;
}

private void Register()
{
    var newUser = new User
    {
        FirstName = _firstname,
        LastName = _lastname,
        Username = _username,
        Password = "", // TODO: Hashing and storing of passwords
    };
    using (var context = new WorkstreamContext())
    {
        var users = context.Set<User>();
        users.Add(newUser);
        context.SaveChanges();
    }
}

#endregion

正如您所看到的,我有一个名为CanRegister()的方法,我想用它来过滤注册过程。我的问题是,如何在调用中实现CanRegister()

_registerCommand = new DelegateCommand(param => Register());

如果CanRegister返回false,

会提示或拒绝该过程?

1 个答案:

答案 0 :(得分:0)

通常的方法是禁用命令按钮,直到满足所有验证条件。在您的情况下,如果您有两个验证规则(用户名不存在,密码匹配规则),我会执行以下操作:

  1. 在用户输入用户名时检查用户名是否存在。显然,您不希望在每次击键后都触发数据库调用,因此请使用绑定中的“延迟”选项。在ViewModel中设置一个属性以反映结果,例如IsUserNameUnique。设置此属性时,请在DelegateCommand上调用RaiseCanExecuteChanged方法。

  2. 使用IsStrongPassword重复此过程以获取密码。

  3. 将DelegateCommand挂钩到其构造函数中的CanRegister方法中。这将禁用该命令,直到CanRegister返回true。

  4. 将CanRegister命令更改为仅在IsStrongPassword和IsUserNameUnique都为真时返回true。

  5. 延迟绑定:

    <TextBox Text="{Binding UserName, Delay=500, UpdateSourceTrigger=PropertyChanged}" />
    

    视图模型

    #region RegisterCommand
    
    private DelegateCommand _registerCommand;
    public ICommand RegisterCommand
    {
        get
        {
            _registerCommand = new DelegateCommand(param => Register(), () => CanRegister());
            return _registerCommand;
        }
    }
    
    private bool CanRegister()
    {
        return _isUserNameUnique && _isStrongPassword;
    }
    
    public string UserName
    {
     get {return _userName;}
     set
     {
      _userName = value;
      OnUserNameChanged();
     }
    }
    
    public string Password
    {
     get {return _password;}
     set {_password = value; OnPasswordChanged();
    }
    
    private void OnUserNameChanged()
    {
      _isUserNameUnique = VerifyUserNameIsUnique(_userName);
      _registerCommand.RaiseCanExecuteChanged();
    }
    
    private void OnPasswordChanged()
    {
      _isStrongPassword = VerifyIsStrongPassword();
      _registerCommand.RaiseCanExecuteChanged();
    }
    
    private void Register()
    {
        var newUser = new User
        {
            FirstName = _firstname,
            LastName = _lastname,
            Username = _username,
            Password = "", // TODO: Hashing and storing of passwords
        };
        using (var context = new WorkstreamContext())
        {
            var users = context.Set<User>();
            users.Add(newUser);
            context.SaveChanges();
        }
    }
    
    #endregion