WPF中的键盘快捷键


129

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

Ctrl+ Z表示撤消,Ctrl+ S表示保存等。

是否有在WPF应用程序中实现这些的“标准”方法?还是自己动手将它们连接到任何命令/控件的情况?

Answers:


170

一种方法是将快捷键本身添加为命令InputGestures。命令实现为RoutedCommands

即使快捷键没有连接到任何控件,这也可以使它们起作用。并且由于菜单项可以理解键盘手势,因此,如果您将该命令挂接到菜单项上,它们将自动在菜单项文本中显示您的快捷键。

  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) { ... }
    

4
如何将命令与菜单项相关联?当然,这将是包含在此答案中的最重要的信息,但是缺少它。
Timwi

8
@Timwi:我已经以这种方式使用上面的代码向现有事件添加了键盘快捷键:RoutedCommand cmndSettings = new RoutedCommand(); cmndSettings.InputGestures.Add(new KeyGesture(Key.S,ModifierKeys.Control)); CommandBindings.Add(新的CommandBinding(cmndSettings,mnuSettings_Click));
itsho 2012年

1
itsho的注释对我来说很有效,无法使上面的xml代码起作用。
gosr 2012年

1
不幸的是,与Executed使用常规命令(自定义ICommand实现)相反,使用这种方法后,该命令的代码将最终位于(窗口或用户控件的)代码背后(而不是视图模型中)。
OR Mapper 2014年


97

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

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

请参阅博客文章MVVM CommandReference和KeyBinding


非常好,很容易!
合并

1
您介意“ CreateCustomerCommand”是什么以及如何实现它吗?
Vinz

这仍然是仅链接的答案,因为复制和粘贴的代码片段在链接的博客文章中用“结果将是异常”进行描述。:P
Martin Schneider

作品惊叹于此。我首先尝试在按钮内容的键之前添加“ _”,例如OP,但是它不起作用。最糟糕的是,当我不专注于界面的可写对象时,当我按下按键本身时,它就会激活。
周杰伦

14

试试这个代码...

首先创建一个RoutedComand对象

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

9

这取决于您要在哪里使用它们。

TextBoxBase派生的控件已经实现了这些快捷方式。如果要使用自定义键盘快捷键,则应查看“命令”和“输入”手势。这是Switch on the Code中的一本小教程:WPF教程-命令绑定和自定义命令


8
多么糟糕的教程—并没有解释绝对最重要的事情,即如何使用一个并非恰好是其预定义的20个“常用”命令之一的命令。
Timwi'2

6

为其他人记录此答案,因为这样做的方法非常简单,很少被引用,并且完全不需要接触XAML。

要链接键盘快捷键,只需在Window构造函数中向InputBindings集合添加一个新的KeyBinding。作为命令,传入实现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

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

不能将“ 1”用作“键”的值。数字不是有效的枚举值。

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

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

我发现此方法非常适合我需要的任何组合。


这对我<UserControl.InputBindings> <KeyBinding Gesture="Enter" Command="{Binding someCommand}"/> </UserControl.InputBindings>
有用-fs_tigre

3

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。


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将拥有对该元素的强烈引用。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.