Reputation: 25141
In WPF XAML, I've got a Button
's Command
property working with an implementation of a class implementing ICommand
.
In this implementation, I don't have my CanExecuteChanged
event wired up to use CommandManager.RequerySuggested
- I want to have control over when CanExecute is called, and using this calls it way more often than necessary.
The only other way I can get ICommand.CanExecute
to re-evaluate is to use something like:
public void InvokeCanExecute()
{
CanExecuteChanged.Invoke(this, new EventArgs());
}
In my class implementing the ICommand
.
This seems really nasty - am I missing something obvious? I've tried invoking the re-evaluation using PropertyChanged
but that doesn't seem to work.
Upvotes: 2
Views: 628
Reputation: 4298
It's true that - if you don't want to use CommandManager.RequerySuggested
, which indeed might call CanExecute
more often than necessary - you need to explicitly invoke your own InvokeCanExecute
method in order to force the command to re-evaluate its CanExecute
condition.
However, in most cases the CanExecute
condition will depend on public (bindable) properties, meaning properties that raise the PropertyChanged
event to indicate that their value has changed - it is possible to hook into this event, in order to automatically call InvokeCanExecute
whenever one of the properties the command depends on has changed. For an example of how to implement such a command, see this guy's blog post (if I'm not mistaken, this approach is implemented e.g. as part of the MVVM Light toolkit).
Instantiating a command using this approach would look somewhat like the following:
SaveCommand = new RelayCommand(() => { /* do some stuff; */ },
() => !string.IsNullOrEmpty(Name),
this, () => Name);
Since the command's CanExecute
condition (which checks whether Name
is empty) depends on the Name
property, it needs to be re-evaluated whenever Name
's content changes. You simply pass a reference to the Name
property to the command's constructor, and InvokeCanExecute
will automatically be called whenever the value of Name
changes.
In theory, it is possible to go one step further and let the command itself check on which properties it depends - if you're interested in this approach, check out one of my blog articles, but note that this one heavily depends on reflection so it always depends on the detailed use-case whether this approach is feasible or not. A sample implementation of this solution is included in the MVVMbasics framework (disclaimer: published by me). In this case, you could reduce the command initialization code to:
SaveCommand = CreateRelayCommand(() => { /* do some stuff; */ },
() => !string.IsNullOrEmpty(Name));
Upvotes: 2
Reputation: 1480
No, you are not really missing anything. Here's a similar question that recommends the same approach you're taking: What is the actual task of CanExecuteChanged and CommandManager.RequerySuggested?.
You can make your method a little bit more robust though:
public void InvokeCanExecute()
{
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}
Upvotes: 1