我在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将获得类型为System.Windows.Input.KeyGesture
的属性,因此我可以简单地编写
Shortcut = new KeyGesture( Key.D, ModifierKeys.Control )
这会导致在拥有菜单的窗口中按Ctrl + D调用项目的Command,这也会导致在菜单中自动显示“Ctrl + D”。
但是我迷失在这里:我想通过数据绑定设置MenuItem.InputBindings集合,但它是get-only。我怎么能把物品放进去呢?或者是否有一个MVVM框架已经支持这样的东西?我在键盘快捷键上找到的大多数q& a都是关于通过xaml设置快捷方式,这没什么用。
更新
搜索'relaycommand vs routeduicommand和'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即可完成。
答案 0 :(得分:3)
这实际上并不符合“答案”的要求。 (我显然无法添加评论) - 但我建议您正在做的事情不是WPF中的预期方法。您正在使用Windows Forms方式(以及许多其他工具包) - 在代码中定义您的UX。你得到了尽可能多的东西,但是现在你遇到了一堵砖墙:关键的手势纯粹是用户体验,绝对不能在代码隐藏中指定。外观(作为视图模型的函数)以及用户与它的交互(发出给定命令的方式)是针对XAML定义的。
属性值和命令适用于您的视图模型,因此您可以将此视图模型重用于其他视图,还可以轻松地为其创建单元测试。如何在视图模型中实现键盘快捷键有助于提高可测试性?为了在其他视图中使用,可以认为实际的快捷方式可能不适用于新视图,因此这不属于那些视图。当然,您可能还有其他原因 - 但我建议您可以考虑在XAML中定义这些原因。
- 已添加,以回应您的评论 -
你说得对 - 我已经看到了一些相当大的WPF UX项目,它们努力避免任何代码 - 并且不必要地使用了不必要的代码。我试着用任何一种方法产生一个工作结果,并且就像我能得到它一样简单。
以下是一个简单创建MenuItem的示例代码段。
<Menu x:Name="miMain" DockPanel.Dock="Top">
<MenuItem Command="{Binding Path=MyGreatCommand}" Header="DoSomething"/>
创建菜单。这里,MyGreatCommand
是ICommand
,只是视图模型上的属性。我通常将其放在DockPanel
内,以处理StatusBar
等。
分配关键手势..
<Window.InputBindings>
<KeyBinding Key="X" Modifiers="ALT" Command="{Binding Path=MyGreatCommand}"/>
但是,既然您提到您已经搜索过答案并且只找到了XAML - 我认为您已经尝试过这种方法。我使用RoutedUICommand
而不是用户定义的ICommand
来获取标题文本中那个很好的右对齐键手势,但我还没有找到如何做到这两点。如果您坚持在代码中创建所有命令和键手势,则可能必须创建RoutedUICommand
s。
为什么要在XAML以外设置关键手势?
如果您希望某些菜单项仅在某些状态在视图模型中占据主导时出现,则可以绑定菜单项的Visibility
属性(可以包含其他菜单项) Collapsed
或Visible
。