Habib Gherairi Habib Gherairi - 23 days ago 14
C# Question

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

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

Answer

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