wpf 如何显示菜单项的工作键盘快捷键?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21972243/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Display Working Keyboard Shortcut for Menu Items?
提问by O. R. Mapper
I am trying to create a localizable WPF menu bar with menu items that have keyboard shortcuts - notaccelerator keys/mnemonics (usually shown as underlined characters that can be pressed to directly select a menu item when the menu is already open), but keyboard shortcuts (usually combinations of Ctrl+ another key) that are displayed right-aligned next to the menu item header.
我正在尝试使用具有键盘快捷键的菜单项创建一个可本地化的 WPF 菜单栏 -不是加速键/助记符(通常显示为带下划线的字符,当菜单已经打开时,可以按下这些字符直接选择菜单项),而是键盘快捷键(通常是Ctrl+ 的组合another key)在菜单项标题旁边右对齐显示。
I am using the MVVM pattern for my application, meaning that I avoid placing any code in code-behind wherever possible and have my view-models (that I assign to the DataContextproperties) provide implementations of the ICommandinterfacethat are used by controls in my views.
我在我的应用程序中使用 MVVM 模式,这意味着我尽可能避免在代码隐藏中放置任何代码,并让我的视图模型(我分配给DataContext属性)提供由我的视图中的控件使用的ICommand接口的实现.
As a base for reproducing the issue, here is some minimal source code for an application as described:
作为重现问题的基础,以下是所描述的应用程序的一些最小源代码:
Window1.xaml
窗口1.xaml
<Window x:Class="MenuShortcutTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuShortcutTest" Height="300" Width="300">
<Menu>
<MenuItem Header="{Binding MenuHeader}">
<MenuItem Header="{Binding DoSomethingHeader}" Command="{Binding DoSomething}"/>
</MenuItem>
</Menu>
</Window>
Window1.xaml.cs
Window1.xaml.cs
using System;
using System.Windows;
namespace MenuShortcutTest
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
}
}
MainViewModel.cs
主视图模型.cs
using System;
using System.Windows;
using System.Windows.Input;
namespace MenuShortcutTest
{
public class MainViewModel
{
public string MenuHeader {
get {
// in real code: load this string from localization
return "Menu";
}
}
public string DoSomethingHeader {
get {
// in real code: load this string from localization
return "Do Something";
}
}
private class DoSomethingCommand : ICommand
{
public DoSomethingCommand(MainViewModel owner)
{
if (owner == null) {
throw new ArgumentNullException("owner");
}
this.owner = owner;
}
private readonly MainViewModel owner;
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
// in real code: do something meaningful with the view-model
MessageBox.Show(owner.GetType().FullName);
}
public bool CanExecute(object parameter)
{
return true;
}
}
private ICommand doSomething;
public ICommand DoSomething {
get {
if (doSomething == null) {
doSomething = new DoSomethingCommand(this);
}
return doSomething;
}
}
}
}
The WPF MenuItemclasshas an InputGestureTextproperty, but as described in SO questions such as this, this, thisand this, that is purely cosmetic and has no effect whatsoever on what shortcuts are actually processed by the application.
在WPFMenuItem类有一个InputGestureText属性,但比如在做题描述这个,这个,这个和这个,纯粹是化妆品和任何有什么快捷方式实际上是由应用程序处理没有影响。
SO questions like thisand thispoint out that the command should be linked with a KeyBindingin the InputBindingslist of the window. While that enables the functionality, it does not automatically display the shortcut with the menu item. Window1.xamlchanges as follows:
SO问题,如这和这人指出,该命令应与被链接KeyBinding在InputBindings窗口的列表中。虽然启用了该功能,但它不会自动显示菜单项的快捷方式。Window1.xaml变化如下:
<Window x:Class="MenuShortcutTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuShortcutTest" Height="300" Width="300">
<Window.InputBindings>
<KeyBinding Key="D" Modifiers="Control" Command="{Binding DoSomething}"/>
</Window.InputBindings>
<Menu>
<MenuItem Header="{Binding MenuHeader}">
<MenuItem Header="{Binding DoSomethingHeader}" Command="{Binding DoSomething}"/>
</MenuItem>
</Menu>
</Window>
I have tried manually setting the InputGestureTextproperty in addition, making Window1.xamllook like this:
InputGestureText此外,我还尝试手动设置属性,使Window1.xaml看起来像这样:
<Window x:Class="MenuShortcutTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuShortcutTest" Height="300" Width="300">
<Window.InputBindings>
<KeyBinding Key="D" Modifiers="Control" Command="{Binding DoSomething}"/>
</Window.InputBindings>
<Menu>
<MenuItem Header="{Binding MenuHeader}">
<MenuItem Header="{Binding DoSomethingHeader}" Command="{Binding DoSomething}" InputGestureText="Ctrl+D"/>
</MenuItem>
</Menu>
</Window>
This does display the shortcut, but is not a viable solution for obvious reasons:
这确实显示了快捷方式,但由于显而易见的原因,这不是一个可行的解决方案:
- It does not update when the actual shortcut binding changes, so even if the shortcuts are not configurable by users, this solution is a maintenance nightmare.
- The text needs to be localized (as e.g. the Ctrlkey has different names in some languages), so if any of the shortcuts is ever changed, alltranslations would need to be updated individually.
- 它不会在实际快捷方式绑定更改时更新,因此即使用户无法配置快捷方式,此解决方案也是维护噩梦。
- 文本需要本地化(例如,Ctrl键在某些语言中具有不同的名称),因此如果任何快捷方式发生更改,则所有翻译都需要单独更新。
I have looked into creating an IValueConverterto use for binding the InputGestureTextproperty to the InputBindingslist of the window (there might be more than one KeyBindingin the InputBindingslist, or none at all, so there is no specific KeyBindinginstance that I could bind to (if KeyBindingeven lends itself to being a binding target)). This appears to me like the most desirable solution, because it is very flexible and at the same time very clean (it does not require a plethora of declarations in various places), but on the one hand, InputBindingCollectiondoes not implement INotifyCollectionChanged, thus the binding would not be updated when shortcuts are replaced, and on the other hand, I did not manage to provide the converter with a reference to my view-model in a tidy manner (which it would need to access the localization data). What is more, InputBindingsis not a dependency property, so I cannot bind that to a common source (such as a list of input bindings located in the view-model) that the ItemGestureTextproperty could be bound to, as well.
我特地到创建一个IValueConverter用于绑定InputGestureText属性设置InputBindings窗口的列表(可能有不止一个KeyBinding的InputBindings列表,或根本没有,所以没有具体的KeyBinding,我可以绑定到(如果实例KeyBinding甚至使其本身成为绑定目标))。这在我看来是最理想的解决方案,因为它非常灵活,同时又非常干净(它不需要在各个地方进行过多的声明),但一方面,InputBindingCollection它没有实现INotifyCollectionChanged,因此在替换快捷方式时不会更新绑定,另一方面,我没有设法以整洁的方式向转换器提供对我的视图模型的引用(它需要访问本地化数据) . 更重要的是,InputBindings它不是依赖属性,因此我无法将其绑定到该属性也可以绑定到的公共源(例如位于视图模型中的输入绑定列表)ItemGestureText。
Now, many resources (this question, that question, this thread, that questionand that threadpoint out that RoutedCommandand RoutedUICommandcontain a built-in InputGesturespropertyand imply that key bindings from that property are automatically displayed in menu items.
现在,许多资源(这个问题、那个问题、这个线程、那个问题和那个线程指出RoutedCommand并RoutedUICommand包含一个内置InputGestures属性并暗示来自该属性的键绑定会自动显示在菜单项中。
However, using either of those ICommandimplementations seems to open a new can of worms, as their Executeand CanExecutemethods are not virtual and thus cannot be overridden in subclasses to fill in the desired functionality. The only way to provide that seems to be declaring a CommandBindingin XAML (shown e.g. hereor here) that connects a command with an event handler - however, that event handler would then be located in the code-behind, thus violating the MVVM architecture described above.
然而,使用这些ICommand实现中的任何一个似乎都打开了一个新的蠕虫罐,因为它们的Execute和CanExecute方法不是虚拟的,因此不能在子类中覆盖以填充所需的功能。提供这一点的唯一方法似乎是CommandBinding在 XAML(例如此处或此处显示)中声明一个将命令与事件处理程序连接起来的 - 但是,该事件处理程序随后将位于代码隐藏中,从而违反了所描述的 MVVM 架构以上。
Trying nonetheless, this means turning most of the aforementioned structure inside-out (which also kind of implies that I need to make my mind up on how to eventually solve the issue in my current, comparably early stage of development):
尽管如此,这意味着将大部分上述结构由内而外(这也意味着我需要决定如何最终解决我当前相对早期的开发阶段的问题):
Window1.xaml
窗口1.xaml
<Window x:Class="MenuShortcutTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MenuShortcutTest"
Title="MenuShortcutTest" Height="300" Width="300">
<Window.CommandBindings>
<CommandBinding Command="{x:Static local:DoSomethingCommand.Instance}" Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
<Menu>
<MenuItem Header="{Binding MenuHeader}">
<MenuItem Header="{Binding DoSomethingHeader}" Command="{x:Static local:DoSomethingCommand.Instance}"/>
</MenuItem>
</Menu>
</Window>
Window1.xaml.cs
Window1.xaml.cs
using System;
using System.Windows;
namespace MenuShortcutTest
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
void CommandBinding_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
{
((MainViewModel)DataContext).DoSomething();
}
}
}
MainViewModel.cs
主视图模型.cs
using System;
using System.Windows;
using System.Windows.Input;
namespace MenuShortcutTest
{
public class MainViewModel
{
public string MenuHeader {
get {
// in real code: load this string from localization
return "Menu";
}
}
public string DoSomethingHeader {
get {
// in real code: load this string from localization
return "Do Something";
}
}
public void DoSomething()
{
// in real code: do something meaningful with the view-model
MessageBox.Show(this.GetType().FullName);
}
}
}
DoSomethingCommand.cs
做某事命令.cs
using System;
using System.Windows.Input;
namespace MenuShortcutTest
{
public class DoSomethingCommand : RoutedCommand
{
public DoSomethingCommand()
{
this.InputGestures.Add(new KeyGesture(Key.D, ModifierKeys.Control));
}
private static Lazy<DoSomethingCommand> instance = new Lazy<DoSomethingCommand>();
public static DoSomethingCommand Instance {
get {
return instance.Value;
}
}
}
}
For the same reason (RoutedCommand.Executeand such being non-virtual), I do not know how to subclass RoutedCommandin a way to create a RelayCommandlike the one used in an answer to this questionbased on RoutedCommand, so I do not have to make the detour over the InputBindingsof the window - while explicitly reimplementing the methods from ICommandin a RoutedCommandsubclass feels like I might be breaking something.
出于同样的原因(RoutedCommand.Execute并且是非虚拟的),我不知道如何以RoutedCommand某种方式创建子类以创建RelayCommand类似于基于 的这个问题的答案中使用的方法RoutedCommand,因此我不必绕道而行InputBindings窗口 -ICommand在RoutedCommand子类中显式重新实现方法时,感觉就像我可能会破坏某些东西。
What is more, while the shortcut is automatically displayed with this method as configured in the RoutedCommand, it does not seem to get automatically localized. My understanding is that adding
此外,虽然快捷方式会按照 中的配置使用此方法自动显示RoutedCommand,但它似乎并未自动本地化。我的理解是添加
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de-de");
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentCulture;
to the MainWindowconstructor should make sure that localizable strings supplied by the framework should be taken from the German CultureInfo- however, Ctrldoes not change to Strg, so unless I am mistaken about how to set the CultureInfofor framework-supplied strings, this method is not viable anyway if I expect the displayed shortcut to be correctly localized.
到MainWindow构造函数应确保框架提供的可本地化字符串应取自德语CultureInfo- 但是,Ctrl不会更改为Strg,因此除非我对如何设置CultureInfo框架提供的字符串有误,否则此方法无论如何都不可行,如果我希望显示的快捷方式能够正确本地化。
Now, I am aware that KeyGestureallows me to specify a custom display string for the keyboard shortcut, but not only is the RoutedCommand-derived DoSomethingCommandclass disjoint from all of my instances (from where I could get in touch with the loaded localization) due to the way CommandBindinghas to be linked with a command in XAML, the respective DisplayStringpropertyis read-only, so there would be no way to change it when another localization is loaded at runtime.
现在,我知道这KeyGesture允许我为键盘快捷键指定一个自定义显示字符串,但不仅 -RoutedCommand派生DoSomethingCommand类与我的所有实例(从那里我可以接触加载的本地化)不相交的方式CommandBinding必须与 XAML 中的命令链接,相应的DisplayString属性是只读的,因此在运行时加载另一个本地化时将无法更改它。
This leaves me with the option to manually dig through the menu tree (EDIT: for the sake of clarification, no code here because I am not asking for this and I know how to do this) and the InputBindingslist of the window to check which commands have any KeyBindinginstances associated with them, and which menu items are linked to any of those commands, so that I can manually set the InputGestureTextof each of the respective menu items to reflect the first (or preferred, by whichever metric I want to use here) keyboard shortcut. And this procedure would have to be repeated every time I think the key bindings may have changed. However, this seems like an extremely tedious workaround for something that is essentially a basic feature of a menu bar GUI, so I'm convinced it cannot be the "correct" way to do this.
这让我可以选择手动挖掘菜单树(编辑:为了澄清起见,这里没有代码,因为我不是要求这个,我知道如何做到这一点)和InputBindings窗口列表来检查哪些命令有KeyBinding与它们关联的任何实例,以及哪些菜单项链接到任何这些命令,以便我可以手动设置InputGestureText每个相应菜单项的 以反映第一个(或首选,我想在这里使用的任何指标)键盘快捷键。每次我认为键绑定可能已更改时,都必须重复此过程。但是,对于本质上是菜单栏 GUI 的基本功能的某些内容,这似乎是一种极其繁琐的解决方法,因此我确信这不是执行此操作的“正确”方法。
What is the right way to automatically display a keyboard shortcut that is configured to work for WPF MenuIteminstances?
自动显示配置为适用于 WPFMenuItem实例的键盘快捷键的正确方法是什么?
EDIT: All of the other questions I found dealt with how a KeyBinding/KeyGesturecould be used to actually enable the functionality visually implied by InputGestureText, without explaining how to automatically link the two aspects in the described situation. The only somewhat promising question that I found was this, but it has not received any answers in over two years.
编辑:我发现的所有其他问题都涉及如何使用KeyBinding/KeyGesture来实际启用InputGestureText. 我发现的唯一有点有希望的问题是this,但两年多来没有收到任何答案。
采纳答案by Pavel Voronin
I'll start with the warning. It can happen that you will need not only customizable hot keys but the menu itself. So think twice before using InputBindingsstatically.
There is one more caution concerning InputBindings: they imply that command is tied to the element in window's visual tree. Sometimes you need global hot keys not connected with any particular window.
我将从警告开始。您可能不仅需要可自定义的热键,还需要菜单本身。所以在InputBindings静态使用之前要三思。
还有一个关于 的警告InputBindings:它们暗示命令与窗口的可视化树中的元素相关联。有时您需要不与任何特定窗口连接的全局热键。
The above said means that you can make it another way and implement your own application wide gestures processing with correct routing to corresponding commands (don't forget to use weak references to commands).
上面说的意思是你可以用另一种方式来实现你自己的应用程序范围的手势处理,并正确路由到相应的命令(不要忘记对命令使用弱引用)。
Nonetheless the idea of gesture aware commands is the same.
尽管如此,手势感知命令的想法是相同的。
public class CommandWithHotkey : ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
MessageBox.Show("It Worked!");
}
public KeyGesture Gesture { get; set; }
public string GestureText
{
get { return Gesture.GetDisplayStringForCulture(CultureInfo.CurrentUICulture); }
}
public string Text { get; set; }
public event EventHandler CanExecuteChanged;
public CommandWithHotkey()
{
Text = "Execute Me";
Gesture = new KeyGesture(Key.K, ModifierKeys.Control);
}
}
Simple View Model:
简单视图模型:
public class ViewModel
{
public ICommand Command { get; set; }
public ViewModel()
{
Command = new CommandWithHotkey();
}
}
Window:
窗户:
<Window x:Class="CommandsWithHotKeys.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:commandsWithHotKeys="clr-namespace:CommandsWithHotKeys"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<commandsWithHotKeys:ViewModel/>
</Window.DataContext>
<Window.InputBindings>
<KeyBinding Command="{Binding Command}" Key ="{Binding Command.Gesture.Key}" Modifiers="{Binding Command.Gesture.Modifiers}"></KeyBinding>
</Window.InputBindings>
<Grid>
<Menu HorizontalAlignment="Stretch" VerticalAlignment="Top" Height="Auto">
<MenuItem Header="Test">
<MenuItem InputGestureText="{Binding Command.GestureText}" Header="{Binding Command.Text}" Command="{Binding Command}">
</MenuItem>
</MenuItem>
</Menu>
</Grid>
</Window>
Sure, you should somehow load the gestures information from configuration and then init commands with the data.
当然,您应该以某种方式从配置加载手势信息,然后使用数据初始化命令。
The next step is keystokes like in VS: Ctrl+K,Ctrl+D, quick search gives this SO question.
下一步是 VS 中的按键:Ctrl+K,Ctrl+D,快速搜索给出了这个问题。
回答by yo chauhan
If I haven't misunderstood your question try this:
如果我没有误解你的问题,试试这个:
<Window.InputBindings>
<KeyBinding Key="A" Modifiers="Control" Command="{Binding ClickCommand}"/>
</Window.InputBindings>
<Grid >
<Button Content="ok" x:Name="button">
<Button.ContextMenu>
<local:CustomContextMenu>
<MenuItem Header="Click" Command="{Binding ClickCommand}"/>
</local:CustomContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
..with:
..和:
public class CustomContextMenu : ContextMenu
{
public CustomContextMenu()
{
this.Opened += CustomContextMenu_Opened;
}
void CustomContextMenu_Opened(object sender, RoutedEventArgs e)
{
DependencyObject obj = this.PlacementTarget;
while (true)
{
obj = LogicalTreeHelper.GetParent(obj);
if (obj == null || obj.GetType() == typeof(Window) || obj.GetType() == typeof(MainWindow))
break;
}
if (obj != null)
SetInputGestureText(((Window)obj).InputBindings);
//UnSubscribe once set
this.Opened -= CustomContextMenu_Opened;
}
void SetInputGestureText(InputBindingCollection bindings)
{
foreach (var item in this.Items)
{
var menuItem = item as MenuItem;
if (menuItem != null)
{
for (int i = 0; i < bindings.Count; i++)
{
var keyBinding = bindings[i] as KeyBinding;
//find one whose Command is same as that of menuItem
if (keyBinding!=null && keyBinding.Command == menuItem.Command)//ToDo : Apply check for None Modifier
menuItem.InputGestureText = keyBinding.Modifiers.ToString() + " + " + keyBinding.Key.ToString();
}
}
}
}
}
I hope this will give you an idea.
我希望这会给你一个想法。
回答by JCH2k
This is how it did it:
它是这样做的:
In the loaded-event of my window I match the Command bindings of the menu items with the Command bindings of all InputBindings, much like ethicallogics's answer, but for a menu bar and it actually compares the Command bindingsand not just the value, because that didn't work for me. this code also recurses into submenus.
在我的窗口的加载事件中,我将菜单项的命令绑定与所有 InputBindings 的命令绑定相匹配,很像道德逻辑的答案,但对于菜单栏,它实际上比较的是命令绑定,而不仅仅是值,因为对我不起作用。此代码也递归到子菜单中。
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
// add InputGestures to menu items
SetInputGestureTextsRecursive(MenuBar.Items, InputBindings);
}
private void SetInputGestureTextsRecursive(ItemCollection items, InputBindingCollection inputBindings)
{
foreach (var item in items)
{
var menuItem = item as MenuItem;
if (menuItem != null)
{
if (menuItem.Command != null)
{
// try to find an InputBinding with the same command and take the Gesture from there
foreach (KeyBinding keyBinding in inputBindings.OfType<KeyBinding>())
{
// we cant just do keyBinding.Command == menuItem.Command here, because the Command Property getter creates a new RelayCommand every time
// so we compare the bindings from XAML if they have the same target
if (CheckCommandPropertyBindingEquality(keyBinding, menuItem))
{
// let a new Keygesture create the String
menuItem.InputGestureText = new KeyGesture(keyBinding.Key, keyBinding.Modifiers).GetDisplayStringForCulture(CultureInfo.CurrentCulture);
}
}
}
// recurse into submenus
if (menuItem.Items != null)
SetInputGestureTextsRecursive(menuItem.Items, inputBindings);
}
}
}
private static bool CheckCommandPropertyBindingEquality(KeyBinding keyBinding, MenuItem menuItem)
{
// get the binding for 'Command' property
var keyBindingCommandBinding = BindingOperations.GetBindingExpression(keyBinding, InputBinding.CommandProperty);
var menuItemCommandBinding = BindingOperations.GetBindingExpression(menuItem, MenuItem.CommandProperty);
if (keyBindingCommandBinding == null || menuItemCommandBinding == null)
return false;
// commands are the same if they're defined in the same class and have the same name
return keyBindingCommandBinding.ResolvedSource == menuItemCommandBinding.ResolvedSource
&& keyBindingCommandBinding.ResolvedSourcePropertyName == menuItemCommandBinding.ResolvedSourcePropertyName;
}
Do this one time in your Window's code-behind and every menu item has an InputGesture. Just the translation is missing
在窗口的代码隐藏中执行一次,每个菜单项都有一个 InputGesture。只是缺少翻译
回答by Matt
Based on Pavel Voronin's answer, I created the following. Actually I just created two new UserControls which automatically set Gesture on the command and read it.
根据 Pavel Voronin 的回答,我创建了以下内容。实际上,我刚刚创建了两个新的 UserControl,它们会自动在命令上设置 Gesture 并读取它。
class HotMenuItem : MenuItem
{
public HotMenuItem()
{
SetBinding(InputGestureTextProperty, new Binding("Command.GestureText")
{
Source = this
});
}
}
class HotKeyBinding : KeyBinding
{
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property.Name == "Command" || e.Property.Name == "Gesture")
{
if (Command is IHotkeyCommand hotkeyCommand)
hotkeyCommand.Gesture = Gesture as KeyGesture;
}
}
}
The used interface
使用的接口
public interface IHotkeyCommand
{
KeyGesture Gesture { get; set; }
}
The Command is pretty much the same, it just implements INotifyPropertyChanged.
命令几乎相同,它只是实现了INotifyPropertyChanged.
So the usage gets a bit cleaner in my opinion:
所以在我看来,用法变得更清晰了:
<Window.InputBindings>
<viewModels:HotKeyBinding Command="{Binding ExitCommand}" Gesture="Alt+F4" />
</Window.InputBindings>
<Menu>
<MenuItem Header="File" >
<viewModels:HotMenuItem Header="Exit" Command="{Binding ExitCommand}" />
</MenuItem>
</Menu>

