gpt4 book ai didi

c# - 'pure' MVVM 中的 MenuItem 键盘快捷键?

转载 作者:太空狗 更新时间:2023-10-29 23:25:39 29 4
gpt4 key购买 nike

我在 wpf 中使用的所有菜单/上下文菜单/工具栏都在 ViewModel 代码中声明,非常像这样:

MenuService.Add( new MenuItem()
{
Header = "DoStuff",
Command = new relayCommand( DoStuff, () => CanDoStuffExecute() )
// some more properties like parent item/image/...
} );

MenuService 提供单个绑定(bind)点,它是 MenuItem 的分层列表,并绑定(bind)到 xaml 中实际菜单的 ItemsSource。

这非常有效,现在我想以同样方便的方式添加键盘快捷键。理想情况下,MenuItem 会获得 System.Windows.Input.KeyGesture 类型的属性,这样我就可以简单地编写

Shortcut = new KeyGesture( Key.D, ModifierKeys.Control )

这将导致在拥有该菜单的窗口中按下 Ctrl+D 时调用该项目的命令,这也会导致在菜单中自动显示“Ctrl+D”。

但是我在这里迷路了:我想通过数据绑定(bind)设置 MenuItem.InputBindings 集合,但它是只获取的。我怎样才能把元素放进去?或者是否有一个 MVVM 框架已经支持这样的东西?我发现的快捷键问答,大部分都是通过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; }

所以这提供了我最初要求的功能(即在易于配置的代码中添加键盘快捷键等)。剩下的就是注册命令绑定(bind)。目前,这只需将它们全部添加到 Application.Current.MainWindow.CommandBindings 即可。

最佳答案

这实际上不符合“答案”的条件(显然我无法添加评论)- 但我建议您正在做的事情不是 WPF 中的预期方法。您正在以 Windows 窗体方式(以及在许多其他工具包中)执行此操作 - 在代码中定义您的用户体验。你已经达到了你所做的,但现在你遇到了一堵砖墙:关键手势纯粹是用户体验,绝对不能在代码隐藏中指定。外观(作为 View 模型的函数)以及用户与其交互(执行给定命令的方式)用于 XAML 定义。

属性值和命令适用于您的 View 模型,因此您可以将此 View 模型重用于其他 View ,还可以轻松地为其创建单元测试。在 View 模型中实现键盘快捷键将如何帮助提高可测试性?对于在其他 View 中的使用,有人可能会争辩说实际的快捷方式可能不适用于新 View ,因此这不属于那些地方。当然,您可能有其他原因 - 但我建议您可以考虑只在 XAML 中定义这些。

-已添加,以回应您的评论-

您说得很对 - 我见过一些相当大的 WPF UX 项目,它们努力避免任何代码 - 并以不必要的方式结束。我尝试只使用任何能产生有效结果的方法,并且尽可能简单。

这是一个简单地创建 MenuItem 的示例片段..

<Menu x:Name="miMain" DockPanel.Dock="Top">
<MenuItem Command="{Binding Path=MyGreatCommand}" Header="DoSomething"/>

创建菜单。这里,MyGreatCommand 是一个 ICommand,只是 View 模型的一个属性。我通常将它放在 DockPanel 中,以处理 StatusBar

分配关键手势..

<Window.InputBindings>
<KeyBinding Key="X" Modifiers="ALT" Command="{Binding Path=MyGreatCommand}"/>

但是,由于您提到您已经搜索过答案并且只找到了 XAML - 我假设您已经尝试过这种方法。我使用 RoutedUICommand 而不是用户定义的 ICommand 来在标题文本中获得漂亮的右对齐按键手势,但我还没有找到如何两者都做。如果您坚持在代码中创建所有命令和按键手势,您可能必须创建 RoutedUICommand

为什么要在 XAML 以外的环境中设置按键手势?

如果您希望某些菜单项仅在某些状态在您的 View 模型中占据主导地位时出现,那么您可以绑定(bind)菜单项的 Visibility 属性(它可以包含其他菜单项 - items) 到 CollapsedVisible

关于c# - 'pure' MVVM 中的 MenuItem 键盘快捷键?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8617897/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com