Partager via


Interface utilisateur imbriquée dans les éléments de liste

L’interface utilisateur imbriquée est une interface utilisateur qui expose des contrôles actionnables imbriqués placés dans un conteneur qui peuvent également prendre le focus indépendant.

Vous pouvez utiliser l’interface utilisateur imbriquée pour présenter à un utilisateur des options supplémentaires qui permettent d’accélérer l’exécution d’actions importantes. Toutefois, plus vous exposez d’actions, plus votre interface utilisateur devient complexe. Vous devez prendre soin lorsque vous choisissez d’utiliser ce modèle d’interface utilisateur. Cet article fournit des instructions pour vous aider à déterminer le meilleur cours d’action pour votre interface utilisateur particulière.

API importantes : classe ListView, classe GridView

Dans cet article, nous abordons la création d’une interface utilisateur imbriquée dans les éléments ListView et GridView . Bien que cette section ne parle pas d’autres cas d’interface utilisateur imbriquée, ces concepts sont transférables. Avant de commencer, vous devez être familiarisé avec les conseils généraux relatifs à l’utilisation des contrôles ListView ou GridView dans votre interface utilisateur, qui se trouvent dans les articles Listes et Vue liste et vue grille.

Dans cet article, nous utilisons les termes liste, élément de liste et interface utilisateur imbriquée, tels que définis ici :

  • La liste fait référence à une collection d’éléments contenus dans un affichage de liste ou une vue grille.
  • L’élément de liste fait référence à un élément individuel sur lequel un utilisateur peut prendre des mesures dans une liste.
  • L’interface utilisateur imbriquée désigne les éléments d’interface utilisateur d’un élément de liste sur lesquels un utilisateur peut agir indépendamment de l'élément de liste lui-même.

Capture d’écran montrant les parties d’un U I imbriqué.

REMARQUE ListView et GridView dérivent tous deux de la classe ListViewBase , de sorte qu’ils ont les mêmes fonctionnalités, mais affichent les données différemment. Dans cet article, lorsque nous parlons de listes, les informations s’appliquent aux contrôles ListView et GridView.

Actions primaires et secondaires

Lors de la création d’une interface utilisateur avec une liste, tenez compte des actions que l’utilisateur peut entreprendre à partir de ces éléments de liste.

  • Un utilisateur peut-il cliquer sur l’élément pour effectuer une action ?
    • En règle générale, le fait de cliquer sur un élément de liste lance une action, mais il n'est pas obligé de le faire.
  • Existe-t-il plusieurs actions que l’utilisateur peut entreprendre ?
    • Par exemple, l’appui sur un e-mail dans une liste ouvre cet e-mail. Toutefois, il peut y avoir d’autres actions, comme la suppression de l’e-mail, que l’utilisateur souhaite prendre sans l’ouvrir en premier. Il serait avantageux pour l’utilisateur d’accéder à cette action directement dans la liste.
  • Comment les actions doivent-elle être exposées à l’utilisateur ?
    • Considérez tous les types d’entrée. Certaines formes d’interface utilisateur imbriquée fonctionnent très bien avec une méthode d’entrée, mais peuvent ne pas fonctionner avec d’autres méthodes.

L’action principale est ce que l’utilisateur s’attend à ce qu’il se produise lorsqu’il appuie sur l’élément de liste.

Les actions secondaires sont généralement des accélérateurs associés aux éléments de liste. Ces accélérateurs peuvent être destinés à la gestion de liste ou aux actions liées à l’élément de liste.

Options pour les actions secondaires

Lors de la création de l’interface utilisateur de liste, vous devez d’abord vous assurer que vous devez prendre en compte toutes les méthodes d’entrée que Windows prend en charge. Pour plus d’informations sur différents types d’entrée, consultez l’aperçu d’entrée.

Une fois que vous avez assuré que votre application prend en charge toutes les entrées prises en charge par Windows, vous devez décider si les actions secondaires de votre application sont suffisamment importantes pour exposer en tant qu’accélérateurs dans la liste principale. N’oubliez pas que plus vous exposez les actions que vous exposez, plus votre interface utilisateur devient complexe. Avez-vous vraiment besoin d’exposer les actions secondaires dans l’interface utilisateur de liste principale, ou pouvez-vous les placer ailleurs ?

Vous pouvez envisager d’exposer des actions supplémentaires dans l’interface utilisateur de liste principale lorsque ces actions doivent être accessibles à tout moment par n’importe quelle entrée.

Si vous décidez que le fait de placer des actions secondaires dans l’interface utilisateur de liste principale n’est pas nécessaire, il existe plusieurs autres façons de les exposer à l’utilisateur. Voici quelques options que vous pouvez prendre en compte pour l’emplacement où placer des actions secondaires.

Placer des actions secondaires sur la page de détails

Placez les actions secondaires sur la page vers laquelle l’élément de liste accède lorsqu’il est appuyé. Lorsque vous utilisez le modèle liste/détails, la page de détails est souvent un bon endroit pour mettre des actions secondaires.

Pour plus d’informations, consultez le modèle liste/détail.

Placer des actions secondaires dans un menu contextuel

Placez les actions secondaires dans un menu contextuel auquel l’utilisateur peut accéder via un clic droit ou appuyez longuement. Cela offre l’avantage de permettre à l’utilisateur d’effectuer une action, telle que la suppression d’un e-mail, sans avoir à charger la page de détails. Il est recommandé de rendre ces options disponibles sur la page de détails, car les menus contextuels sont destinés à être des accélérateurs plutôt que l’interface utilisateur principale.

Pour exposer des actions secondaires lorsque l’entrée provient d’un boîtier de commande ou d’un contrôle à distance, nous vous recommandons d’utiliser un menu contextuel.

Pour plus d’informations, consultez menus contextuels et panneaux déroulants.

Placer des actions secondaires dans l'interface de pointage pour optimiser l'utilisation du pointeur.

Si vous attendez que votre application soit fréquemment utilisée avec des entrées de pointeur telles que la souris et le stylet, et que vous souhaitez rendre les actions secondaires facilement disponibles uniquement pour ces entrées, vous pouvez afficher les actions secondaires uniquement sur le pointage. Cet accélérateur est visible uniquement lorsqu’une entrée de pointeur est utilisée. Veillez donc à utiliser les autres options pour prendre en charge d’autres types d’entrée.

Interface utilisateur imbriquée affichée au survol

Pour plus d’informations, consultez interactions avec la souris.

Placement de l’interface utilisateur pour les actions primaires et secondaires

Si vous décidez que les actions secondaires doivent être exposées dans l’interface utilisateur de liste principale, nous vous recommandons les instructions suivantes.

Lorsque vous créez un élément de liste avec des actions primaires et secondaires, placez l’action principale à gauche et les actions secondaires à droite. Dans les cultures de lecture de gauche à droite, les utilisateurs associent des actions sur le côté gauche de l’élément de liste comme action principale.

Dans ces exemples, nous parlons de l’interface utilisateur de liste où l’élément circule plus horizontalement (il est plus large que sa hauteur). Toutefois, vous pouvez avoir des éléments de liste qui sont plus carrés en forme, ou plus hauts que leur largeur. En règle générale, il s’agit d’éléments utilisés dans une grille. Pour ces éléments, si la liste ne fait pas défiler verticalement, vous pouvez placer les actions secondaires en bas de l’élément de liste plutôt qu’à droite.

Prendre en compte toutes les entrées

Lorsque vous décidez d’utiliser l’interface utilisateur imbriquée, évaluez également l’expérience utilisateur avec tous les types d’entrée. Comme mentionné précédemment, l’interface utilisateur imbriquée fonctionne parfaitement pour certains types d’entrée. Toutefois, il ne fonctionne pas toujours très bien pour d’autres. En particulier, le clavier, le contrôleur et les entrées distantes peuvent avoir des difficultés à accéder aux éléments d’interface utilisateur imbriqués. Veillez à suivre les instructions ci-dessous pour vous assurer que votre Windows fonctionne avec tous les types d’entrée.

Gestion de l’interface utilisateur imbriquée

Lorsque vous avez plusieurs actions imbriquées dans l’élément de liste, nous vous recommandons de gérer la navigation avec un clavier, un boîtier de commande, un contrôle à distance ou une autre entrée non pointeur.

Interface utilisateur imbriquée où les éléments de liste effectuent une action

Si votre interface utilisateur de liste avec des éléments imbriqués prend en charge des actions telles que l’invocation, la sélection (unique ou multiple) ou les opérations de glisser-déplacer, nous vous recommandons de suivre ces techniques de navigation par flèches pour naviguer à travers les éléments imbriqués de votre interface utilisateur.

Capture d’écran montrant les éléments U I imbriqués étiquetés avec les lettres A, B, C et D.

Boîtier de commande

Lorsque l’entrée provient d’une manette, fournissez cette expérience utilisateur :

  • De A, la touche directionnelle droite met le focus sur B.
  • De B, la touche directionnelle droite met le focus sur C.
  • À partir de C, la touche directionnelle droite est soit sans effet, soit, s'il existe un élément d'interface utilisateur pouvant être focalisé à droite de la liste, placez-y le focus.
  • À partir de C, la touche directionnelle gauche met le focus sur B.
  • À partir de B, la touche directionnelle gauche met le focus sur A.
  • À partir de A, la touche directionnelle gauche n’est pas op, ou s’il existe un élément d’interface utilisateur focusable à droite de List, placez le focus là-bas.
  • À partir de A, B ou C, la touche directionnelle vers le bas met le focus sur D.
  • De l’élément d’interface utilisateur à gauche de l’élément de liste, la touche directionnelle droite met le focus sur A.
  • De l’élément d’interface utilisateur à droite de l’élément de liste, la touche directionnelle gauche met le focus sur A.

Keyboard

Lorsque l’entrée provient d’un clavier, il s’agit de l’expérience que l’utilisateur obtient :

  • À partir de A, la touche tabulation déplace le focus sur B.
  • À partir de B, la touche tabulation met le focus sur C.
  • À partir de C, la touche tabulation met le focus sur l’élément d’interface utilisateur focusable suivant dans l’ordre de tabulation.
  • À partir de C, Maj+Tabulation déplace le focus sur B.
  • À partir de B, Maj+Tabulation ou flèche gauche déplace le focus sur A.
  • À partir de A, maj+tabulation met le focus sur l’élément d’interface utilisateur focusable suivant dans l’ordre de tabulation inverse.
  • À partir de A, B ou C, la touche de direction vers le bas met le focus sur D.
  • Depuis l’élément d’interface utilisateur à gauche de l’élément de liste, la touche de tabulation place le focus sur A.
  • De l'élément d'UI à droite de l'élément de liste, la combinaison de touches Maj + Tab met le focus sur C.

Pour obtenir cette interface utilisateur, définissez IsItemClickEnabled sur true sur votre liste. SelectionMode peut être n’importe quelle valeur.

Pour le code nécessaire à l'implémentation, consultez la section Exemple de cet article.

Interface utilisateur imbriquée où les éléments de liste n’effectuent pas d’action

Vous pouvez utiliser un affichage de liste, car il fournit un comportement de défilement optimisé et de virtualisation, mais n’a pas d’action associée à un élément de liste. Ces interfaces utilisateur utilisent généralement l’élément de liste uniquement pour regrouper les éléments et s’assurer qu’ils défilent sous la forme d’un ensemble.

Ce type d’interface utilisateur a tendance à être beaucoup plus compliqué que les exemples précédents, avec un grand nombre d’éléments imbriqués sur lesquels l'utilisateur peut agir.

Capture d’écran d’un U imbriqué complexe montrant un grand nombre d’éléments imbriqués avec lesquels l’utilisateur peut interagir.

Pour obtenir cette interface utilisateur, définissez les propriétés suivantes dans votre liste :

<ListView SelectionMode="None" IsItemClickEnabled="False" >
    <ListView.ItemContainerStyle>
         <Style TargetType="ListViewItem">
             <Setter Property="IsFocusEngagementEnabled" Value="True"/>
         </Style>
    </ListView.ItemContainerStyle>
</ListView>

Lorsque les éléments de liste n’effectuent pas d’action, nous vous recommandons de gérer la navigation avec un boîtier de commande ou un clavier.

Boîtier de commande

Lorsque l’entrée provient d’une manette, fournissez cette expérience utilisateur :

  • Dans l’élément de liste, la touche directionnelle vers le bas met le focus sur l’élément de liste suivant.
  • Dans l'élément de liste, la touche gauche/droite ne fait rien; ou s'il existe un élément d'interface utilisateur focusable à droite de la liste, placez le focus sur cet élément.
  • À partir de l’élément de liste, le bouton « A » place le focus sur l’interface utilisateur imbriquée en priorité supérieure/gauche/droite.
  • Dans l’interface utilisateur imbriquée, suivez le modèle de navigation XY Focus. Le focus ne peut naviguer que dans l’interface utilisateur imbriquée contenue dans l’élément de liste actif jusqu’à ce que l’utilisateur appuie sur le bouton « B », ce qui rétablit le focus sur l’élément de liste.

Keyboard

Lorsque l’entrée provient d’un clavier, il s’agit de l’expérience que l’utilisateur obtient :

  • Dans l’élément de liste, la flèche vers le bas met le focus sur l’élément de liste suivant.
  • Dans l’élément de liste, appuyer sur la touche gauche/droite n’a aucun effet.
  • À partir de l’élément de liste, l’appui sur la touche Tab place le focus sur le prochain point de tabulation dans l’élément d’interface utilisateur imbriqué.
  • À partir d'un élément d'interface utilisateur imbriqué, appuyer sur la touche Tab permet de parcourir les éléments imbriqués dans l'ordre de tabulation. Une fois que tous les éléments d'interface utilisateur imbriqués sont parcourus, il place le focus sur le contrôle suivant dans l'ordre de tabulation après ListView.
  • Maj+Tab se comporte dans le sens inverse du comportement de l’onglet.

Example

Cet exemple montre comment implémenter l’interface utilisateur imbriquée où les éléments de liste effectuent une action.

<ListView SelectionMode="None" IsItemClickEnabled="True"
          ChoosingItemContainer="listview1_ChoosingItemContainer"/>
private void OnListViewItemKeyDown(object sender, KeyRoutedEventArgs e)
{
    // Code to handle going in/out of nested UI with gamepad and remote only.
    if (e.Handled == true)
    {
        return;
    }

    var focusedElementAsListViewItem = FocusManager.GetFocusedElement() as ListViewItem;
    if (focusedElementAsListViewItem != null)
    {
        // Focus is on the ListViewItem.
        // Go in with Right arrow.
        Control candidate = null;

        switch (e.OriginalKey)
        {
            case Windows.System.VirtualKey.GamepadDPadRight:
            case Windows.System.VirtualKey.GamepadLeftThumbstickRight:
                var rawPixelsPerViewPixel = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
                GeneralTransform generalTransform = focusedElementAsListViewItem.TransformToVisual(null);
                Point startPoint = generalTransform.TransformPoint(new Point(0, 0));
                Rect hintRect = new Rect(startPoint.X * rawPixelsPerViewPixel, startPoint.Y * rawPixelsPerViewPixel, 1, focusedElementAsListViewItem.ActualHeight * rawPixelsPerViewPixel);
                candidate = FocusManager.FindNextFocusableElement(FocusNavigationDirection.Right, hintRect) as Control;
                break;
        }

        if (candidate != null)
        {
            candidate.Focus(FocusState.Keyboard);
            e.Handled = true;
        }
    }
    else
    {
        // Focus is inside the ListViewItem.
        FocusNavigationDirection direction = FocusNavigationDirection.None;
        switch (e.OriginalKey)
        {
            case Windows.System.VirtualKey.GamepadDPadUp:
            case Windows.System.VirtualKey.GamepadLeftThumbstickUp:
                direction = FocusNavigationDirection.Up;
                break;
            case Windows.System.VirtualKey.GamepadDPadDown:
            case Windows.System.VirtualKey.GamepadLeftThumbstickDown:
                direction = FocusNavigationDirection.Down;
                break;
            case Windows.System.VirtualKey.GamepadDPadLeft:
            case Windows.System.VirtualKey.GamepadLeftThumbstickLeft:
                direction = FocusNavigationDirection.Left;
                break;
            case Windows.System.VirtualKey.GamepadDPadRight:
            case Windows.System.VirtualKey.GamepadLeftThumbstickRight:
                direction = FocusNavigationDirection.Right;
                break;
            default:
                break;
        }

        if (direction != FocusNavigationDirection.None)
        {
            Control candidate = FocusManager.FindNextFocusableElement(direction) as Control;
            if (candidate != null)
            {
                ListViewItem listViewItem = sender as ListViewItem;

                // If the next focusable candidate to the left is outside of ListViewItem,
                // put the focus on ListViewItem.
                if (direction == FocusNavigationDirection.Left &&
                    !listViewItem.IsAncestorOf(candidate))
                {
                    listViewItem.Focus(FocusState.Keyboard);
                }
                else
                {
                    candidate.Focus(FocusState.Keyboard);
                }
            }

            e.Handled = true;
        }
    }
}

private void listview1_ChoosingItemContainer(ListViewBase sender, ChoosingItemContainerEventArgs args)
{
    if (args.ItemContainer == null)
    {
        args.ItemContainer = new ListViewItem();
        args.ItemContainer.KeyDown += OnListViewItemKeyDown;
    }
}
// DependencyObjectExtensions.cs definition.
public static class DependencyObjectExtensions
{
    public static bool IsAncestorOf(this DependencyObject parent, DependencyObject child)
    {
        DependencyObject current = child;
        bool isAncestor = false;

        while (current != null && !isAncestor)
        {
            if (current == parent)
            {
                isAncestor = true;
            }

            current = VisualTreeHelper.GetParent(current);
        }

        return isAncestor;
    }
}