简体   繁体   中英

How can I enable/disable a button?

Although I have found several answers to this question I somehow don't get it. So please excuse me asking.

I have a WPF application following the MVVM pattern. It contains a button which is bound to a command in the view model:

<button Content="Login" Command="{Binding ProjectLoginCommand}"/>

The commands are using RelayCommand . Now I would like to do the following:

  • The user clicks the button and the corresponding command is executed. This works.
  • Within this command another button shall be deactivated, ie it shall not be clickable.

I found that this should be possible using CanExecute but being honest: I simply don't get it. Hoe can I set the button to enabled/disabled?

This is the RelayCommand.cs :

namespace MyApp.Helpers {
    class RelayCommand : ICommand {

    readonly Action<object> execute;
    readonly Predicate<object> canExecute;

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

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
      if (execute == null)
          throw new ArgumentNullException("execute");

      this.execute = execute;
      this.canExecute = canExecute;           
    }

    public bool CanExecute(object parameter)
    {
      return canExecute == null ? true : canExecute(parameter);
    }

  public event EventHandler CanExecuteChanged
  {
      add { CommandManager.RequerySuggested += value; }
      remove { CommandManager.RequerySuggested -= value; }
  }

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

This is how I call the command:

RelayCommand getProjectListCommand;

public ICommand GetProjectListCommand {
    get {
        if (getProjectListCommand == null) {
            getProjectListCommand = new RelayCommand(param => this.ProjectLogin());
        }
        return getProjectListCommand;
    }
}

When creating a RelayCommand object you have to pass a can Predicate, which could be (among other things) a method with following signature:

bool MethodName(object parameter).

If you don't need the parameter, use eg bool MethodName(), but pass it to RelayCommand constructor like that: (o) => MethodName().

In this method you should do your logic and return a value indicating whether the command can be executed. The rest should be handled by WPF Command infrastructure.

When you use the RelayCommand you can specify two methods. The first method is the main method you want to run when the command is invoked. The second method you use to add in checks such as validation, and this should return a bool. if it returns false, then the main method will not run.

How it affects the button you have the command bound to, is it will run the boolean method continually, and while it return false, then the button the command is bound to will be disabled.

So in your command property:

public ICommand GetProjectListCommand {
get {
    if (getProjectListCommand == null) {
        getProjectListCommand = new RelayCommand(param => this.ProjectLogin(), CanProjectLogin());
    }
    return getProjectListCommand;
}

Add in new method:

public bool CanProjectLogin()
{
    //here check some properties to make sure everything is set that you'd want to use in your ProjectLogin() method
}

you can see how the CanExecute works if you put a break point in the bool method.

If you are having trouble working with the canExecute callback, you may find it easier to work with a simpler version of RelayCommand:

class RelayCommand : ICommand 
{
    readonly Action execute;
    private bool canExecute;

    public RelayCommand(Action execute) 
    {
        this.execute = execute;
        this.canExecute = true;
    }

    public bool CanExecute(object parameter)
    {
        return canExecute;
    }

    public void SetCanExecute(bool canExecute)
    {
        this.canExecute = canExecute;
        var handler = CanExecuteChanged;
        if (handler != null) handler(this, EventArgs.Empty);
    }

    public event EventHandler CanExecuteChanged;

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

With this approach, you save references to the RelayCommand objects you make, allowing you to disable the commands like this:

getProjectListCommand.SetCanExecute(false);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM