Compartir a través de


Visión general del enfoque

En WPF hay dos conceptos principales relacionados con el foco: el foco del teclado y el enfoque lógico. El foco de teclado hace referencia al elemento que recibe la entrada del teclado y el foco lógico hace referencia al elemento de un ámbito de foco que tiene el foco. Estos conceptos se describen detalladamente en esta introducción. Comprender la diferencia en estos conceptos es importante para crear aplicaciones complejas que tienen varias regiones donde se puede obtener el foco.

Las clases principales que participan en la administración del foco son la Keyboard clase, la FocusManager clase y las clases de elemento base, como UIElement y ContentElement. Para obtener más información sobre los elementos base, vea Información general sobre elementos base.

La Keyboard clase se preocupa principalmente por el foco del teclado y se preocupa principalmente por el FocusManager foco lógico, pero esto no es una distinción absoluta. Un elemento que tenga el foco del teclado también tendrá el foco lógico, pero un elemento que tiene el foco lógico no necesariamente tiene el foco del teclado. Esto es evidente cuando se usa la Keyboard clase para establecer el elemento que tiene el foco del teclado, para que también establezca el foco lógico en el elemento.

Foco del teclado

El foco del teclado hace referencia al elemento que recibe actualmente la entrada del teclado. Solo puede haber un elemento en todo el escritorio que tenga el foco del teclado. En WPF, el elemento que tiene el foco de teclado tendrá IsKeyboardFocused establecido en true. La propiedad estática FocusedElement de la clase Keyboard obtiene el elemento que actualmente tiene el foco del teclado.

Para que un elemento obtenga el foco del teclado, las propiedades Focusable y IsVisible en los elementos base deben establecerse en true. Algunas clases, como la Panel clase base, se ha establecido en Focusable por defecto; por lo tanto, debe establecer false en Focusable si desea que dicho elemento pueda obtener el foco del teclado.

El foco del teclado se puede obtener a través de la interacción por parte del usuario con la interfaz de usuario, como navegar hasta un elemento o hacer clic con el ratón en determinados elementos. El foco del teclado también se puede obtener mediante programación mediante el Focus método de la Keyboard clase . El Focus método intenta proporcionar el foco del teclado al elemento especificado. El elemento devuelto es el elemento que tiene el foco del teclado, que puede ser un elemento diferente al solicitado si el objeto de foco anterior o nuevo bloquea la solicitud.

En el ejemplo siguiente se usa el método Focus para establecer el foco del teclado en un Button.

private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}
Private Sub OnLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
    ' Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton)
End Sub

La IsKeyboardFocused propiedad de las clases de elemento base obtiene un valor que indica si el elemento tiene el foco del teclado. La IsKeyboardFocusWithin propiedad de las clases de elemento base obtiene un valor que indica si el elemento o cualquiera de sus elementos secundarios visuales tiene el foco del teclado.

Al establecer el foco inicial al inicio de la aplicación, el elemento que recibirá el foco debe estar en el árbol visual de la ventana inicial cargada por la aplicación; además, el elemento debe tener Focusable y IsVisible configurados con true. El lugar recomendado para establecer el foco inicial está en el Loaded controlador de eventos. También se puede usar un Dispatcher callback llamando a Invoke o BeginInvoke.

Foco lógico

El foco lógico hace referencia al FocusManager.FocusedElement en un ámbito de enfoque. Un alcance de enfoque es un elemento que realiza un seguimiento del FocusedElement dentro de su alcance. Cuando el foco del teclado deja un ámbito de foco, el elemento centrado perderá el foco del teclado, pero conservará el foco lógico. Cuando el enfoque del teclado vuelve al ámbito de enfoque, el elemento enfocado obtendrá el enfoque del teclado. Esto permite cambiar el foco del teclado entre varios ámbitos de foco, pero garantiza que el elemento centrado en el ámbito de foco recupere el foco del teclado cuando el foco vuelva al ámbito del foco.

Puede haber varios elementos que tengan el foco lógico en una aplicación, pero solo puede haber un elemento que tenga el foco lógico en un ámbito de enfoque determinado.

Un elemento que tiene el foco del teclado tiene el enfoque lógico para el ámbito de enfoque al que pertenece.

Un elemento se puede convertir en un ámbito de enfoque en el Lenguaje de Marcado Extensible de Aplicaciones (XAML) estableciendo la propiedad adjunta FocusManagerIsFocusScope a true. En el código, un elemento se puede convertir en un ámbito de foco llamando a SetIsFocusScope.

En el ejemplo siguiente, StackPanel se convierte en un ámbito de foco al establecer la propiedad adjunta IsFocusScope.

<StackPanel Name="focusScope1" 
            FocusManager.IsFocusScope="True"
            Height="200" Width="200">
  <Button Name="button1" Height="50" Width="50"/>
  <Button Name="button2" Height="50" Width="50"/>
</StackPanel>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);
Dim focuseScope2 As New StackPanel()
FocusManager.SetIsFocusScope(focuseScope2, True)

GetFocusScope devuelve el ámbito de foco del elemento especificado.

Las clases de WPF que son ámbitos de foco de forma predeterminada son Window, MenuItem, ToolBary ContextMenu.

GetFocusedElement obtiene el elemento centrado para el ámbito de foco especificado. SetFocusedElement establece el elemento centrado en el ámbito de foco especificado. SetFocusedElement normalmente se usa para establecer el elemento centrado inicial.

En el ejemplo siguiente se establece el elemento centrado en un ámbito de foco y se obtiene el elemento centrado de un ámbito de foco.

// Sets the focused element in focusScope1
// focusScope1 is a StackPanel.
FocusManager.SetFocusedElement(focusScope1, button2);

// Gets the focused element for focusScope 1
IInputElement focusedElement = FocusManager.GetFocusedElement(focusScope1);
' Sets the focused element in focusScope1
' focusScope1 is a StackPanel.
FocusManager.SetFocusedElement(focusScope1, button2)

' Gets the focused element for focusScope 1
Dim focusedElement As IInputElement = FocusManager.GetFocusedElement(focusScope1)

Navegación mediante teclado

La KeyboardNavigation clase es responsable de implementar la navegación predeterminada del foco del teclado cuando se presiona una de las teclas de navegación. Las teclas de navegación son: TAB, MAYÚS+TAB, CTRL+TAB, CTRL+MAYÚS+TAB, UPARROW, DOWNARROW, LEFTARROW y RIGHTARROW.

El comportamiento de navegación de un contenedor de navegación se puede cambiar estableciendo las propiedades adjuntas KeyboardNavigationTabNavigation, ControlTabNavigationy DirectionalNavigation. Estas propiedades son de tipo KeyboardNavigationMode y los valores posibles son Continue, Local, Contained, Cycle, Oncey None. El valor predeterminado es Continue, lo que significa que el elemento no es un contenedor de navegación.

En el siguiente ejemplo se crea un Menu con varios objetos MenuItem. La TabNavigation propiedad adjunta se establece en Cycle en el Menu. Cuando se cambia el foco mediante la tecla de tabulación dentro de Menu, el foco se moverá de cada elemento y cuando se alcance el último elemento, el foco volverá al primer elemento.

<Menu KeyboardNavigation.TabNavigation="Cycle">
  <MenuItem Header="Menu Item 1" />
  <MenuItem Header="Menu Item 2" />
  <MenuItem Header="Menu Item 3" />
  <MenuItem Header="Menu Item 4" />
</Menu>
Menu navigationMenu = new Menu();
MenuItem item1 = new MenuItem();
MenuItem item2 = new MenuItem();
MenuItem item3 = new MenuItem();
MenuItem item4 = new MenuItem();

navigationMenu.Items.Add(item1);
navigationMenu.Items.Add(item2);
navigationMenu.Items.Add(item3);
navigationMenu.Items.Add(item4);

KeyboardNavigation.SetTabNavigation(navigationMenu,
    KeyboardNavigationMode.Cycle);
Dim navigationMenu As New Menu()
Dim item1 As New MenuItem()
Dim item2 As New MenuItem()
Dim item3 As New MenuItem()
Dim item4 As New MenuItem()

navigationMenu.Items.Add(item1)
navigationMenu.Items.Add(item2)
navigationMenu.Items.Add(item3)
navigationMenu.Items.Add(item4)

KeyboardNavigation.SetTabNavigation(navigationMenu, KeyboardNavigationMode.Cycle)

La API adicional para trabajar con el foco es MoveFocus y PredictFocus.

MoveFocus cambia el foco al siguiente elemento de la aplicación. TraversalRequest Se usa para especificar la dirección. El FocusNavigationDirection objeto pasado a MoveFocus especifica que se puede mover el enfoque en direcciones diferentes, como First, Last, Up y Down.

En el ejemplo siguiente se usa MoveFocus para cambiar el elemento centrado.

// Creating a FocusNavigationDirection object and setting it to a
// local field that contains the direction selected.
FocusNavigationDirection focusDirection = _focusMoveValue;

// MoveFocus takes a TraveralReqest as its argument.
TraversalRequest request = new TraversalRequest(focusDirection);

// Gets the element with keyboard focus.
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;

// Change keyboard focus.
if (elementWithFocus != null)
{
    elementWithFocus.MoveFocus(request);
}
' Creating a FocusNavigationDirection object and setting it to a
' local field that contains the direction selected.
Dim focusDirection As FocusNavigationDirection = _focusMoveValue

' MoveFocus takes a TraveralReqest as its argument.
Dim request As New TraversalRequest(focusDirection)

' Gets the element with keyboard focus.
Dim elementWithFocus As UIElement = TryCast(Keyboard.FocusedElement, UIElement)

' Change keyboard focus.
If elementWithFocus IsNot Nothing Then
    elementWithFocus.MoveFocus(request)
End If

PredictFocus devuelve el objeto que recibiría el foco si se cambiara el foco. Actualmente, solo Up, Down, Left, y Right son compatibles con PredictFocus.

Eventos de foco

Los eventos relacionados con el foco del teclado son PreviewGotKeyboardFocus, GotKeyboardFocus y PreviewLostKeyboardFocus, LostKeyboardFocus. Los eventos se definen como eventos adjuntos en la Keyboard clase , pero son más accesibles como eventos enrutados equivalentes en las clases de elemento base. Para obtener más información sobre los eventos, consulte la Visión general de los eventos enrutados.

GotKeyboardFocus se genera cuando el elemento obtiene el foco del teclado. LostKeyboardFocus se genera cuando el elemento pierde el foco del teclado. Si el evento PreviewGotKeyboardFocus o el evento PreviewLostKeyboardFocusEvent está controlado y Handled se establece en true, entonces el foco no cambiará.

En el ejemplo siguiente se adjuntan GotKeyboardFocus controladores de eventos y LostKeyboardFocus a .TextBox

<Border BorderBrush="Black" BorderThickness="1"
        Width="200" Height="100" Margin="5">
  <StackPanel>
    <Label HorizontalAlignment="Center" Content="Type Text In This TextBox" />
    <TextBox Width="175"
             Height="50" 
             Margin="5"
             TextWrapping="Wrap"
             HorizontalAlignment="Center"
             VerticalScrollBarVisibility="Auto"
             GotKeyboardFocus="TextBoxGotKeyboardFocus"
             LostKeyboardFocus="TextBoxLostKeyboardFocus"
             KeyDown="SourceTextKeyDown"/>
  </StackPanel>
</Border>

Cuando el TextBox obtiene el foco del teclado, la propiedad Background del TextBox se cambia a LightBlue.

private void TextBoxGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    TextBox source = e.Source as TextBox;

    if (source != null)
    {
        // Change the TextBox color when it obtains focus.
        source.Background = Brushes.LightBlue;

        // Clear the TextBox.
        source.Clear();
    }
}
Private Sub TextBoxGotKeyboardFocus(ByVal sender As Object, ByVal e As KeyboardFocusChangedEventArgs)
    Dim source As TextBox = TryCast(e.Source, TextBox)

    If source IsNot Nothing Then
        ' Change the TextBox color when it obtains focus.
        source.Background = Brushes.LightBlue

        ' Clear the TextBox.
        source.Clear()
    End If
End Sub

Cuando el TextBox pierde el foco del teclado, la propiedad Background del TextBox se cambia de nuevo a blanco.

private void TextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    TextBox source = e.Source as TextBox;

    if (source != null)
    {
        // Change the TextBox color when it loses focus.
        source.Background = Brushes.White;

        // Set the  hit counter back to zero and updates the display.
        this.ResetCounter();
    }
}
Private Sub TextBoxLostKeyboardFocus(ByVal sender As Object, ByVal e As KeyboardFocusChangedEventArgs)
    Dim source As TextBox = TryCast(e.Source, TextBox)

    If source IsNot Nothing Then
        ' Change the TextBox color when it loses focus.
        source.Background = Brushes.White

        ' Set the  hit counter back to zero and updates the display.
        Me.ResetCounter()
    End If
End Sub

Los eventos relacionados con el foco lógico son GotFocus y LostFocus. Estos eventos se definen en como FocusManager eventos adjuntos, pero FocusManager no expone contenedores de eventos CLR. UIElement y ContentElement exponen estos eventos de forma más cómoda.

Consulte también