我知道在使用下划线_
代替&
,但我想了解所有的Ctrl+键盘按键快捷方式。
Ctrl+Z 为撤销,Ctrl+S 为保存,等等。
在WPF应用程序中,是否有一种“标准”方法来实现这些快捷键?还是需要自己编写代码并将其连接到相应的命令/控件?
我知道在使用下划线_
代替&
,但我想了解所有的Ctrl+键盘按键快捷方式。
Ctrl+Z 为撤销,Ctrl+S 为保存,等等。
在WPF应用程序中,是否有一种“标准”方法来实现这些快捷键?还是需要自己编写代码并将其连接到相应的命令/控件?
一种方法是将快捷键添加到命令本身中作为 InputGestures
。 命令实现为RoutedCommands
。
这使得即使没有连接到任何控件,快捷键也能起作用。而且由于菜单项可以理解键盘手势,如果将该命令连接到菜单项,则菜单项将自动在菜单项文本中显示您的快捷键。
创建静态属性来保存命令(最好作为你为命令创建的静态类中的属性,但为了简单起见,只需在window.cs中使用静态属性):
public static RoutedCommand MyCommand = new RoutedCommand();
添加应该调用方法的快捷键:
MyCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
创建一个命令绑定,将其指向要在执行时调用的方法。将它们放置在应该工作的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>
试一下这个。
首先创建一个RoutedCommand对象:
RoutedCommand newCmd = new RoutedCommand();
newCmd.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control));
CommandBindings.Add(new CommandBinding(newCmd, btnNew_Click));
<MenuItem x:Name="loadSheetCommand" Header="Load From _Spreadsheet" Click="loadSheetCommand_Click" InputGestureText="Ctrl+O" />
但这是我目前找到的最简单的解决方案,而且它有效! - Stewart这取决于您想在哪里使用它们。
TextBoxBase
派生控件已经实现了这些快捷方式。如果您想使用自定义键盘快捷键,您应该查看命令和输入手势。这是来自Switch on the Code的一个小教程:WPF 教程 - 命令绑定和自定义命令
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)));
...
}
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'不能用作“Key”的值。数字不是有效的枚举值。
经过进一步搜索,我修改了@aliwa的答案如下:
<Window.InputBindings>
<KeyBinding Gesture="Ctrl+1" Command="{Binding MyCommand}"/>
</Window.InputBindings>
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的方法,但都没有成功。最终,我找到了一个基于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));
}
}
public MainWindow()
{
InitializeComponent();
BindShortcuts();
}
像魔法一样运作。
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));
}
}
}
<TextBox x:Name="SearchTextBox"
Text={Binding Path=SearchText}
local:AttachedProperties.FocusShortcutKey="Ctrl+Q"/>
包括FocusElementCommand实现的完整示例可在gist上找到: https://gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d
免责声明:您可以在任何地方免费使用此代码。请注意,这只是一个示例,不适用于重度使用。例如,由于命令将保持对元素的强引用,因此不会对已删除的元素进行垃圾回收。
特殊情况:如果焦点在“非本地”元素上,则您的快捷方式不会触发。例如,在我的情况下,聚焦于WpfCurrencyTextbox将不会触发在XAML中定义的快捷方式(像oliwa的答案中所定义的那样)。
我通过使用NHotkey包使我的快捷方式全局化来解决此问题。
简而言之,对于XAML,您只需要替换
<KeyBinding Gesture="Ctrl+Alt+Add" Command="{Binding IncrementCommand}" />
由
<KeyBinding Gesture="Ctrl+Alt+Add" Command="{Binding IncrementCommand}"
HotkeyManager.RegisterGlobalHotkey="True" />