Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF and MVVM : How to move focus to the next Control automatically

Tags:

c#

mvvm

wpf

I have a little WPF Window with 2 TextBoxes Having Ordered TabIndex 0,1 and i want to move focus automatically from the first TextBox to the second when i press Enter Key. I Use MVVM Light.

Remark : This post is not duplicated. here I do not use Classic approach with event Handler but MVVM Pattern and as you know Code Behind is not allowed in view.

I Found a solution but I don't know if it respect MVVM Principle. Here the code :

The View

<Window x:Class="WpfMMVLight2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:cmd ="http://www.galasoft.ch/mvvmlight"
    Title="MainWindow" Height="350" Width="525"
    DataContext="{Binding MainViewModel}">
    <Grid FocusManager.FocusedElement="{Binding ElementName=tb1}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="70"/>
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <TextBlock Grid.Column="0" Text="Text 1" VerticalAlignment="Center"/>
    <TextBox x:Name="tb1" Grid.Column="1" VerticalAlignment="Center" Margin="5">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="KeyDown">
                <cmd:EventToCommand PassEventArgsToCommand="True"
                Command ="{Binding KeyDownCommand, Mode=OneWay}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>


     <TextBlock Grid.Column="0" Grid.Row="1" Text="Text 2" VerticalAlignment="Center"/>
     <TextBox x:Name="tb2" Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" Margin="5">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="KeyDown">
                <cmd:EventToCommand PassEventArgsToCommand="True"
            Command ="{Binding KeyDownCommand, Mode=OneWay}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>

</Grid>

The ViewModel :

 private ICommand _keydownCommand;
 public ICommand KeyDownCommand
    {
       get
        {
            if (_keydownCommand== null)
                _keydownCommand= new DelegateCommand<KeyEventArgs>(KeyDownCommandExecute);
            return _keydownCommand;
        }



    }


    private void KeyDownCommandExecute(KeyEventArgs e)
    {
        if (e != null && e.Key == Key.Enter)
        {
      TraversalRequest request = new TraversalRequest(FocusNavigationDirection.Next);
      request.Wrapped = true;
      ((Control)e.Source).MoveFocus(request);
     }
    }
}    

I don't know if use of "Control" Class in ViewModel Is allowed or not

like image 226
Habib Gherairi Avatar asked Apr 11 '14 09:04

Habib Gherairi


People also ask

How do I set focus in WPF MVVM?

SetFocus(()=>ViewModelProperty); or this. SetFocus("Property");

Is Mvvm slow?

MVVM Done Right is Slow In a large application, you might need to loop through the data multiple times to make sure it has all recalculated correctly. If you just use the framework and let the framework deal with your sloppy code, this can make the system incredibly slow.

What is focus in WPF?

Keyboard focus refers to the element that is currently receiving keyboard input. There can be only one element on the whole desktop that has keyboard focus. In WPF, the element that has keyboard focus will have IsKeyboardFocused set to true .


2 Answers

As you are using MVVM, you can use a Behavior for this:

public class TabOnEnterBehavior : Behavior<TextBox>
{

  protected override void OnAttached()
  {
    AssociatedObject.PreviewKeyDown += AssociatedObject_PreviewKeyDown;
  }

  private void AssociatedObject_PreviewKeyDown(object sender, KeyEventArgs e)
  {
    if (e.Key == Key.Enter)
    {
      var request = new TraversalRequest(FocusNavigationDirection.Next);
      request.Wrapped = true;
      AssociatedObject.MoveFocus(request);
    }
  }

  protected override void OnDetaching()
  {
    AssociatedObject.PreviewKeyDown -= AssociatedObject_PreviewKeyDown;
  }

}

In your xaml:

<TextBox>
  <i:Interaction.Behaviors>
    <wpfTest:TabOnEnterBehavior />
  </i:Interaction.Behaviors>
</TextBox>
like image 109
Julien Poulin Avatar answered Sep 18 '22 08:09

Julien Poulin


Add a PreviewKeyDown event to your TextBox first:

<TextBox PreviewKeyDown="OnTextBoxKeyDown" />

Then create a TraversalRequest to move focus to the next item:

private void OnTextBoxKeyDown(object sender, KeyEventArgs e)
{
 if (e.Key == Key.Return)
 {
   TraversalRequest request = new TraversalRequest(FocusNavigationDirection.Next);
   MoveFocus(request);
 }
}

EDIT

Alternatively, if you prefer using a Command, you can just set a KeyBinding in your TextBox :

        <TextBox.InputBindings>
            <KeyBinding Key="Enter" Command="{Binding YourCommand}" />
        </TextBox.InputBindings>

And just put pretty much the same thing as above in your ICommandsExecute` logic.

Also, same question here: How do I simulate a Tab key press when Return is pressed in a WPF application?

like image 35
Damascus Avatar answered Sep 20 '22 08:09

Damascus