WPF 中的键盘快捷键

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

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

在 WPF 应用程序中是否有实现这些的“标准”方法?还是你自己动手,把它们连接到任何命令/控制系统?

137745 次浏览

这取决于你想在哪里使用它们。

派生于 TextBoxBase的控件已经实现了这些快捷方式。如果你想使用自定义键盘快捷键,你应该看看命令和输入手势。下面是一个来自 打开密码: WPF 教程-命令绑定和自定义命令的小教程

一种方法是将快捷键作为 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)
    { ... }
    

我发现这正是我所寻找的与 WPF 中的密钥绑定相关的内容:

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

见博客文章 Rel = “ noReferrer”> MVVM CommandReference and KeyBinding

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。

如何将命令与 MenuItem关联:

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

试试这个。

首先创建一个 RoutedCommand 对象:

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

为其他人记录这个答案,因为有一种更简单的方法可以做到这一点,这种方法很少被引用,而且根本不需要涉及 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();
}
}
}

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

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

经过进一步的搜索,我修改了@aliwa 给出的答案:

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

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

尽管前面的答案是正确的,但是我个人喜欢使用附加属性来使解决方案能够应用于任何 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 实现的完整示例可以作为 gist 获得: https://gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d

免责声明: 您可以在任何地方免费使用此代码。请记住,这是一个样品,不适合大量使用。例如,没有对已移除元素的垃圾收集,因为 Command 将保存对该元素的强引用。

特殊情况: 如果焦点位于“非本机”的元素上,则快捷方式不会触发。例如,在我的例子中,对 WpfCurrencyTextbox的关注不会触发 XAML 中定义的快捷方式(定义类似于奥利瓦的答案)。

我通过使用 NHotkey 包使我的快捷方式全局化来解决这个问题。

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

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

作者

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

答案也已张贴到: 如何使用 WPF 和.NET 3.5注册一个全局热键来表示 CTRL + SHIFT + (LETTER) ?

我尝试了各种使用 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 ]”命令自动生成的 Click 事件方法。这里我只展示了两个——一个定义了快捷键,另一个没有(Close) :

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 _ Execated (...)方法由快捷绑定调用(我将在下面讨论) ,XXX _ Click 方法由 Click 命令调用。

我对 New Project、 Open Project、 SaveProjectAs 和 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));
}
}

这样,当我添加带有更多快捷方式的新菜单项时,我只需要添加适当的 < MenuItem.../> 标记,定义一个 XXX _ Exected 方法来调用自动生成的 XXX _ Click 方法,并更新 BindShortcut ()函数。

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

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

非常有效。