Search code examples
c#wpfmvvmicommand

Binding Static ICommand Variable grays out button?


Continuing with my struggle with Static variables and XAML, I can't work around the command bindings greying out the button.

The code in View Model:

public static ICommand CancelCalender => _cancelCalender
          ?? (_cancelCalender = new CommandHandler(CancelCalender_Button, _canExecute));


public class CommandHandler : ICommand
{
    private Action _action;
    private bool _canExecute;
    public CommandHandler(Action action, bool canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

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

    public event EventHandler CanExecuteChanged;

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

The reference,

xmlns:viewModels="clr-namespace:StaffShiftManager.ViewModels"

And these are the ways I tried to bind the command variable:

Command="{x:Static viewModels:ViewModelBase.CancelCalender}"

And

Command="viewModels:ViewModelBase.CancelCalender"

And

Command="{Binding Source={x:Static viewModels:ViewModelBase.CancelCalender}}"

Is there something that I am missing? Any help would be greatly appreciated.


Solution

  • Basically in the ICommand CanExecute() method, this returns wether or not the Command is enabled \ can execute.

    Returning false from the CanExecute() will disable (gray out) the button.

    Now I have modified your code slightly to provide a Func<bool> as the CanExecute() handler. What will happen here is every time the Command Execution is re-queried it will execute your canExecute method.

    public class CommandHandler : ICommand
    {
        public CommandHandler(Action execute)
            :this(execute, null)
        {
        }
    
        public CommandHandler(Action execute, Func<bool> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException(nameof(execute));
    
            _executeHandler = execute;
            _canExecuteHandler = canExecute ?? (() => true);
        }
    
    
        Func<bool> _canExecuteHandler = () => true;
        Action _executeHandler;
    
        public event EventHandler CanExecuteChanged;
    
        public bool CanExecute(object parameter)
        {
            return _canExecuteHandler();
        }
    
        public void Execute(object parameter)
        {
            _executeHandler?.Invoke();
        }
    }
    

    Not that the default implementation for the canExecute method is to return true. Even passing a null Func to the constructor will still result in true.

    Just to add one more thing one of my favorite command binders (much more advanced than above) is using the DelegateCommand. I dont remeber where I found the original source (as I did not write it) but is much more advanced.