WPF中的键盘快捷键

时间:2009-09-01 08:58:22

标签: wpf keyboard-shortcuts

我知道使用_代替&,但我正在查看所有 Ctrl +类型的快捷方式。

Ctrl + Z 用于撤消, Ctrl + S 用于保存等

在WPF应用程序中实现这些是否存在“标准”方式?或者是自己滚动的情况并将它们连接到任何命令/控制?

11 个答案:

答案 0 :(得分:159)

我理解标准方法是创建命令,然后将快捷键作为InputGestures添加到它们。

这使快捷键即使没有连接到任何控件也能工作。由于菜单项了解键盘手势,如果您将该命令挂钩到菜单项,它们将自动在菜单项文本中显示您的快捷键。

  1. 创建静态属性来保存命令(最好是作为为命令创建的静态类中的属性 - 但是对于一个简单的例子,只需在window.cs中使用静态属性):

    public static RoutedCommand MyCommand = new RoutedCommand();
    
  2. 添加应调用方法的快捷键:

    MyCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
    
  3. 创建一个命令绑定,指向要在执行时调用的方法。将它们放在UI元素的命令绑定中(例如,窗口)和方法:

    <Window.CommandBindings>
        <CommandBinding Command="{x:Static local:MyWindow.MyCommand}" Executed="MyCommandExecuted"/>
    </Window.CommandBindings>
    
    private void MyCommandExecuted(object sender, ExecutedRoutedEventArgs e) { ... }
    

答案 1 :(得分:87)

我发现这正是我在寻找与WPF中的键绑定相关的内容:

<Window.InputBindings>
        <KeyBinding Modifiers="Control"
                    Key="N"
                    Command="{Binding CreateCustomerCommand}" />
</Window.InputBindings>

请参阅博客文章 MVVM CommandReference and KeyBinding

答案 2 :(得分:12)

试试这段代码......

首先创建一个RoutedComand对象

  RoutedCommand newCmd = new RoutedCommand();
  newCmd.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control));
  CommandBindings.Add(new CommandBinding(newCmd, btnNew_Click));

答案 3 :(得分:9)

这取决于您想要使用它们的位置。

TextBoxBase - 派生控件已经实现了这些快捷方式。如果要使用自定义键盘快捷键,则应查看“命令”和“输入”手势。以下是启用代码的小教程:WPF Tutorial - Command Bindings and Custom Commands

答案 4 :(得分:4)

为其他人记录这个答案,因为有一种更简单的方法可以做到这一点很少被引用,并且根本不需要触及XAML。

要链接键盘快捷键,请在Window构造函数中添加一个新的KeyBinding到InputBindings集合。作为命令,传入实现ICommand的任意命令类。对于execute方法,只需实现您需要的任何逻辑。在下面的示例中,我的WindowCommand类接受一个委托,它将在每次调用时执行。当我构造新的WindowCommand以传入我的绑定时,我只是在我的初始化器中指出我希望WindowCommand执行的方法。

您可以使用此模式提供自己的快捷键盘快捷键。

public YourWindow() //inside any WPF Window constructor
{
   ...
   //add this one statement to bind a new keyboard command shortcut
   InputBindings.Add(new KeyBinding( //add a new key-binding, and pass in your command object instance which contains the Execute method which WPF will execute
      new WindowCommand(this)
      {
         ExecuteDelegate = TogglePause //REPLACE TogglePause with your method delegate
      }, new KeyGesture(Key.P, ModifierKeys.Control)));
   ...
}

创建一个简单的WindowCommand类,它接受一个执行委托来触发任何设置的方法。

public class WindowCommand : ICommand
{
    private MainWindow _window;

    //Set this delegate when you initialize a new object. This is the method the command will execute. You can also change this delegate type if you need to.
    public Action ExecuteDelegate { get; set; }

    //You don't have to add a parameter that takes a constructor. I've just added one in case I need access to the window directly.
    public WindowCommand(MainWindow window)
    {
        _window = window;
    }

    //always called before executing the command, mine just always returns true
    public bool CanExecute(object parameter)
    {
        return true; //mine always returns true, yours can use a new CanExecute delegate, or add custom logic to this method instead.
    }

    public event EventHandler CanExecuteChanged; //i'm not using this, but it's required by the interface

    //the important method that executes the actual command logic
    public void Execute(object parameter)
    {
        if (ExecuteDelegate != null)
        {
            ExecuteDelegate();
        }
        else
        {
            throw new InvalidOperationException();
        }
    }
}

答案 5 :(得分:3)

我有类似的问题,发现@ aliwa的答案是最有帮助和最优雅的解决方案;但是,我需要一个特定的组合键, Ctrl + 1 。不幸的是我收到了以下错误:

  

'1'不能用作'Key'的值。数字不是有效的枚举值。

通过进一步搜索,我修改了@ aliwa对以下内容的回答:

<Window.InputBindings>
    <KeyBinding Gesture="Ctrl+1" Command="{Binding MyCommand}"/>
</Window.InputBindings>

我发现这很适合我需要的任何组合。

答案 6 :(得分:2)

VB.NET:

Public Shared SaveCommand_AltS As New RoutedCommand

加载的事件中:

SaveCommand_AltS.InputGestures.Add(New KeyGesture(Key.S, ModifierKeys.Control))

Me.CommandBindings.Add(New CommandBinding(SaveCommand_AltS, AddressOf Me.save))

不需要XAML。

答案 7 :(得分:1)

尽管最正确的答案是正确的,但我个人还是希望使用附加属性来使解决方案适用于任何UIElement,尤其是在Window不知道应该使用的元素的情况下。专注。以我的经验,我经常看到由几个视图模型和用户控件组成的视图,其中窗口通常只不过是根容器。

摘要

public sealed class AttachedProperties
{
    // Define the key gesture type converter
    [System.ComponentModel.TypeConverter(typeof(System.Windows.Input.KeyGestureConverter))]
    public static KeyGesture GetFocusShortcut(DependencyObject dependencyObject)
    {
        return (KeyGesture)dependencyObject?.GetValue(FocusShortcutProperty);
    }

    public static void SetFocusShortcut(DependencyObject dependencyObject, KeyGesture value)
    {
        dependencyObject?.SetValue(FocusShortcutProperty, value);
    }

    /// <summary>
    /// Enables window-wide focus shortcut for an <see cref="UIElement"/>.
    /// </summary>
    // Using a DependencyProperty as the backing store for FocusShortcut.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FocusShortcutProperty =
        DependencyProperty.RegisterAttached("FocusShortcut", typeof(KeyGesture), typeof(AttachedProperties), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(OnFocusShortcutChanged)));

    private static void OnFocusShortcutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is UIElement element) || e.NewValue == e.OldValue)
            return;

        var window = FindParentWindow(d);
        if (window == null)
            return;

        var gesture = GetFocusShortcut(d);
        if (gesture == null)
        {
            // Remove previous added input binding.
            for (int i = 0; i < window.InputBindings.Count; i++)
            {
                if (window.InputBindings[i].Gesture == e.OldValue && window.InputBindings[i].Command is FocusElementCommand)
                    window.InputBindings.RemoveAt(i--);
            }
        }
        else
        {
            // Add new input binding with the dedicated FocusElementCommand.
            // see: https://gist.github.com/shuebner20/349d044ed5236a7f2568cb17f3ed713d
            var command = new FocusElementCommand(element);
            window.InputBindings.Add(new InputBinding(command, gesture));
        }
    }
}

使用此附加属性,您可以为任何UIElement定义焦点快捷方式。它将自动在包含该元素的窗口中注册输入绑定。

用法(XAML)

<TextBox x:Name="SearchTextBox"
         Text={Binding Path=SearchText}
         local:AttachedProperties.FocusShortcutKey="Ctrl+Q"/>

源代码

包含FocusElementCommand实现的完整示例可作为要点:https://gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d

免责声明:您可以在任何地方免费使用此代码。请记住,这是不适合大量使用的示例。例如,由于Command将保留对该元素的强烈引用,因此不会对已删除的元素进行垃圾回收。

答案 8 :(得分:0)

特殊情况:如果焦点位于“非本机”元素上,则快捷方式不会触发。以我为例,专注于WpfCurrencyTextbox不会触发XAML中定义的快捷方式(就像oliwa的答案中定义的那样)。

我通过使用NHotkey软件包将快捷方式设置为全局来解决此问题。

简而言之,对于XAML,您所需要做的就是替换

<KeyBinding Gesture="Ctrl+Alt+Add" Command="{Binding IncrementCommand}" />

作者

<KeyBinding Gesture="Ctrl+Alt+Add" Command="{Binding IncrementCommand}"
            HotkeyManager.RegisterGlobalHotkey="True" />

答案也已发布到:How can I register a global hot key to say CTRL+SHIFT+(LETTER) using WPF and .NET 3.5?

答案 9 :(得分:0)

我使用 XAML 尝试了各种方法,但没有任何效果。我终于根据 Shahid Neermunda 证明的答案找到了解决方案

一、菜单栏:

<Menu x:Name="MainMenuBar" Grid.Row="0" HorizontalContentAlignment="Left">
    <MenuItem Header="_File" HorizontalContentAlignment="Left">
        <MenuItem x:Name="NewProjectMenuItem"
                    Header="New Project"
                    InputGestureText="Ctrl+N"
                    Click="NewProject_Click"/>
        <MenuItem x:Name="OpenProjectMenuItem"
                    Header="Open Project"
                    InputGestureText="Ctrl+O"
                    Click="OpenProject_Click"/>
        <MenuItem x:Name="CloseProjectMenuItem"
                    Header="Close Project"
                    Click="CloseProject_Click"/>
        <Separator/>
        <MenuItem x:Name="SaveProjectMenuItem"
                    Header="Save Project"
                    InputGestureText="Ctrl+S"
                    Click="SaveProject_Click"/>
        <MenuItem x:Name="SaveProjectAsMenuItem"
                    Header="Save Project As ..."
                    InputGestureText="Shift+Ctrl+S"
                    Click="SaveProjectAs_Click"/>
        <Separator/>
        <MenuItem x:Name="ExitMenuItem"
                    Header="Exit"
                    InputGestureText="Alt+F4"
                    Click="Exit_Click"/>
    </MenuItem>
</Menu>

没什么特别的。每个菜单项都有一个“InputGestureText”属性(关闭除外)

然后我修改了由 Click="[tab]" 命令自动生成的点击事件方法。我在这里只展示了两个——一个定义了快捷键,另一个没有定义(关闭):

private void OpenProject_Executed(object sender, ExecutedRoutedEventArgs e) => OpenProject_Click(sender, e);
private void OpenProject_Click(object sender, RoutedEventArgs e)
{
    OpenProject();
}

private void CloseProject_Click(object sender, RoutedEventArgs e)
{
    CloseProject();
}

XXX_Executed(...) 方法由快捷方式绑定调用(我将在接下来介绍),而 XXX_Click 方法由 Click 命令调用。

我对 New Project、Open Project、Save Project As 和 Exit 自动生成的 XXX_Click 方法做了同样的处理。

然后我创建了一个包含绑定的新文件(我将其分离出来以便在添加其他绑定时更容易找到):

partial class MainWindow
{
    private void BindShortcuts()
    {
        BindShortcut(Key.N, ModifierKeys.Control, NewProject_Executed);
        BindShortcut(Key.O, ModifierKeys.Control, OpenProject_Executed);
        BindShortcut(Key.S, ModifierKeys.Control, SaveProject_Executed);
        BindShortcut(Key.S, ModifierKeys.Control | ModifierKeys.Shift, SaveProjectAs_Executed);
        BindShortcut(Key.F4, ModifierKeys.Alt, Exit_Executed);
    }

    private void BindShortcut(Key key, ModifierKeys modifiers, ExecutedRoutedEventHandler executed)
    {
        RoutedCommand cmd = new();
        _ = cmd.InputGestures.Add(new KeyGesture(key, modifiers));
        _ = CommandBindings.Add(new CommandBinding(cmd, executed));
    }
}

这样,当我添加附加了更多快捷方式的新菜单项时,我只需要添加适当的 标签,定义一个 XXX_Executed 方法来调用自动生成的 XXX_Click 方法,并更新BindShortcuts() 函数。

最后,我在 MainWindow 类的构造函数中添加了以下内容:

public MainWindow()
{
    InitializeComponent();
    BindShortcuts();
}

就像一个魅力。

答案 10 :(得分:-2)

如何将命令与MenuItem关联:

<MenuItem Header="My command" Command="{x:Static local:MyWindow.MyCommand}"/>
相关问题