Why is the WPF ApplicationCommands.Close command disabled on the button and in the menu item?
<Window x:Class="ApplicationCloseCommand.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:ApplicationCloseCommand.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="169.493" Width="319.273">
<Window.DataContext>
<viewModels:MainWindowViewModel />
</Window.DataContext>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_Exit" Command="Close"/>
</MenuItem>
</Menu>
<Canvas>
<Button Content="Close" Command="Close" Height="23" VerticalAlignment="Top" Canvas.Left="142" Canvas.Top="31"/>
</Canvas>
</DockPanel>
</Window>
Some sources say to implement an ICommand
yourself and do a this.Close()
in the command handler. But then, I don't understand why ApplicationCommands.Close
exists at all.
Some sources say that one needs to implement a CanExecute
methode to return true
. But again, if I have to do that myself including the CloseCommandHandler
(from the linked example), what's the benefit of ApplicationCommands.Close
?
Some sources mention a CommandTarget
. This didn't work:
<MenuItem Header="_Exit" Command="Close" CommandTarget="{Binding ElementName=MyMainWindow}"/>
Did I just do it wrong with the CommandTarget
?
ApplicationCommands
, like NavigationCommands
and ComponentCommands
exposes set of predefined common UI commands. They are all implementations of RoutedCommand
. RoutedCommand
or RoutedUICommand
implement ICommand
.
RoutedCommand
doesn't implement an Execute
or CanExecute
method. It just raises the corresponding RoutedEvent
.
This event will traverse the visual tree until it is handled by a CommandBinding
. It's the CommandBinding
that defines or executes the CanExecute
and Execute
methods or special event handlers. This means the actual command implementations can be defined somewhere on the tree on which the RoutedCommand
was raised.
There are a few controls that implement a default CommandBinding
(or command implementation). TextBox
can handle e.g. the ApplicationCommands.Copy
RoutedCommand
. Or the DocumentViewer
can handle the NavigationCommands.NextPage RoutedCommand. ApplicationCommands.Close
has no supporter or default implementation provided by any control.
RoutedCommand
is designed to be used in UI context e.g. executing behaviour of a control. This kind of logic should never be handled in the view model. Therefore ApplicationCommands.Close
must be implemented by a control or an attached behaviour that hooks into the visual tree.
For data related behaviour or logic you must provide your own ICommand
implementation, which has the handlers defined in the view model.
If you assign a RoutedCommand
e.g., ApplicationCommands.Close
to a command source e.g. a Button
, but don't provide a handler for this RoutedCommand
and therefore no CanExecute
handler exists the command source e.g. Button
assumes CanExecute
is false and disables itself.
This means you must provide a CommandBinding
:
MainWindow.xaml
<Window>
<Window.CommandBindings>
<CommandBinding Command="{x:Static ApplicationCommands.Close}"
Executed="ExecutedCloseCommand"
CanExecute="CanExecuteCloseCommand" />
</Window.CommandBindings>
<Button Command="{x:Static ApplicationCommands.Close}"
Content="Close Window"/>
</Window>
MainWindow.xaml.cs
private void CanExecuteCloseCommand(object sender,
CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void ExecutedCloseCommand(object sender,
ExecutedRoutedEventArgs e)
{
this.Close();
}