我被Windows.Forms和VB 6过度偏见,所以我有点赞同Jonathan和Jase,认为有一个更加直接/程序化的方法来静态地连接事件处理程序,这些处理程序不一定是CommandBindings
。 我想这是可以实现的。
一个很好的使用非CommandBinding
处理程序的教程,尤其是关于按钮的,可以在这篇MSDN博客文章中找到。 我会提炼并针对MenuItem
...
创建ICommand
首先,创建一个实现了
ICommand
接口的类。当然,你可以把它放在任何地方,甚至是你的 MainWindow.xaml.cs 文件中,如果你想让你的演示代码非常简单。当你想要稍后禁用/启用菜单项时,你可能会想让
CanExecute
更加复杂,但是现在,我们将始终启用我们的菜单项。
public class HelloWorldCommand : ICommand
{
public void Execute(object parameter)
{
MessageBox.Show(@"""Hello, world!"" from "
+ (parameter ?? "somewhere secret").ToString());
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
}
正如教程中指出的那样,您已经可以从任何地方调用此命令,例如以下代码...
var hwc = new HelloWorldCommand();
if (hwc.CanExecute(this))
hwc.Execute(this);
在窗口中声明您的命令
因此,让我们为HelloWorldCommand
添加一种类似于“声明”的方法,以便稍后可以使用它。在您的Window
标签内部,将该命令注册为资源:
<Window.Resources>
<local:HelloWorldCommand x:Key="hwc"/>
</Window.Resources>
现在我们有一个方便的快捷方式来链接到这个“本地命名空间”命令,
"hwc"
,虽然您可以使用任何字符串。我们将在xaml中经常使用它。
连接(和重用!)命令
让我们将我们的
MenuItem
添加到我们的xaml中。我已经用
DockPanel
替换了原始的
Grid
,因为这是最简单的方法(对我来说),可以填充
Window
的等距小部件,尽管我留下了所有其他UI。
请注意,
Command =“{StaticResource hwc}”
散布在每个
MenuItem
声明中。关键是里面的
hwc
- 记住,这是我们在
Window
级别设置的
HelloWorldCommand
的快捷方式。当然,
StaticResource
只是说要查找
Window
的资源。我们不绑定任何东西;我们只是使用我们的快捷方式。
<DockPanel LastChildFill="True">
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem
Header="_Open"
Command="{StaticResource hwc}"
>
<MenuItem.CommandParameter>
<!-- so you could make this object as complex as you wanted,
like, say, your entire Window. See magic incantation, below. -->
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}" />
</MenuItem.CommandParameter>
</MenuItem>
<MenuItem
Header="_Close"
Command="{StaticResource hwc}"
CommandParameter="Close"
InputGestureText="Ctrl+G" />
<MenuItem
Header="_Save"
Command="{StaticResource hwc}"
CommandParameter="Save" />
<Separator />
<MenuItem
Header="_Quit"
Command="{StaticResource hwc}"
CommandParameter="Quit" />
</MenuItem>
</DockPanel>
使用CommandParameters区分事件源
请注意我们对所有内容都使用相同的命令!但是我们如何知道哪个小部件触发了事件呢?为此,您需要使用CommandParameter
-- 记住我们的Execute
方法的签名:Execute(object parameter)
。那个CommandParameter
参数就是我们可以用来知道如何处理事件的。尝试运行这个程序并注意MessageBox
将使用CommandParameter
中的任何内容来让您知道事件的来源。虽然我们正在手动完成所有操作,但这并不太难。
还要注意,您可以使这些对象变得非常复杂。您可以在MenuItem
标记中使用属性来定义参数,或者可以使用“真正的”<MenuItem.CommandParameter>
标记,例如上面的Open菜单项,来定义一些复杂的东西。在这种情况下,我们传递了整个父Window
对象,这是把VB6-ish上下文放入事件处理程序代码的最简单(虽然不是最干净)的方法。
为MenuItem
添加键盘快捷键(也称为“回答OP”)
现在我们终于可以回答最初的问题了!让我们终于为Close
菜单项连接一个键盘快捷键。您会注意到,我们已经声明了一个InputGestureText
。仅凭InputGestureText
只是装饰性的。如果我们过分挑剔,我们可能会争论创建键盘快捷键的机制根本没有与MenuItem
直接、固有的关系!
相反,我们需要在Window
级别注册一个Ctrl-G的监听器来捕获按键。因此,在您的窗口标记的顶层插入以下内容(基本上来源于这里):
<Window.InputBindings>
<KeyBinding Modifiers="Control"
Key="G"
Command="{StaticResource hwc}"
CommandParameter="window input binding"
/>
</Window.InputBindings>
请注意,您可以通过将
CommandParameter
标签从自闭合的XML移动到“真正的”打开和关闭
KeyBinding
标签中,在
KeyBinding
中放置它。
完成后,请运行您的应用程序并按Ctrl-G。很简单。
我认为这比大多数介绍命令和
MenuItems
的方式要简单得多,一旦您了解了玩家的情况。
可能的专业提示:
整个CommandBinding
的事情让我困惑了一段时间。我相信这只是针对特定命令类型的。也就是说,您不能随意连接任何Command
。像这里所吹嘘的(在一个不错的入门教程中!)...
可能不完全明显,但通过使用命令,我们刚刚获得了很多免费的东西:键盘快捷键、项目上的文本和InputGestureText以及WPF根据活动控件及其状态自动启用/禁用项目。在这种情况下,由于未选择任何文本,因此“剪切”和“复制”被禁用,但“粘贴”处于启用状态,因为我的剪贴板不为空!
...有点神奇,不一定好,当您新接触WPF菜单时可能会感到困惑。
Open
命令。如果您使用此类命令,则无需显式指定KeyBinding
或InputGestureText
。此外,如果默认文本对您来说可以接受,您可以省略Header
。 - Martin