0

I have a DelegateCommand that looks like so:

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

I have a process that allows the user to register onto a database. However, I need to add some validation in for example, does the username already exist, does the password match rules etc. Here is the register command:

#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

As you can see, I have a method called CanRegister() that I want to use to filter through the registration process. My question is, how would I implement CanRegister() in the call here:

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

that prompts or denies the process if CanRegister returns false?

CBreeze
  • 2,925
  • 4
  • 38
  • 93
  • Try to read answer from [here](https://stackoverflow.com/questions/23110880/wpf-command-binding-with-input-validation-how-to-enable-the-save-button-only), may be It would help – bogdanbrizhaty Jul 11 '17 at 21:00
  • _"how would I implement CanRegister() in the call here"_ -- what's that mean? To _implement_ `CanRegister()` is to put code in the method body, i.e. replace the `return true;` you have now with real code. To _use_ the method _"in the call here"_ means to simply call the method in e.g. a lambda, i.e. `_registerCommand = new DelegateCommand(param => Register(), param => CanRegister());`. Which is it that _you_ want to do? What do you actually need help with? What's the code doing now, what _precisely_ do you want it to do instead, what've you tried, and what _specifically_ do you need help with? – Peter Duniho Jul 11 '17 at 21:56

1 Answers1

0

The usual approach is to disable your command button until all validation criteria have been met. In your case, where you have two validation rules (user name does not exist, password matches rules) I would do the following:

  1. Check that the user name exists as the user types it in. Obviously you don't want the database call firing after every keystroke, so use the Delay option in the binding. Set a property in your ViewModel to reflect the result, e.g. IsUserNameUnique. When setting this property, call the RaiseCanExecuteChanged method on your DelegateCommand.

  2. Repeat this process for your password with IsStrongPassword.

  3. Hook your DelegateCommand into the CanRegister method in its constructor. This will disable the command until CanRegister returns true.

  4. Change your CanRegister command to only return true when both IsStrongPassword and IsUserNameUnique are true.

Delay binding:

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

Viewmodel

#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
Barracoder
  • 3,696
  • 2
  • 28
  • 31