我在 wpf 中使用的所有菜单/上下文菜单/工具栏都在 ViewModel 代码中声明,非常像这样:
MenuService.Add( new MenuItem()
{
Header = "DoStuff",
Command = new relayCommand( DoStuff, () => CanDoStuffExecute() )
// some more properties like parent item/image/...
} );
MenuService 提供单个绑定点,它是 MenuItem 的分层列表,并绑定到 xaml 中实际 Menu 的 ItemsSource。
这非常有效,现在我想以同样方便的方式添加键盘快捷键。
理想情况下,MenuItem 将获得 type 的属性System.Windows.Input.KeyGesture
所以我可以简单地写
Shortcut = new KeyGesture( Key.D, ModifierKeys.Control )
这将导致在拥有菜单的窗口中按 Ctrl+D 时调用该项目的命令,并且还会导致在菜单中自动显示“Ctrl+D”。
但是我在这里迷失了:我想通过数据绑定设置 MenuItem.InputBindings 集合,但它是仅获取的。我怎样才能将物品放入其中?或者是否有一个 MVVM 框架已经支持这样的东西?我在键盘快捷键上发现的大多数问答都是关于通过xaml设置快捷键,这没有任何帮助。
Update
搜索“relaycommand vsrouteduicommand”和“relaycommand keygesture”等确实揭示了足够的信息来提出一个可行的解决方案。肯定还有其他更好的方法,但目前这对我来说是超低优先级的,而且可以完美地完成工作。我向 MenuItem 类添加了两个属性,如下所示:
//Upon setting a Gesture, the original command is replaced with a RoutedCommand
//since that automatically gives us proper display of the keyboard shortcut.
//The RoutedCommand simply calls back into the original Command.
//It also sets the CommandBinding property, which still has to be added to the
//CommandBindingCollection of either the bound control or one of it ancestors
public InputGesture Gesture
{
set
{
var origCmd = Command;
if( origCmd == null )
return;
var routedCmd = new RoutedCommand( Header,
typeof( System.Windows.Controls.MenuItem ),
new InputGestureCollection { value } );
CommandBinding = new CommandBinding( routedCmd,
( sender, args ) => origCmd.Execute( args.Parameter ),
( sender, args ) => { args.CanExecute = origCmd.CanExecute( args.Parameter ); } );
Command = routedCmd;
}
}
//CommandBinding created when setting Gesture
public CommandBinding CommandBinding { get; private set; }
因此,这提供了我最初要求的功能(即在易于配置的代码中添加键盘快捷键等)。剩下的就是注册命令绑定。目前,只需将它们全部添加到 Application.Current.MainWindow.CommandBindings 即可完成。