C# - 如何在MVVM中处理XAML键盘事件?

9

到目前为止,我使用 .xaml.cs 文件来处理输入。

这是我的 XAML 头代码:

<Window x:Class="My_Windows_App.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:My_Windows_App.ViewModel"
Title="MainWindow" Height="600" Width="900"
Keyboard.KeyDown="keyDownEventHandler" Keyboard.KeyUp="keyUpEventHandler">

以下是MainWindow.xaml.cs代码的一部分:

public partial class MainWindow : Window
    {
        private bool pushToTalk;

        public void keyDownEventHandler(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.LeftCtrl)
                pushToTalk = true;
        }

        public void keyUpEventHandler(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.LeftCtrl)
                pushToTalk = false;
        }
}

我该怎样在MVVM中实现同样的功能呢? 因为据我所知,我们只能绑定属性,而不能绑定方法,对吗?

3个回答

22

看起来你已经得到了答案,但这里还有另一种解决方案。
你可以使用 i:interactionInputBindings 来处理键盘事件。在与交互配合使用的情况下,一些使用 DatePicker 的示例可能是:

<DatePicker Name="fancy_name_here" SelectedDate="{Binding your_date_property_here}">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="PreviewKeyDown">               
    <i:InvokeCommandAction Command="{Binding Path=TestMeCommand}" />
    </i:EventTrigger>
  </i:Interaction.Triggers>
</DatePicker>

请注意,在窗口定义中您需要加入下一行代码才能使i:Interaction正常工作:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

同时需要为输入绑定进行设置:

<DatePicker Name="fancy_name_here"  SelectedDate="{Binding your_date_property_here}">
  <DatePicker.InputBindings>
    <KeyBinding Key="Up" Modifiers="Shift" Command="{Binding your_command_name}" />
    <KeyBinding Key="Up" Modifiers="Alt" Command="{Binding TestMeCommand}" />       
    <KeyBinding Key="Up" Command="{Binding TestMeCommand}" />        
  </DatePicker.InputBindings>
</DatePicker>

请随意查看我的其他答案,其中讨论了i:interactionInputBindings,并指向处理键事件的另一篇文章:日期选择器中的上下操作,并探讨了背后的代码/MVVM方法。

希望你会发现它们有用。


2
+1。我正要发布这个。不需要使用“工具包”,而且效果很好。 - trinaldi
1
虽然这种方法还可以,但我不知道你如何处理OnKeyUp,以便像OP一样将PushToTalk属性切换为false。 - Federico Berasategui

6

输入处理是视图的职责,而不是ViewModel的职责,为什么要将其移动到ViewModel中?

相反,将应用/业务逻辑委托给ViewModel,同时保持键盘输入处理在View中:

public partial class MainWindow : Window
{
    private MyViewModel ViewModel;

    public MainWindow()
    {
        ViewModel = new MyViewModel();
    }


    public void keyDownEventHandler(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.LeftCtrl)
            ViewModel.PushToTalk = true;
    }

    public void keyUpEventHandler(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.LeftCtrl)
            ViewModel.PushToTalk = false;
    }
}

注意我将 PushToTalk 属性移动到 ViewModel,因为它确实是应用程序逻辑的一部分,而不是 UI,同时保持键盘事件在 View 层级别。这不会破坏 MVVM,因为您没有混合 UI 和应用程序逻辑,而是将它们放置在真正属于它们的地方。

2
虽然这可能有效,但MVVM并不涉及事件。一个“纯粹主义者”会报警的:p - trinaldi
2
@Tico 错了。MVVM 是关于不将业务逻辑和 UI 放在一起,而不是关于无意义的任意限制可以使用什么和不能使用什么。我的解决方案符合 MVVM,因为它让 View 处理自己的问题,同时将业务逻辑保留在 ViewModel 中。 - Federico Berasategui
1
好的,我相信。但这不会与“命令”模式冲突吗?我不是一个纯粹主义者。但是通过其他架构也可以实现UI/逻辑的分离。 - trinaldi
它确实与“Command”模式冲突,但似乎没有办法将命令放在窗口本身上。就我所知,@Noctis的答案行不通,因为Interaction.Triggers无法粘贴在窗口上。同时,也没有KeyDown/KeyUp的EventTrigger方向可走。 - scottheckel

2
以下内容适用于处理TextBox中的“回车”键:
```C# private void textBox1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { //处理“回车”键 } } ```
在TextBox的KeyDown事件中,检查按下的键是否是“Enter”键,如果是则可以执行相应操作。
<TextBox Text="{Binding UploadNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
    <KeyBinding 
      Key="Enter" 
      Command="{Binding FindUploadCommand}" 
      CommandParameter="{Binding Path=Text, RelativeSource={RelativeSource AncestorType={x:Type TextBox}}}" />
</TextBox.InputBindings>


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