【问题标题】:How to detect keypress in TextBox using MVVM Light如何使用 MVVM Light 检测 TextBox 中的按键
【发布时间】:2026-01-29 09:40:01
【问题描述】:

在我的 ViewModel 中,如何检测在 textBox 中输入文本时按下了什么键?

在普通的 WPF/C# 中,我正在这样做......

XAML 文件

<TextBox x:Name="myInputField" KeyDown="inputField_KeyDown"/>

代码隐藏 .xaml.cs

private void inputField_KeyDown(object sender, KeyEventArgs e)
{
    if (Keyboard.IsKeyDown(Key.Enter)) {
        // do something
    }
}

编辑:

仅供参考 - 我要做的是为回车键创建一个快捷方式。

【问题讨论】:

标签: c# wpf xaml mvvm mvvm-light


【解决方案1】:

有几种方法可以解决这个问题。第一种方法更适合 MVVM,我们只检测到绑定到您的 TextBoxText 的值发生变化:

在 XAML 中:

<TextBox x:Name="myInputField", 
         Text="{Binding MyText, UpdateSourceTrigger=PropertyChanged}" />

在虚拟机中

private string myText;
public string MyText
{
   get
   {
       return myText;
   }

   set
   {
       if (Set(nameof (MyText), ref myText, value))
       {
            // the value of the text box changed.. do something here?
       }
   }
}

或者,为了更直接地回答您提出的问题,如果您必须依靠检测文本框中的按键,您应该利用 EventToCommand that you can hook in with MVVMLight

在 XAML 中:

xmlns:cmd="http://www.galasoft.ch/mvvmlight"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

...

<TextBox ....
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="KeyDown">
            <cmd:EventToCommand Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=DataContext.KeyDownCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>    
</TextBox>

编辑

此外,您还可以绑定到文本框上的 KeyBinding 命令:

<TextBox AcceptsReturn="False">
<TextBox.InputBindings>
    <KeyBinding 
        Key="Enter" 
        Command="{Binding SearchCommand}" 
        CommandParameter="{Binding Path=Text, RelativeSource={RelativeSource AncestorType={x:Type TextBox}}}" />
</TextBox.InputBindings>

另一种选择是在视图中继续处理 KeyDown 事件,但在代码隐藏中调用 ViewModel 方法:

【讨论】:

  • @flyte 抱歉,我卡住了,我不确定如何在我的 ViewModel 中捕获键的值。您是否介意详细说明如何在 ViewModel 中接收值(在您的第二个示例中)?仅供参考 - 我想做的是为回车键创建一个快捷方式,我认为我不能用第一种方法来完成。
  • 您可以将 EventArgs 传递给 VM 中的命令。请查看我提供的 MVVMLight 链接上的 Getting the EventArgs to the ViewModel 部分。
【解决方案2】:

据我了解,您实际上不想将Key 发送到ViewModel。你只是想在你的ViewModel 中触发一些东西。

EventAggregator 可能是您的解决方案,在您的KeyDown 事件中,您在不知道 VM 的情况下触发 VM 内部的事件并传递您想要的任何内容,有几种方法可以做到。

如果您使用像MVVMLightPrism 这样的框架,它们可能有自己的实现,如果您不使用,则有一个简单的tutorial 用于它。 (这不是唯一的方法,搜索observer pattern可以找到不同的实现方式)

在您的if 中,您调用来自EventAggregatorPublish 方法。您的所有订阅者都可以通过您选择的参数来获得它。

这样您就可以随时随地与您的ViewModel 通信。

【讨论】:

    【解决方案3】:

    我个人创建了一个Behavior,如下:

    public class KeyUpToCommandBehaviour : Behavior<UIElement>
    {
        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
            "Command", typeof(ICommand), typeof(KeyUpToCommandBehaviour), new PropertyMetadata(default(ICommand)));
    
        public ICommand Command
        {
            get { return (ICommand) GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }
    
        public static readonly DependencyProperty KeyProperty = DependencyProperty.Register(
            "Key", typeof(Key), typeof(KeyUpToCommandBehaviour), new PropertyMetadata(default(Key)));
        private RoutedEventHandler _routedEventHandler;
    
        public Key Key
        {
            get { return (Key) GetValue(KeyProperty); }
            set { SetValue(KeyProperty, value); }
        }
    
        protected override void OnAttached()
        {
            base.OnAttached();
            _routedEventHandler = AssociatedObject_KeyUp;
    
            AssociatedObject.AddHandler(UIElement.KeyUpEvent, _routedEventHandler, true);
        }
    
        void AssociatedObject_KeyUp(object sender, RoutedEventArgs e)
        {
            var keyArgs = e as KeyEventArgs;
    
            if (keyArgs == null)
                return;
    
            if(keyArgs.Key == Key)
                Command?.Execute(null);
        }
    
        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.RemoveHandler(UIElement.KeyUpEvent, _routedEventHandler);
        }
    }
    

    然后把它当作

    <TextBox ....
        <i:Interaction.Behaviors>
            <attachedBehaviors:KeyUpToCommandBehaviour Key="Enter" Command="{Binding OpenFxTradeTargetingWizardCommand}"/>
        </i:Interaction.Behaviors>
    </TextBox>
    

    【讨论】: