<Grid x:Name="Container" Padding="30">
<Button Content="Save"
Click="OnSave"
KeyboardAcceleratorPlacementMode="Auto"
KeyboardAcceleratorPlacementTarget="{x:Bind Container}">
<Button.KeyboardAccelerators>
<KeyboardAccelerator Key="S" Modifiers="Control" />
</Button.KeyboardAccelerators>
</Button>
</Grid>
在某些情况下,我们建议使用控件的标签来标识控件是否具有关联的键盘快捷键,如果是,那么快捷键组合是什么。
默认情况下,某些平台控件会执行此操作,特别是 MenuFlyoutItem 和 ToggleMenuFlyoutItem 对象,而 AppBarButton 和 AppBarToggleButton 会在命令栏的溢出菜单中显示时执行此操作。
菜单项标签中所述的键盘快捷键
可以通过 MenuFlyoutItem、ToggleMenuFlyoutItem、AppBarButton 和 AppBarToggleButton 控件的 KeyboardAcceleratorTextOverride 属性替代标签的默认快捷键文本(对无文本使用单个空格)。
如果系统无法检测到附加的键盘,则不会显示替代文本(可以通过 KeyboardPresent 属性自行检查)。
在这里,我们回顾了键盘加速器的一些低级别方面。
输入事件在特定序列中发生,你可以根据应用的要求截获和处理这些事件。
KeyDown/KeyUp 冒泡事件
在 XAML 中,将像只有一个输入冒泡管道一样处理击键。 KeyDown/KeyUp 事件和字符输入使用此输入管道。 例如,如果元素具有焦点,并且用户按下某个键,则会在元素上引发 KeyDown 事件,后跟元素的父级,依此树向上,直到参数。句柄属性为 true。
KeyDown 事件也由某些控件用来实现内置控件加速器。 当控件具有键盘快捷键时,它将处理 KeyDown 事件,这意味着不会发生 KeyDown 事件冒泡。 例如,RichEditBox 支持使用 Ctrl+C 进行复制。 按下 Ctrl 时,将触发 KeyDown 事件并引发气泡,但当用户同时按 C 时,KeyDown 事件将标记为 Handled 且不会引发(除非 UIElement.AddHandler 的 handledEventsToo 参数设置为 true)。
CharacterReceived 事件
由于在 TextBox 等文本控件的 KeyDown 事件后触发 CharacterReceived 事件,因此可以在 KeyDown 事件处理程序中取消字符输入。
PreviewKeyDown 和 PreviewKeyUp 事件
预览输入事件在任何其他事件之前触发。 如果不处理这些事件,则会触发具有焦点的元素的加速器,后跟 KeyDown 事件。 这两个事件在处理之前会冒泡。
键事件序列
事件的顺序:
预览 KeyDown 事件
应用加速键
OnKeyDown 方法
KeyDown 事件
父项上的应用加速键
父项上的 OnKeyDown 方法
父项上的 KeyDown 事件
(浮升至根)
CharacterReceived 事件
PreviewKeyUp 事件
KeyUp 事件
处理加速器事件时,KeyDown 事件也会标记为已处理。 KeyUp 事件保持不变。
解析加速器
键盘快捷键事件从具有焦点到根的元素中冒泡。 如果未处理该事件,XAML 框架将查找浮泡路径之外的其他未范围应用加速器。
使用同一键组合定义两个键盘快捷键时,将调用在可视化树上找到的第一个键盘快捷键。
仅当焦点位于特定作用域内时,才会调用限定范围的键盘加速器。 例如,在包含数十个控件的网格中,仅当焦点位于 Grid(范围所有者)内时,才能为控件调用键盘快捷键。
以编程方式限定加速键的范围
UIElement.TryInvokeKeyboardAccelerator 方法调用元素的子树中的任何匹配加速器。
UIElement.OnProcessKeyboardAccelerators 方法在键盘加速器之前执行。 此方法传递一个 ProcessKeyboardAcceleratorArgs 对象,该对象包含键、修饰符和一个布尔值,该对象指示是否处理键盘加速器。 如果标记为已处理,键盘快捷键将气泡(因此,永远不会调用外部键盘快捷键)。
OnProcessKeyboardAccelerators 始终触发(是否处理(类似于 OnKeyDown 事件)。 必须检查事件是否已标记为已处理。
在此示例中,我们使用 OnProcessKeyboardAccelerators 和 TryInvokeKeyboardAccelerator 将键盘加速器限定为 Page 对象:
protected override void OnProcessKeyboardAccelerators(
ProcessKeyboardAcceleratorArgs args)
if(args.Handled != true)
this.TryInvokeKeyboardAccelerator(args);
args.Handled = true;
本地化加速器
建议本地化所有键盘加速器。 你可以使用标准资源 (.resw) 文件和 XAML 声明中的 X:uid 属性来执行此操作。 在此示例中,Windows 运行时会自动加载资源。
使用资源文件的键盘加速器本地化
<Button x:Uid="myButton" Click="OnSave">
<Button.KeyboardAccelerators>
<KeyboardAccelerator x:Uid="myKeyAccelerator" Modifiers="Control"/>
</Button.KeyboardAccelerators>
</Button>
键盘快捷键作为虚拟键实现。 必须从虚拟密钥代码的预定义集合中选择本地化加速器(否则,将发生 XAML 分析器错误)。
以编程方式设置加速器
下面是以编程方式定义加速器的示例:
void AddAccelerator(
VirtualKeyModifiers keyModifiers,
VirtualKey key,
TypedEventHandler<KeyboardAccelerator, KeyboardAcceleratorInvokedEventArgs> handler )
var accelerator =
new KeyboardAccelerator()
Modifiers = keyModifiers, Key = key
accelerator.Invoked += handler;
this.KeyboardAccelerators.Add(accelerator);
KeyboardAccelerator 不可共享,无法将同一 KeyboardAccelerator 添加到多个元素。
替代键盘快捷键行为
可以处理 KeyboardAccelerator.Invoked 事件以替代默认的 KeyboardAccelerator 行为。
此示例演示如何在自定义 ListView 控件中重写“全选”命令(Ctrl+A 键盘快捷键)。 我们还将 Handled 属性设置为 true 以进一步停止事件冒泡。
public class MyListView : ListView
protected override void OnKeyboardAcceleratorInvoked(KeyboardAcceleratorInvokedEventArgs args)
if(args.Accelerator.Key == VirtualKey.A
&& args.Accelerator.Modifiers == KeyboardModifiers.Control)
CustomSelectAll(TypeOfSelection.OnlyNumbers);
args.Handled = true;
VirtualKey 枚举
WinUI 库