定义MenuItem快捷方式

时间:2011-01-13 17:07:15

标签: wpf keyboard-shortcuts

我需要一种简单的方法来设置菜单项的快捷方式。

但这不适用于快捷方式,只需点击:

<MenuItem Header="Editar">
    <MenuItem Header="Procurar" Name="MenuProcurar"
              InputGestureText="Ctrl+F"
              Click="MenuProcurar_Click">
        <MenuItem.ToolTip>
            <ToolTip>
                Procurar
            </ToolTip>
        </MenuItem.ToolTip>
    </MenuItem>
</MenuItem>

我正在使用WPF 4.0

7 个答案:

答案 0 :(得分:57)

H.B。是的......我只是想增加更多精确度。

删除Click上的MenuItem个活动,并将其与Command关联。

1 - 添加/创建命令:

<Window.CommandBindings>
     <CommandBinding Command="Open" Executed="OpenCommandBinding_Executed"/>
     <CommandBinding Command="SaveAs" Executed="SaveAsCommandBinding_Executed"/>
</Window.CommandBindings>

命令参考以下代码:

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 - 将命令与所需的键相关联:

<Window.InputBindings>
    <KeyBinding Key="O" Modifiers="Control" Command="Open"/>
    <KeyBinding Key="S" Modifiers="Control" Command="SaveAs"/>
</Window.InputBindings>

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>

这样,多个输入可以与同一命令相关联。

答案 1 :(得分:56)

您需要使用KeyBindings(和CommandBindings如果您(重新)使用RoutedCommands,例如在ApplicationCommands class中找到的那些),那么在快捷键的控件中应该工作。

e.g。

<Window.CommandBindings>
        <CommandBinding Command="New" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Window.InputBindings>
        <KeyBinding Key="N" Modifiers="Control" Command="New"/>
</Window.InputBindings>

对于自定义RoutedCommands

static class CustomCommands
{
    public static RoutedCommand DoStuff = new RoutedCommand();
}

用法:

<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>

(实现ICommand interface而不是使用RoutedCommands通常更方便。您可以拥有一个构造函数,它可以使ExecuteCanExecute的代理轻松创建命令做不同的事情,这种实现通常被称为DelegateCommandRelayCommand。这样你就不需要CommandBindings。)

答案 2 :(得分:10)

在我的拙见中,仅仅在标题处使用_就容易得多。这将自动创建所需的HotKey。

例如:

<MenuItem Header="_Editar">
<MenuItem Header="_Procurar" Name="MenuProcurar"
          InputGestureText="Ctrl+F"
          Click="MenuProcurar_Click">
    <MenuItem.ToolTip>
        <ToolTip>
            Procurar
        </ToolTip>
    </MenuItem.ToolTip>
</MenuItem>
</MenuItem>

答案 3 :(得分:7)

您也可以在XAML中声明RoutedUICommand

<Window.Resources>
    <RoutedUICommand x:Key="BuildCmd" Text="Build">
        <RoutedUICommand.InputGestures>
            <KeyGesture>CTRL+SHIFT+B</KeyGesture>
        </RoutedUICommand.InputGestures>
    </RoutedUICommand>      
</Window.Resources>

进行绑定

<Window.CommandBindings>
    <CommandBinding Command="{StaticResource BuildCmd}" Executed="BuildCmdExecuted"/>
</Window.CommandBindings>

并在MenuItem

<MenuItem Command="{StaticResource BuildCmd}"/>

讨论了另一种解决方案here

答案 4 :(得分:7)

我过度偏向Windows.Forms&amp; gulp VB 6,所以我有点agree with JonathanJase,这是一种更简单/程序化的方法来静态连接不是&#的事件处理程序39; t必然CommandBindings。而且,我认为有。

我相信,this MSDN blog post可以在from here中找到使用非CommandBinding处理程序,但强调按钮的好教程。我将提炼并定位MenuItem s ...

创建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);

在窗口中声明您的命令

所以,让我们添加一种&#34;声明&#34;对于HelloWorldCommand我们的窗口,以便我们以后可以使用它。在Window标记内,将命令注册为资源:

<Window.Resources>
    <local:HelloWorldCommand x:Key="hwc"/>
</Window.Resources>

现在我们有了一个简洁的快捷方式来链接到这个&#34;本地命名空间&#34;命令,"hwc",虽然你显然可以使用你想要的任何字符串。我们会在我们的xaml中使用它。

接线(并重复使用!)命令

让我们将MenuItem添加到我们的xaml中。我已经用[{1}}替换了股票Grid,因为这是(对我来说)最简单的方式(等我),等间距的小部件填充了DockPanel,尽管I&I #39;已将我剩下的所有UI留下了。

请注意每个Window声明中都附带了Command="{StaticResource hwc}"。关键是 MenuItem - 请记住,这是我们在hwc级别设置的HelloWorldCommand的快捷方式。当然,Window只是为了查找StaticResource的资源。我们没有约束力;我们只是使用我们的快捷方式。

Window

用于区分事件源的CommandParame

请注意我们为所有内容使用相同的命令!但是我们如何判断哪个小部件引发了该事件?为此,您需要使用<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> - 请记住我们的CommandParameter方法签名:ExecuteExecute(object parameter)参数是我们可以用来知道如何处理事件的参数。尝试运行此操作并注意CommandParameter将使用MessageBox中的任何内容来告知您事件的来源。我们手动完成所有操作,但这并不算太糟糕。

另请注意,您可以使这些对象像您一样复杂。您可以使用CommandParameter标记中的属性来定义参数,也可以使用&#34; real&#34; MenuItem标记,如上面的“打开”菜单项,用于定义复杂的内容。在这种情况下, 我们正在传递整个父<MenuItem.CommandParameter>对象 ,这是抛出我们VB6的最简单(但不是最干净)方式ish context进入事件处理程序代码。

Window添加键盘快捷键(又名&#34;回答OP&#34;)

现在我们终于可以回答原来的问题!让我们最后连接MenuItem菜单项的键盘快捷键。您注意到我们已经宣布了Close。就其本身而言, InputGestureText只是化妆品。如果我们过于挑剔,我们可以说创建键盘快捷键的机制与InputGestureText根本没有任何直接的内在联系!

我们需要代替(或另外)在MenuItem级别注册Ctrl-G的监听器以捕获击键。因此,在Window标签的顶层,插入此内容(基本上采用what's bragged about here):

Window

请注意,您可以将<Window.InputBindings> <KeyBinding Modifiers="Control" Key="G" Command="{StaticResource hwc}" CommandParameter="window input binding" /> </Window.InputBindings> 标记放在CommandParameter中,方法是将其从自动关闭的XML移动到&#34;真实&#34;打开和关闭KeyBinding标签。

我们已经完成了。运行您的应用程序,然后按Ctrl-G。 Whaddup。

非常直截了当,一旦你有了球员的直线,而且比我对大多数对命令和KeyBinding的暗示要少得多的魔术束缚,我认为。

  

可能的专业提示:

     

整个MenuItems事情让我困惑了一段时间。对于特定的命令类型,这只是 ,我相信。也就是说,您无法连接任何您喜欢的CommandBinding。像{{3}}这样的东西(事实上,这是一个不错的介绍教程!)......

     
    

这可能不是很明显,但是通过使用命令,我们可以免费获得大量内容:项目上的键盘快捷键,文本和InputGestureText以及WPF根据活动控件及其自动启用/禁用项目州。在这种情况下,剪切和复制被禁用,因为没有选择文本,但启用了粘贴,因为我的剪贴板不是空的!

  
     

...有点神奇,并不一定好,当您对WPF菜单不熟悉时可能会让人感到困惑。

答案 5 :(得分:1)

这是 PowerShell 中的解决方案:

  1. 定义您的 XAML 文件:
<Window x:Class="WpfApp1.Window1"
    xmlns:local="clr-namespace:WpfApp1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="My App" Height="620" Width="950" >
    <Window.InputBindings>
        <KeyBinding Key="S" Modifiers="Ctrl"/>
    </Window.InputBindings>
    <Grid x:Name="MainGrid">
    <!--Your GUI is here-->
        <Menu Margin="0">
            <MenuItem Header="_File">
                <MenuItem x:Name="SaveProfile" Header="_Save Profile" InputGestureText="Ctrl+S"/>
            </MenuItem>
        </Menu>
    </Grid>
</Window>
  1. 添加新类型以创建命令
Add-Type @"
public class DelegateCommand : System.Windows.Input.ICommand
{
    private System.Action<object> _action;
    public DelegateCommand(System.Action<object> action)
    {
        _action = action;
    }
    public bool CanExecute(object parameter)
    {
        return true;
    }
    public event System.EventHandler CanExecuteChanged = delegate { };
    public void Execute(object parameter)
    {
        _action(parameter);
    }
}
"@
  1. 为之前定义的 KeyBinding 创建和分配新的 Command,它是第一个键绑定,这就是为什么我用 [0] 来解决它。 注意:在我的例子中,我在 $hash.Window 变量中保存了主窗口的句柄,你应该把你的主窗口对象的链接放在这里,你用 [Windows.Markup.XamlReader]::Load($xamlXmlNodeReader) 创建命令或其他窗口创建命令。
$hash.Window.InputBindings[0].Command = New-Object DelegateCommand( { Save-Profile } )
  1. 创建您放入命令中的函数
function Save-Profile {
    Write-Host "Save Profile"
    # Your logic goes here
}

感谢 Nicholas Wolverson 提供有关如何为命令创建类型的提示。

答案 6 :(得分:0)

这对我有用

<ContextMenu  PreviewKeyUp="ContextMenu_PreviewKeyUp">
    <MenuItem Header="Delete"  Click="DeleteID"   />
</ContextMenu>

后面的代码:

private void ContextMenu_PreviewKeyUp(object sender, KeyEventArgs e)
{
    ContextMenu contextMenu = sender as ContextMenu;
    if (e.Key == Key.D)
    {
        //DELETE ID

    }
    contextMenu.IsOpen = false;
}