Ari Roth
Ari Roth

Reputation: 5534

DelegateCommand.CanExecute method not behaving correctly

I'm binding a control to a DelegateCommand and the CanExecute portion of it is not working properly. I am using the Prism libraries. Can anyone tell me why?

Command declaration and instantiation:

public PlayerManagementViewModel(DatabaseManager dbManager)
{
    _dbManager = dbManager;
    this.ResetUpToDateStatusCommand = new DelegateCommand(() => this.ResetXpUpToDateStatus());
    this.DeletePlayerCommand = new DelegateCommand(() => this.DeleteSelectedPlayer(), () => SelectedPlayer != null);
    this.RefreshPlayers();
}

public ICommand DeletePlayerCommand { get; private set; }

SelectedPlayer definition:

public Player SelectedPlayer
{
    get { return _selectedPlayer; }
    set
    {
        SetProperty(ref this._selectedPlayer, value);
        this.OnPropertyChanged(() => this.FormattedPlayerStatus);
    }
}

The weird thing is that if you look at the line above the DeletePlayerCommand instantiation, that line works just fine. I don't get any CanExecute behavior out of it, but at least it works. As is, the DeletePlayerCommand command never fires off, even with a breakpoint, unless I remove the CanExecute portion of the constructor entirely.

Can anyone please explain to me why this is or what I'm doing wrong?

Upvotes: 1

Views: 5157

Answers (2)

Ayyappan Subramanian
Ayyappan Subramanian

Reputation: 5366

It is the way PRISM DelegateCommnd is designed. refer CanExecuteChanged event of ICommand.

Alternatively you can derive the DelegateCommand to overcome the limitation. refer the below code.

 class DelegateCmdEx : DelegateCommand
{       
    public DelegateCmdEx(Action executeMethod):base(executeMethod)
    {

    }

    public DelegateCmdEx(Action executeMethod, Func<bool> canExecuteMethod)
        : base(executeMethod, canExecuteMethod)
    {

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

Upvotes: 0

If the CanExecute function of the DeletePlayerCommand is () => SelectedPlayer != null, then there must be a DelegateCommandBase.RaiseCanExecuteChanged Method call when SelectedProperty value is changed:

Raises CanExecuteChanged on the UI thread so every command invoker can requery to check if the command can execute.

The appropriate UI-element (with data-bound command) is a command invoker.

To summarize, the implementation of the SelectedPlayer property should be updated as follows:

class PlayerManagementViewModel : BindableBase
{
    private Player _selectedPlayer;
    private readonly DelegateCommand _deletePlayerCommand;

    public PlayerManagementViewModel(...)
    {
        _deletePlayerCommand = new DelegateCommand(() => DeleteSelectedPlayer(), () => SelectedPlayer != null);
    }

    public ICommand DeletePlayerCommand
    {
        get { return _deletePlayerCommand; }
    }

    public Player SelectedPlayer
    {
        get { return _selectedPlayer; }
        set
        {
            SetProperty(ref _selectedPlayer, value);
            OnPropertyChanged(() => FormattedPlayerStatus);
            _deletePlayerCommand.RaiseCanExecuteChanged();
        }
    }
}

Upvotes: 5

Related Questions