为什么 WPF ApplicationCommands.Close 命令在按钮和菜单项中被禁用?
Why is the WPF ApplicationCommands.Close command disabled on the button and in the menu item?
问题
为什么 WPF ApplicationCommands.Close 命令在按钮和菜单项中被禁用?
代码
<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 说自己实现 ICommand
并在命令处理程序中执行 this.Close()
。但是,我根本不明白为什么 ApplicationCommands.Close
存在。
Some sources 表示需要对 return true
实施 CanExecute
方法。但是,如果我必须自己做,包括 CloseCommandHandler
(来自链接示例),那么 ApplicationCommands.Close
有什么好处?
Some sources提一个CommandTarget
。这没有用:
<MenuItem Header="_Exit" Command="Close" CommandTarget="{Binding ElementName=MyMainWindow}"/>
我是不是用 CommandTarget
做错了?
ApplicationCommands
,如 NavigationCommands
和 ComponentCommands
公开了一组预定义的通用 UI 命令。它们都是RoutedCommand
的实现。 RoutedCommand
或 RoutedUICommand
实施 ICommand
。
RoutedCommand
没有实现 Execute
或 CanExecute
方法。它只是引发相应的 RoutedEvent
。
此事件将遍历可视化树,直到被 CommandBinding
处理。 CommandBinding
定义或执行 CanExecute
和 Execute
方法或特殊事件处理程序。这意味着可以在引发 RoutedCommand
的树上的某处定义实际的命令实现。
有一些实现默认 CommandBinding
(或命令实现)的控件。 TextBox
可以处理例如ApplicationCommands.Copy
RoutedCommand
。或者 DocumentViewer
可以处理 NavigationCommands.NextPage RoutedCommand。 ApplicationCommands.Close
没有任何控件提供的支持者或默认实现。
RoutedCommand
旨在用于 UI 上下文,例如控件的执行行为。这种逻辑不应该在视图模型中处理。因此 ApplicationCommands.Close
必须由挂接到可视化树中的控件或附加行为来实现。
对于数据相关的行为或逻辑,您必须提供自己的 ICommand
实现,它具有在视图模型中定义的处理程序。
如果您将 RoutedCommand
例如 ApplicationCommands.Close
分配给命令源,例如Button
,但不为此 RoutedCommand
提供处理程序,因此命令源中不存在 CanExecute
处理程序,例如Button
假定 CanExecute
为假并禁用自身。
这意味着您必须提供 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();
}
问题
为什么 WPF ApplicationCommands.Close 命令在按钮和菜单项中被禁用?
代码
<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 说自己实现 ICommand
并在命令处理程序中执行 this.Close()
。但是,我根本不明白为什么 ApplicationCommands.Close
存在。
Some sources 表示需要对 return true
实施 CanExecute
方法。但是,如果我必须自己做,包括 CloseCommandHandler
(来自链接示例),那么 ApplicationCommands.Close
有什么好处?
Some sources提一个CommandTarget
。这没有用:
<MenuItem Header="_Exit" Command="Close" CommandTarget="{Binding ElementName=MyMainWindow}"/>
我是不是用 CommandTarget
做错了?
ApplicationCommands
,如 NavigationCommands
和 ComponentCommands
公开了一组预定义的通用 UI 命令。它们都是RoutedCommand
的实现。 RoutedCommand
或 RoutedUICommand
实施 ICommand
。
RoutedCommand
没有实现 Execute
或 CanExecute
方法。它只是引发相应的 RoutedEvent
。
此事件将遍历可视化树,直到被 CommandBinding
处理。 CommandBinding
定义或执行 CanExecute
和 Execute
方法或特殊事件处理程序。这意味着可以在引发 RoutedCommand
的树上的某处定义实际的命令实现。
有一些实现默认 CommandBinding
(或命令实现)的控件。 TextBox
可以处理例如ApplicationCommands.Copy
RoutedCommand
。或者 DocumentViewer
可以处理 NavigationCommands.NextPage RoutedCommand。 ApplicationCommands.Close
没有任何控件提供的支持者或默认实现。
RoutedCommand
旨在用于 UI 上下文,例如控件的执行行为。这种逻辑不应该在视图模型中处理。因此 ApplicationCommands.Close
必须由挂接到可视化树中的控件或附加行为来实现。
对于数据相关的行为或逻辑,您必须提供自己的 ICommand
实现,它具有在视图模型中定义的处理程序。
如果您将 RoutedCommand
例如 ApplicationCommands.Close
分配给命令源,例如Button
,但不为此 RoutedCommand
提供处理程序,因此命令源中不存在 CanExecute
处理程序,例如Button
假定 CanExecute
为假并禁用自身。
这意味着您必须提供 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();
}