在ViewModel中将WPF快捷键绑定到命令

39

我有一个使用MVVM模式的WPF应用程序。将按钮连接到VM非常简单,因为它们实现了ICommand。我有一个类似的工具栏,它也可以正常工作。下一步是为上下文菜单创建快捷键。我无法弄清如何让快捷键调用命令。以下是一个示例:

<MenuItem Header="Update" Command="{Binding btnUpdate}" >
    <MenuItem.Icon>
        <Image Source="/Images/Update.png"
               Width="16"
               Height="16" />
        </MenuItem.Icon>
    </MenuItem>

现在我已经添加了这个:

<Window.InputBindings>
    <KeyBinding Key="U"
                Modifiers="Control" 
                Command="{Binding btnUpdate}" />
</Window.InputBindings>

尝试将快捷键连接到相同的绑定,但这并不起作用。错误是:

错误 169“Binding”无法设置为类型为“KeyBinding”的“Command”属性。只能在DependencyObject的DependencyProperty上设置“绑定”。

难道没有一种方法可以将此事件连接到命令吗?我无法弄清楚这个问题。

提前致谢!

Bill


我应该提到我也在使用Josh Smith的RelayCommand。 - Bill Campbell
5个回答

43
以下代码可用于将快捷键直接绑定到命令:
<Window.InputBindings>
    <KeyBinding Command="{Binding Path=NameOfYourCommand}" 
                Key="O" 
                Modifiers="Control"/>
</Window.InputBindings>

在您的视图的XAML代码中,在Window.Resources之后添加此内容。


4
没搞清楚 OP 的问题是什么,但这个方法可以正常工作。(我在使用 MVVM light) - GONeale
10
他明确表示这不起作用,而所选答案解释了原因:他没有使用WPF4。不确定为什么你把他的代码作为一个“答案”发表。 - aaronburro
修饰键是 Ctrl 吗? - amit jha
1
@aaronburro 好的,回答很好,问题应该更新一下,提到WPF 4,但对于我们这些甚至不看问题的人来说,这个答案很有用,老实说,如果我看了问题,我会感到困惑。 - Piotr Golacki

26

我编写了一个自定义标记扩展,用于将InputBindings绑定到命令,它几乎可以像真正的绑定一样使用:

<UserControl.InputBindings>
    <KeyBinding Modifiers="Control" 
                Key="E" 
                Command="{input:CommandBinding EditCommand}"/>
</UserControl.InputBindings>

请注意,此标记扩展使用私有反射,因此只能在应用程序以完全信任运行时使用...
另一种选择是使用CommandReference类。它可以在MVVM工具包这里中找到。这可能是一种更清晰的方法,但使用起来会稍微复杂一些。
请注意,在WPF 4中,InputBinding.Command、InputBinding.CommandParameter和InputBinding.CommandTarget属性是依赖属性,因此可以正常绑定。

我是否试图在上下文菜单而不是标准菜单上使用这些快捷键? - Bill Campbell
你使用了哪种技术?是Markup扩展还是CommandReference类? - Thomas Levesque
CommandReference - 看起来放置KeyBinding在XAML中的位置很重要。如果我将其放置在窗口中的DataGrid中,我会在CanExecute中触发断点 - 但它似乎总是返回false。 - Bill Campbell
我曾想过,如果我在窗口的任何位置放置KeyBinding,它就会起作用,但事实并非如此。 - Bill Campbell
可以的。我本以为如果将KeyBinding放在包含控件的窗口上,它也会被子控件触发,但也许不是这样? - Bill Campbell
显示剩余3条评论

9

我同意在XAML中完成这项工作是理想的,但为了完整起见,您也可以在代码中添加绑定。如果您在构造函数中执行此操作,请确保它在调用InitializeComponent()之后。

InputBindings.Add(new KeyBinding(btnUpdate, new KeyGesture(Key.U, ModifierKeys.Control));

+1 这个方法让我可以将它放入我的视图中,因为我需要这个函数只能与 UI 元素一起使用。 - CaptainBli
3
但是这会将一个名为“btnUpdate”的按钮控件绑定到快捷键Ctrl-U,而不是像Michel Keijzers的XAML那样绑定到命令。 - ProfK
2
我正在回答原始帖子,该帖子试图绑定到名为“btnUpdate”的东西。 - Eddie Deyo
这个可以工作,但是你需要用你的按钮命令替换btnUpdate。 - EdgarT

0

已经能够在DataGrid级别上添加Keybinding。像这样:

Xaml:

<DataGrid 
                    AutoGenerateColumns="False"
                    ItemsSource="{Binding YourCollection}"                         
                    CanUserAddRows="False"                        
                    HeadersVisibility="Column" 
                    CanUserDeleteRows="False" 
                    CanUserSortColumns="True"
                    CanUserResizeRows="False"
                    CanUserResizeColumns="False"                       
                    SelectedItem="{Binding YourSelectedItem}" 
                    SelectionMode="Single" 
                    SelectionUnit="FullRow"
                   >
                <DataGrid.ContextMenu>
                    <ContextMenu>
                       **<MenuItem Header="Delete" InputGestureText="Del" Command="{Binding DeleteCommand}">**
                        </MenuItem>
                    </ContextMenu>
                </DataGrid.ContextMenu>
                **<DataGrid.InputBindings>
                    <KeyBinding Key="Delete" Command="{Binding DeleteCommand}" CommandParameter="Delete"/>**
                </DataGrid.InputBindings>
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Column Header" Binding="{Binding YourColumn}" IsReadOnly="True" />
                </DataGrid.Columns>
</DataGrid>

视图模型:

public ICommand DeleteCommand
            {
                get
                {
                    return new DelegateCommand(ExecuteCommand, CanExecute);
                }
            }

  private void ExecuteCommand()
{
// your code to delete here.
   YourCollection.Remove(YourSelectedItem);
}

private void CanExecute()
{
// logic to check if the delete command can execute.
   return YourSelectedItem != null ;
}

0

谢谢...我需要一些时间来研究它(意思是我现在没有太多时间,但我点赞了,因为链接似乎非常有用(不仅仅是针对我的问题)。 - Michel Keijzers
这个回答只是宣传,没有提供任何帮助,给出的链接也没有用。 - Alessandro Muzzi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接