After studying several Q&A on stackoverflow, some tutorials and of course the official documentation, I trying to use ApplicationCommands
in my WPF Prism MVVM application.
My current approach
After trying different solutions I found out, I ended up with following constellation:
I am using the
AttachCommandBindingsBehavior
class mentioned in this answer, which will be used like this in the view:<UserControl> <i:Interaction.Behaviors> <localBehaviors:AttachCommandBindingsBehavior CommandBindings="{Binding CommandBindings}"/> </i:Interaction.Behaviors> </UserControl>
MyViewModel
contains aCommandBindingCollection
property, which will be populated in the constructor:public CommandBindingCollection CommandBindings { get; } = new CommandBindingCollection(); public MyViewModel() { this.CommandBindings.AddRange(new[] { new CommandBinding(ApplicationCommands.Save, this.Save, this.CanSave), new CommandBinding(ApplicationCommands.Open, this.Open) }); }
The UserControl
MyView
contains two buttons:<Button Command="ApplicationCommands.Open" Content="Open" /> <Button Command="ApplicationCommands.Save" Content="Save" />
My first question at this point is: Are the Executed()
and CanExecute()
methods already bound to the Command-DependencyProperty of the Button
? Since it does not work, what did I forgot or made wrong?
My second question is: How can I trigger the CanExecute
of the Command the Button is bound to? The actual use-case: MyViewModel.CanSave()
returns true, when the user successfully executed the MyViewModel.Open()
method. Usually, I would call an DelegateCommand.RaiseCanExecuteChanged()
, but calling ApplicationCommands.Save.RaiseCanExecuteChanged()
does not execute MyViewModel.CanSave()
.
Feel free to ask for more information. I will really appreciate your answers. Thank you!
The
CommandBindings
property on your behavior is anObservableCollection<CommandBinding>
, but you're binding it to aCommandBindingCollection
in your view model. Change your view model's property to aObservableCollection<CommandBinding>
.There are also some problems with the
AttachCommandBindingsBehavior
you linked to. I'm not sure why the answer was accepted, because it's actually quite broken. The tweaked version below should work, though.You can suggest that WPF's routed command system reevaluate all commands by calling
CommandManager.InvalidateRequerySuggested()
. The actual reevaluation will occur asynchronously at theBackground
dispatcher priority. This is the explicit way to do it, but you should know that this already happens implicitly upon certain actions, like focus changes and mouse/keyboard button-up events. The WPF developers tried to make automatic command requerying as seamless as possible, so it "just works" most of the time.Just to be clear, as a
CanExecuteRoutedEventHandler
, yourCanSave
method should returnvoid
and setCanExecute
totrue
on the event argument.