wpf 定义菜单项快捷方式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4682915/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Defining MenuItem Shortcuts
提问by Felipe Fujiy Pessoto
I need a simple way to set a shortcut for menu items.
我需要一种简单的方法来设置菜单项的快捷方式。
But this don′t work with shortcut, just with click:
但这不适用于快捷方式,只需单击即可:
<MenuItem Header="Editar">
<MenuItem Header="Procurar" Name="MenuProcurar"
InputGestureText="Ctrl+F"
Click="MenuProcurar_Click">
<MenuItem.ToolTip>
<ToolTip>
Procurar
</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
</MenuItem>
I am using WPF 4.0
我正在使用 WPF 4.0
回答by H.B.
You need to use KeyBindings
(and CommandBindings
if you (re)use RoutedCommands
such as those found in the ApplicationCommands
class) for that in the controls where the shortcuts should work.
您需要在快捷方式应该工作的控件中使用KeyBindings
(并且CommandBindings
如果您(重新)使用RoutedCommands
在ApplicationCommands
类中找到的那些)。
e.g.
例如
<Window.CommandBindings>
<CommandBinding Command="New" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Key="N" Modifiers="Control" Command="New"/>
</Window.InputBindings>
For custom RoutedCommands
:
对于定制RoutedCommands
:
static class CustomCommands
{
public static RoutedCommand DoStuff = new RoutedCommand();
}
usage:
用法:
<Window
...
xmlns:local="clr-namespace:MyNamespace">
<Window.CommandBindings>
<CommandBinding Command="local:CustomCommands.DoStuff" Executed="DoStuff_Executed" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Key="D" Modifiers="Control" Command="local:CustomCommands.DoStuff"/>
</Window.InputBindings>
...
</Window>
(It is often more convenient to implement the ICommand
interfacerather than using RoutedCommands
. You can have a constructor which takes delegates for Execute
and CanExecute
to easily create commands which do different things, such implementations are often called DelegateCommand
or RelayCommand
. This way you do not need CommandBindings
.)
(实现ICommand
接口通常比使用更方便RoutedCommands
。您可以拥有一个构造函数,该构造函数接受委托Execute
并CanExecute
轻松创建执行不同操作的命令,此类实现通常称为DelegateCommand
or RelayCommand
。这样您就不需要CommandBindings
。)
回答by Guish
H.B. was right... I just wanted to add more precisions.
HB 是对的......我只是想增加更多的精度。
Remove the Click
event on your MenuItem
and associate it with a Command
instead.
删除Click
您的事件MenuItem
并将其与 a 相关联Command
。
1 - Add/create your commands:
1 - 添加/创建您的命令:
<Window.CommandBindings>
<CommandBinding Command="Open" Executed="OpenCommandBinding_Executed"/>
<CommandBinding Command="SaveAs" Executed="SaveAsCommandBinding_Executed"/>
</Window.CommandBindings>
The commands are refering to the following code:
这些命令是指以下代码:
private void OpenCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
Open();//Implementation of open file
}
private void SaveAsCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
SaveAs();//Implementation of saveAs
}
2 - Associate the commands with the wanted keys:
2 - 将命令与所需的键相关联:
<Window.InputBindings>
<KeyBinding Key="O" Modifiers="Control" Command="Open"/>
<KeyBinding Key="S" Modifiers="Control" Command="SaveAs"/>
</Window.InputBindings>
3 - Finally assign the commands with you menu item (InputGestureText
is just a decorating text):
3 - 最后为你的菜单项分配命令(InputGestureText
只是一个装饰文本):
<Menu Name="menu1">
<MenuItem Header="_File">
<MenuItem Name="menuOpen" Header="_Open..." Command="Open" InputGestureText="Ctrl+O"/>
<MenuItem Name="menuSaveAs" Header="_Save as..." Command="SaveAs" InputGestureText="Ctrl+S"/>
</MenuItem>
</Menu>
That way multiple inputs may be associated to the same command.
这样,多个输入可以关联到同一个命令。
回答by Ignacio Soler Garcia
In my humble opinion is much easier just to use _ at the Header. This will create automatically the desired HotKey.
在我看来,仅在标题中使用 _ 就容易多了。这将自动创建所需的热键。
For example:
例如:
<MenuItem Header="_Editar">
<MenuItem Header="_Procurar" Name="MenuProcurar"
InputGestureText="Ctrl+F"
Click="MenuProcurar_Click">
<MenuItem.ToolTip>
<ToolTip>
Procurar
</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
</MenuItem>
回答by jiasli
You can also declare RoutedUICommand
in XAML:
您还可以RoutedUICommand
在 XAML 中声明:
<Window.Resources>
<RoutedUICommand x:Key="BuildCmd" Text="Build">
<RoutedUICommand.InputGestures>
<KeyGesture>CTRL+SHIFT+B</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
</Window.Resources>
Do the binding
做绑定
<Window.CommandBindings>
<CommandBinding Command="{StaticResource BuildCmd}" Executed="BuildCmdExecuted"/>
</Window.CommandBindings>
And in MenuItem
而在 MenuItem
<MenuItem Command="{StaticResource BuildCmd}"/>
Another solution is discussed here.
此处讨论了另一种解决方案。
回答by ruffin
I'm overly biased by Windows.Forms & gulpVB 6, so I kind of agree with Jonathanand Jasethat there's got to be a more straightforward/procedural method to statically wire up event handlers that aren't necessarily CommandBindings
. And there is, I think.
我对 Windows.Forms 和gulpVB 6过于偏心,所以我有点同意 Jonathan和Jase 的观点,即必须有一种更直接/程序化的方法来静态连接不一定是CommandBindings
. 还有,我想。
A good tutorial for using non-CommandBinding
handlers like this, but with an emphasis on buttons, can be found in this MSDN blog post, I believe. I'll distill and target MenuItem
s...
我相信CommandBinding
,可以在这篇 MSDN 博客文章中找到使用此类非处理程序的好教程,但重点是按钮。我将提炼并瞄准MenuItem
...
Creating the ICommand
创建 ICommand
First, create a class implementing ICommand
. You can put this anywhere, of course, even in your MainWindow.xaml.cs file if you wanted, to keep your demo code insanely simple. You'll probably want to make CanExecute
more complicated when you want to dis/en/able menu items later, but for now, we'll just always have our menu items enabled.
首先,创建一个实现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;
}
As the tutorial helpfully points out, you could call this command from anywhere already, with code like...
正如教程中有用地指出的那样,您可以从任何地方调用此命令,代码如下...
var hwc = new HelloWorldCommand();
if (hwc.CanExecute(this))
hwc.Execute(this);
Declaring your command in the Window
在窗口中声明你的命令
So let's add a sort of "declaration" for the HelloWorldCommand
to our Window so that we can use it later. Inside of your Window
tags, register the command as a resource:
因此,让HelloWorldCommand
我们为 Window添加一种“声明”,以便我们以后可以使用它。在Window
标签内,将命令注册为资源:
<Window.Resources>
<local:HelloWorldCommand x:Key="hwc"/>
</Window.Resources>
Now we have a neat shortcut for linking to this "locally namespaced" command, "hwc"
, though you can obviously use any string you want. We'll use that a lot in our xaml.
现在我们有一个简洁的快捷方式来链接到这个“本地命名空间”命令"hwc"
,虽然你显然可以使用任何你想要的字符串。我们将在我们的 xaml 中大量使用它。
Wiring up (and reusing!) the command
连接(和重用!)命令
Let's add our MenuItem
s to our xaml. I've replaced the stock Grid
with a DockPanel
because that's the easiest way (for me) to have equi-spaced widgets that fill the Window
, though I've left all of the rest of my UI out.
让我们将MenuItem
s添加到我们的 xaml 中。我已经Grid
用 a替换了股票,DockPanel
因为这是(对我而言)最简单的方法来填充等距小部件Window
,尽管我已经将 UI 的所有其余部分都排除在外。
Note the Command="{StaticResource hwc}"
s sprinkled into each MenuItem
declaration. The key is the hwc
in there - remember that that's our shortcut for the HelloWorldCommand
that we set up at the Window
level. And, of course, StaticResource
says just to look it up the Window
's resources. We're not binding anything; we're just using our shortcut.
注意Command="{StaticResource hwc}"
s 散布在每个MenuItem
声明中。关键是hwc
在那里 - 请记住,这是我们HelloWorldCommand
在Window
关卡中设置的快捷方式。而且,当然,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 to distinguish event sources
区分事件源的命令参数
Note that we're using the same Command for everything!But how can we tell which widget threw the event? For that, you need to use the CommandParameter
-- remember our Execute
method's signature: Execute(object parameter)
. That CommandParameter
parameter is what we can use to know how to handle the event. Try running this and note that the MessageBox
will use whatever's in CommandParameter
to let you know the source of the event. We're doing it all manually, but that's not too bad.
请注意,我们对所有内容都使用相同的命令!但是我们怎么知道是哪个小部件抛出了这个事件呢?为此,您需要使用CommandParameter
-- 记住我们Execute
方法的签名:Execute(object parameter)
。该CommandParameter
参数是我们可以用来了解如何处理事件的参数。尝试运行此程序并注意,MessageBox
它将使用其中的任何内容CommandParameter
来让您知道事件的来源。我们都是手动完成的,但这还不错。
Also note that you can make these objects as complicated as you'd like. You can use a property in the MenuItem
tag to define the parameter, or can use "real" <MenuItem.CommandParameter>
tags, like in the Open menu item, above, to define something complex. In this case, we're passing the entire parent Window
object, which was the easiest (though not the cleanest) way to throw our VB6-ish context into the event handler code.
另请注意,您可以根据需要使这些对象变得复杂。您可以使用MenuItem
标签中的属性来定义参数,也可以使用“真实”<MenuItem.CommandParameter>
标签(如上面的打开菜单项中)来定义复杂的内容。在这种情况下,我们传递了整个父Window
对象,这是将我们的 VB6-ish 上下文扔到事件处理程序代码中的最简单(虽然不是最干净)的方法。
Adding keyboard shortcuts to MenuItem
s (aka, "Answering the OP")
向MenuItem
s添加键盘快捷键(又名“回答 OP”)
And now we can finally answer the original question! Let's finally wire up a keyboard shortcut for the Close
menu item. You'll note that we've already declared an InputGestureText
. By itself, InputGestureText
is only cosmetic. If we were overly picky, we could argue the mechanism for creating the keyboard shortcut doesn't have any direct, inherent relationship with the MenuItem
at all!
现在我们终于可以回答最初的问题了!最后让我们为Close
菜单项连接一个键盘快捷键。您会注意到我们已经声明了一个InputGestureText
. 就其本身而言,InputGestureText
只是装饰性的。如果我们过于挑剔,我们可能会争辩说创建键盘快捷键的机制与 根本没有任何直接的内在关系MenuItem
!
We need to instead (or additionally) register a listener for Ctrl-G at the Window
level to catch the keystroke. So at the top level of your Window tags, insert this (taken essentially from here):
我们需要(或另外)在Window
级别上为 Ctrl-G 注册一个侦听器以捕获击键。所以在你的 Window 标签的顶层,插入这个(基本上取自这里):
<Window.InputBindings>
<KeyBinding Modifiers="Control"
Key="G"
Command="{StaticResource hwc}"
CommandParameter="window input binding"
/>
</Window.InputBindings>
Note that you could put CommandParameter
tags in your KeyBinding
by moving it from a self-closing piece of XML to "real" open and close KeyBinding
tags.
请注意,您可以通过将CommandParameter
标签KeyBinding
从 XML 的自闭合部分移动到“真正的”打开和关闭KeyBinding
标签来将标签放入您的标签中。
And we're done. Run your app, and press Ctrl-G. Whaddup.
我们已经完成了。运行您的应用程序,然后按 Ctrl-G。瓦杜普。
Pretty straightforward, once you've got the players straight, and much less magic binding-y than most intros to commands and MenuItems
, I think.
非常简单,一旦你让玩家直截了当,并且比大多数命令和 的介绍少得多的魔法绑定MenuItems
,我认为。
Possible pro tip:
The whole
CommandBinding
thing confused me for a while. This is justfor specific command types, I believe. That is, you can't just wire up anyCommand
you like. Stuff like what's bragged about here(in what's admittedly a decent intro tutorial!)...It might not be completely obvious, but by using commands, we just got a whole bunch of things for free: Keyboard shortcuts, text and InputGestureText on the items and WPF automatically enables/disables the items depending on the active control and its state. In this case, Cut and Copy are disabled because no text is selected, but Paste is enabled, because my clipboard is not empty!
... is kind of magic-y and not necessarily good, and can be confusing when you're new to WPF menus.
可能的专业提示:
整件事
CommandBinding
让我困惑了一段时间。我相信这仅适用于特定的命令类型。也就是说,您不能随意连接任何Command
您喜欢的东西。像这里吹嘘的东西(在公认的不错的介绍教程中!)...这可能不是很明显,但是通过使用命令,我们可以免费获得一大堆东西:项目上的键盘快捷键、文本和 InputGestureText,WPF 根据活动控件及其状态自动启用/禁用项目。在这种情况下,剪切和复制被禁用,因为没有选择文本,但粘贴被启用,因为我的剪贴板不是空的!
... 有点神奇,不一定很好,当您不熟悉 WPF 菜单时可能会感到困惑。