2010-08-10 15 views
5

Tengo un cuadro de texto en el que tengo esto: <KeyBinding Command="{Binding MyCommand}" Key="Tab"/>WPF: combinación de teclas para Tab, Tab Golondrinas y no pasar a lo largo

El problema es que se traga la ficha y no lo hace pestaña al siguiente control . ¿Cómo puedo atrapar la pestaña para el cuadro de texto y aún conservar las pestañas en el próximo control en el orden de las pestañas? Editar: También estoy usando MVVM y MyCommand está en el código de ViewModel, por lo que es donde tengo que volver a lanzar la pestaña.

+1

Tal vez el evento 'LostFocus' es más adecuado para sus propósitos? (Todavía considero que tu pregunta es interesante, así que +1.) – Heinzi

+0

Miré en LostFocus, pero con mi edición de Estoy usando MVVM, me gustaría no poner el código allí. – mike

+0

Creo que más acerca de LostFocus, ¿cómo podría vincular el comando al evento LostFocus? Quiero hacer esto sin poner código en el código xaml detrás, solo vinculando a un comando en mi ViewModel. – mike

Respuesta

0

No encuentro una manera de establecer el foco en un control dada su pregunta como una solución puramente XAML.
Elijo crear una propiedad atacada y luego, a través del enlace, establezco el foco en el próximo control del Comando asociado con su Enlace de clave en el modelo de vista.

Aquí es la vista:

<Window x:Class="WarpTab.Views.MainView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:c="clr-namespace:WarpTab.Commands" 
    xmlns:Views="clr-namespace:WarpTab.Views" 
    xmlns:local="clr-namespace:WarpTab.ViewModels" 
    Title="Main Window" Height="400" Width="800"> 

    <Window.Resources> 
     <c:CommandReference x:Key="MyCommandReference" Command="{Binding MyCommand}" /> 
    </Window.Resources> 

    <DockPanel> 
    <ScrollViewer> 
     <WrapPanel > 
     <TextBox Text="First text value" > 
      <TextBox.InputBindings> 
       <KeyBinding Command="{StaticResource MyCommandReference}" Key="Tab"/> 
      </TextBox.InputBindings> 
     </TextBox> 
     <TextBox Text="Next text value" local:FocusExtension.IsFocused="{Binding FocusControl}" /> 
     <Button Content="My Button" /> 
     </WrapPanel> 
    </ScrollViewer> 
    </DockPanel> 
</Window> 

Aquí es el modelo de vista:

using System.Windows.Input; 
using WarpTab.Commands; 

namespace WarpTab.ViewModels 
{ 
    public class MainViewModel : ViewModelBase 
    { 
    public ICommand MyCommand { get; set; } 
    public MainViewModel() 
    { 
     MyCommand = new DelegateCommand<object>(OnMyCommand, CanMyCommand); 
    } 

    private void OnMyCommand(object obj) 
    { 
     FocusControl = true; 

     // process command here 

     // reset to allow tab to continue to work 
     FocusControl = false; 
     return; 
    } 

    private bool CanMyCommand(object obj) 
    { 
     return true; 
    } 

    private bool _focusControl = false; 
    public bool FocusControl 
    { 
     get 
     { 
     return _focusControl; 
     } 
     set 
     { 
     _focusControl = value; 
     OnPropertyChanged("FocusControl"); 
     } 
    } 
    } 
} 

Este es el código para definir la propiedad adjunto que he encontrado en el siguiente answer.

using System.Windows; 

namespace WarpTab.ViewModels 
{ 
    public static class FocusExtension 
    { 
    public static bool GetIsFocused(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsFocusedProperty); 
    } 

    public static void SetIsFocused(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsFocusedProperty, value); 
    } 

    public static readonly DependencyProperty IsFocusedProperty = 
      DependencyProperty.RegisterAttached(
      "IsFocused", typeof(bool), typeof(FocusExtension), 
      new UIPropertyMetadata(false, OnIsFocusedPropertyChanged)); 

    private static void OnIsFocusedPropertyChanged(DependencyObject d, 
      DependencyPropertyChangedEventArgs e) 
    { 
     var uie = (UIElement)d; 
     if ((bool)e.NewValue) 
     { 
     uie.Focus(); // Don't care about false values. 
     } 
    } 
    } 
} 
0

¿Por qué no solo utiliza este código en el controlador de comandos?

private void MyCommandHandler(){ 

    // Do command's work here 

    TraversalRequest request = new TraversalRequest(FocusNavigationDirection.Next); 
    request.Wrapped = true; 
    control.MoveFocus(request); 

} 

Eso es básicamente lo que hace 'Tab', así que si haces lo mismo, ya estás listo. (Por supuesto invertir el sentido de si tiene un comando con Shift-Tab.

De hecho, me envolví esto en un método de extensión como tal ...

public static class NavigationHelpers{ 

    public static void MoveFocus(this FrameworkElement control, FocusNavigationDirection direction = FocusNavigationDirection.Next, bool wrap = true) { 

     TraversalRequest request = new TraversalRequest(direction); 
     request.Wrapped = wrap; 
     control.MoveFocus(request); 

    } 

} 

... es decir, el código se vuelve aún más simple antes , así ...

private void MyCommandHandler(){ 

    // Do command's work here 

    Control.MoveFocus(); 

} 

... y si usted no sabe lo que el control es enfocado actualmente, sólo puede hacer esto ...

(Keyboard.FocusedElement as FrameworkElement).MoveFocus(); 

Espero que esto ayude! Si es así, ¡lo valoro mucho si me votas o lo marcas como aceptado!

+0

El ViewModel no tiene ningún FrameworkElement para mover el foco. – Nick