简体   繁体   中英

How to detect keypress in TextBox using MVVM Light

In my ViewModel, how can I detect what key was pressed when entering text in a textBox?

In plain WPF/C# I'm doing it like this...

XAML File

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

Codebehind .xaml.cs

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

EDIT:

FYI -What I'm trying to do is create a shortcut for the enter key.

There are a couple of ways to go about this. The first approach would be more MVVM appropriate where we just detect a change to the value of the Text that is bound to your TextBox :

In XAML:

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

In VM

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?
       }
   }
}

Or, to more directly answer the question you asked, if you must rely on detecting a keypress in the textbox, you should take advantage of the EventToCommand that you can hook in with MVVMLight

In 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>

Edit

In addition, you could also bind to the KeyBinding Command on the textbox:

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

And yet another option would be to keep handling the KeyDown event in your view, but in the codebehind call a ViewModel method:

As I understand, you actually do not want to send the Key to ViewModel . You just want to trigger something inside your ViewModel .

EventAggregator might be your solution, in your KeyDown event, you trigger event inside VM without knowing VM and you pass anything you want, there are several ways to do it.

If you are using framework like MVVMLight , Prism they might have own implementations, if you don't, there is a simple tutorial for it. (This is not the only way, you can find different implementations when you search observer pattern )

Inside your if you call Publish method which comes from EventAggregator . And all your Subscribers get that with a parameter you choose.

This way you can communicate with your ViewModel from wherever you want.

Personally I have created a Behavior as follows:

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);
    }
}

And then use it as

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM