简体   繁体   中英

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?

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

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

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