Vue d'ensemble du focus

Dans WPF, il existe deux concepts principaux associés au focus : le focus clavier et le focus logique. Le focus clavier fait référence à l'élément qui reçoit une entrée au clavier, tandis que le focus logique fait référence à l'élément d'une portée de focus qui a le focus. Ces concepts sont présentés en détail dans cette vue d'ensemble. Il est important de bien comprendre les différences entre ces concepts lors de la création d'applications complexes qui comportent plusieurs régions où le focus peut être obtenu.

Les principales classes impliquées par la gestion du focus sont les classes Keyboard et FocusManager, ainsi que les classes d'élément de base telles que UIElement et ContentElement. Pour plus d'informations sur les éléments de base, consultez Vue d'ensemble des éléments de base.

La classe Keyboard est principalement responsable du focus clavier et la classe FocusManager du focus logique. Il ne s'agit toutefois pas d'une distinction absolue. En effet, un élément qui a le focus clavier possède également le focus logique, tandis qu'un élément qui a le focus logique ne possède pas nécessairement le focus clavier. Ce principe se vérifie lorsque vous utilisez la classe Keyboard pour définir l'élément qui a le focus clavier, car elle définit également le focus logique sur l'élément.

Cette rubrique comprend les sections suivantes.

  • Focus clavier
  • Focus logique
  • Navigation au clavier
  • Navigation du focus par programme
  • Événements de focus
  • Rubriques connexes

Focus clavier

Le focus clavier fait référence à l'élément qui reçoit actuellement l'entrée au clavier. Un seul élément de l'ordinateur peut avoir le focus clavier. Dans WPF, le IsKeyboardFocused de l'élément qui a le focus clavier est affecté à la valeur true. La propriété statique FocusedElement de la classe Keyboard obtient l'élément qui a actuellement le focus clavier.

Pour qu'un élément puisse obtenir le focus clavier, les propriétés Focusable et IsVisible doivent avoir la valeur true pour les éléments de base. Pour certaines classes, comme la classe de base Panel, Focusable a par défaut la valeur false. Par conséquent, vous devez définir Focusable sur la valeur true si vous souhaitez que ce type d'élément puisse obtenir le focus clavier.

Le focus clavier peut être obtenu par intervention de l'utilisateur à l'aide de l'UI (tabulation vers un élément ou clic de souris sur certains éléments, par exemple). Le focus clavier peut également être obtenu par programme en utilisant la méthode Focus sur la classe Keyboard. La méthode Focus tente d'accorder le focus clavier à l'élément spécifié. L'élément retourné correspond à l'élément qui a le focus clavier. Il peut s'agir d'un autre élément que celui demandé si l'objet de focus précédent ou le nouveau bloque la demande.

L'exemple suivant utilise la méthode Focus pour placer le focus clavier sur un Button.

        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
private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}

La propriété IsKeyboardFocused des classes d'élément de base obtient une valeur qui indique si l'élément a le focus clavier. La propriété IsKeyboardFocusWithin des classes d'élément de base obtient une valeur qui indique si l'élément ou l'un de ses éléments enfants visuels a le focus clavier.

Lors de la configuration du focus initial au démarrage de l'application, l'élément devant recevoir le focus doit se situer dans l'arborescence d'éléments visuels de la fenêtre initiale chargée par l'application, et la valeur true doit être affectée à Focusable et IsVisible. Il est recommandé de définir le focus initial dans le gestionnaire d'événements Loaded. Un rappel Dispatcher peut également être utilisé en appelant Invoke ou BeginInvoke.

Focus logique

Le focus logique fait référence à FocusManager.FocusedElement dans une portée de focus. Une portée de focus est un élément qui effectue le suivi de FocusedElement dans sa portée. Lorsque le focus clavier quitte une portée de focus, l'élément ayant le focus perd le focus clavier, mais il conserve le focus logique. Lorsque le focus clavier revient dans la portée de focus, l'élément ayant le focus obtient le focus clavier. Cela permet au focus clavier de changer entre des portées de focus et de s'assurer que l'élément ayant le focus dans la portée de focus retrouve le focus clavier lorsque le focus revient dans la portée de focus.

Plusieurs éléments d'une application peuvent avoir le focus logique, mais un seul élément peut avoir le focus logique dans une portée de focus donnée.

Un élément ayant le focus clavier a également le focus logique pour la portée de focus à laquelle il appartient.

Un élément peut être converti en portée de focus en langage Extensible Application Markup Language (XAML) en affectant à la propriété jointe IsFocusScope de FocusManager la valeur true. Dans le code, cette conversion peut être réalisée en appelant SetIsFocusScope.

L'exemple suivant convertit un StackPanel en portée de focus en définissant la propriété attachée 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>
            Dim focuseScope2 As New StackPanel()
            FocusManager.SetIsFocusScope(focuseScope2, True)
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);

GetFocusScope retourne la portée de focus pour l'élément spécifié.

Dans WPF, les classes ayant des portées de focus par défaut sont Window, MenuItem, ToolBar et ContextMenu.

GetFocusedElement reçoit l'élément ayant le focus pour la portée de focus spécifiée. SetFocusedElement définit l'élément ayant le focus dans la portée de focus spécifiée. SetFocusedElement est généralement utilisé pour définir l'élément ayant le focus initial.

L'exemple suivant définit l'élément ayant le focus dans une portée de focus et obtient l'élément ayant le focus d'une portée de focus.

            ' 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)
// 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);

La classe KeyboardNavigation est chargée d'implémenter la navigation du focus clavier par défaut lorsque l'utilisateur appuie sur l'une des touches de navigation. Les touches de navigation sont les suivantes : TAB, MAJ+TAB, CTRL+TAB, CTRL+MAJ+TAB, FLÈCHE HAUT, FLÈCHE BAS, FLÈCHE GAUCHE et FLÈCHE DROITE.

Le comportement de navigation d'un conteneur de navigation peut être modifié en définissant les propriétés attachées TabNavigation, ControlTabNavigation et DirectionalNavigation de KeyboardNavigation. Ces propriétés sont du type KeyboardNavigationMode et les valeurs possibles sont Continue, Local, Contained, Cycle, Once et None. La valeur par défaut (Continue) indique que l'élément ne correspond pas à un conteneur de navigation.

L'exemple suivant crée un Menu contenant plusieurs objets MenuItem. La propriété attachée TabNavigation a la valeur Cycle dans Menu. Lorsque le focus est modifié à l'aide de la touche Tab dans Menu, il se détache de chaque élément, puis retourne au premier élément une fois qu'il a atteint le dernier.

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

MoveFocus et PredictFocus constituent des API supplémentaires permettant d'utiliser le focus.

MoveFocus fait passer le focus à l'élément suivant dans l'application. Un TraversalRequest est utilisé pour spécifier la direction. Le FocusNavigationDirection passé à MoveFocus spécifie les différentes directions du focus, comme First, Last, Up et Down.

L'exemple suivant utilise MoveFocus pour modifier l'élément ayant le focus.

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

PredictFocus retourne l'objet qui recevrait le focus si celui-ci venait à changer. Actuellement, seuls Up, Down, Left et Right sont pris en charge par PredictFocus.

Événements de focus

Les événements liés au focus clavier sont PreviewGotKeyboardFocus, GotKeyboardFocus et PreviewLostKeyboardFocus, LostKeyboardFocus. Les événements sont définis en tant qu'événements attachés dans la classe Keyboard. Il est toutefois plus facile d'y accéder s'ils correspondent à des événements routés équivalents dans les classes d'élément de base. Pour plus d'informations sur les événements, consultez Vue d'ensemble des événements routés.

GotKeyboardFocus est déclenché lorsque l'élément obtient le focus clavier. LostKeyboardFocus est déclenché lorsque l'élément perd le focus clavier. Le focus ne change pas si l'événement PreviewGotKeyboardFocus ou PreviewLostKeyboardFocusEvent est géré et que Handled a la valeur true.

L'exemple suivant attache les gestionnaires d'événements GotKeyboardFocus et LostKeyboardFocus à un 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>

Lorsque TextBox obtient le focus clavier, la propriété Background de TextBox est remplacée par LightBlue.

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

Lorsque TextBox perd le focus clavier, la propriété Background de TextBox reprend la couleur blanche.

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

Les événements liés au focus logique sont GotFocus et LostFocus. Ces événements sont définis dans le FocusManager en tant qu'événements attachés. Toutefois, le FocusManager n'expose pas les wrappers d'événement CLR. UIElement et ContentElement exposent ces événements sous une forme plus pratique.

Voir aussi

Référence

FocusManager

UIElement

ContentElement

Concepts

Vue d'ensemble des entrées

Vue d'ensemble des éléments de base