2014-04-11 16 views
6

Mam małe okienko WPF z 2 polami tekstowymi, które mają uporządkowane TabIndex 0,1 i chcę przenieść fokus automatycznie z pierwszego pola tekstowego do drugiego po naciśnięciu klawisza Enter . Używam światła MVVM.WPF i MVVM: Jak automatycznie przenieść ostrość do następnej Kontroli?

Uwaga: ten wpis nie jest duplikatem. tutaj nie używam podejścia klasycznego z Event Handler, ale MVVM Pattern i jak wiadomo Code Behind jest niedozwolone w widoku.

Znalazłem rozwiązanie, ale nie wiem, czy przestrzega ono zasady MVVM. Oto kod:

Widok

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

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

ja nie wiem, czy użycie "kontrola" w klasie ViewModel jest dozwolony czy nie

Odpowiedz

11

Jak używasz MVVM, można użyć Zachowanie dla tego:

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

} 

W swojej XAML:

<TextBox> 
    <i:Interaction.Behaviors> 
    <wpfTest:TabOnEnterBehavior /> 
    </i:Interaction.Behaviors> 
</TextBox> 
+0

To dobre rozwiązanie i działa dobrze. Dziękuję –

+0

Dzięki za dobre rozwiązanie. Mam bardzo textbox na projekcie, czy mogę ustawić to dla domyślnego TextBox i nie dodawać zachowań dla wszystkich textbox? –

+0

@ ar.gorgin: spójrz na to pytanie SO: http: // stackoverflow.com/questions/1647815/how-to-add-a-blend-behaviour-in-a-style-setter –

2

Dodaj wydarzenie PreviewKeyDown do swojego TextBox pierwszy:

<TextBox PreviewKeyDown="OnTextBoxKeyDown" /> 

Następnie utwórz TraversalRequest aby przenieść fokus do następnego elementu:

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

EDIT

Ewentualnie, jeśli wolisz za pomocą poleceń, można po prostu ustawić KeyBinding w twoim :

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

Po prostu umieść to samo, co powyżej, w logice ICommand s Execute`.

Również samo pytanie tutaj: How do I simulate a Tab key press when Return is pressed in a WPF application?

+1

śledzę MVVM wzór . Myślę, że żadne wydarzenia nie są dozwolone. –

+0

Właściwie używam MVVM Light, które oferują EventToCommand do zamiany Keydown Event na Command. Ale moim problemem jest jak przenieść Focus do następnego TextBox bez użycia EventHandler. –

+7

Ponownie, MVVM polega na oddzieleniu widoku od logiki. Nie chodzi o ekstremistów "żadne wydarzenia nie są dozwolone". Próbujesz przenieść fokus, który jest czystym działaniem interfejsu użytkownika, dlaczego miałbyś go umieścić w dowolnym miejscu, ale w interfejsie użytkownika (czy może to być xaml lub xaml.cs)? Pamiętaj najpierw: MVVM nie dotyczy "braku kodu" lub "braku zdarzeń", chodzi o "brak biznesu w logice interfejsu użytkownika". Masz pełne prawo do używania wydarzeń tam :) – Damascus