Compartir a través de


Interfaz de usuario anidada en elementos de lista

La interfaz de usuario anidada es una interfaz de usuario que muestra controles interactivos anidados contenidos dentro de un contenedor que también puede enfocarse de manera independiente.

Puede usar la interfaz de usuario anidada para presentar a un usuario opciones adicionales que ayuden a acelerar la realización de acciones importantes. Sin embargo, cuantos más acciones exponga, más complicada será la interfaz de usuario. Debe tener cuidado adicional al elegir usar este patrón de interfaz de usuario. En este artículo se proporcionan instrucciones para ayudarle a determinar el mejor curso de acción para su interfaz de usuario concreta.

API importantes: clase ListView, clase GridView

En este artículo discutimos la creación de la interfaz de usuario anidada en elementos ListView y GridView. Aunque en esta sección no se habla de otros casos de interfaz de usuario anidadas, estos conceptos se pueden transferir. Antes de empezar, debe estar familiarizado con las instrucciones generales para usar los controles ListView o GridView en la interfaz de usuario, que se encuentran en los artículos Lista y vista de lista y vista de cuadrícula .

En este artículo, usamos los términos lista, elemento de lista y interfaz de usuario anidada como se define aquí:

  • List hace referencia a una colección de elementos contenidos en una vista de lista o una vista de cuadrícula.
  • Elemento de lista hace referencia a un elemento individual en el que un usuario puede realizar acciones en una lista.
  • La interfaz de usuario anidada se refiere a elementos de la interfaz de usuario dentro de un elemento de lista donde un usuario puede tomar medidas independientemente de realizar acciones en el elemento de lista en sí mismo.

Captura de pantalla que muestra las partes de una U anidada I.

NOTA ListView y GridView derivan de la clase ListViewBase , por lo que tienen la misma funcionalidad, pero muestran datos de forma diferente. En este artículo, cuando hablamos de listas, la información se aplica a los controles ListView y GridView.

Acciones principales y secundarias

Al crear una interfaz de usuario con una lista, tenga en cuenta las acciones que el usuario puede realizar de esos elementos de lista.

  • ¿Puede un usuario hacer clic en el elemento para realizar una acción?
    • Normalmente, al hacer clic en un elemento de lista se inicia una acción, pero no es obligatorio que lo haga.
  • ¿Hay más de una acción que puede realizar el usuario?
    • Por ejemplo, al pulsar un correo electrónico en una lista se abre ese correo electrónico. Sin embargo, puede haber otras acciones, como eliminar el correo electrónico, que el usuario querría realizar sin abrirlo primero. Beneficiaría al usuario acceder a esta acción directamente en la lista.
  • ¿Cómo deben exponerse las acciones al usuario?
    • Tenga en cuenta todos los tipos de entrada. Algunas formas de interfaz de usuario anidada funcionan bien con un método de entrada, pero es posible que no funcionen con otros métodos.

La acción principal es lo que el usuario espera que suceda cuando presiona el elemento de lista.

Las acciones secundarias suelen ser aceleradores asociados a elementos de lista. Estos aceleradores pueden ser para la administración de listas o acciones relacionadas con el elemento de lista.

Opciones para acciones secundarias

Al crear la interfaz de usuario de lista, primero debe asegurarse de tener en cuenta todos los métodos de entrada compatibles con Windows. Para obtener más información sobre los distintos tipos de entrada, consulta Entrada básica.

Después de asegurarte de que la aplicación admite todas las entradas compatibles con Windows, debes decidir si las acciones secundarias de la aplicación son lo suficientemente importantes como para exponer como aceleradores en la lista principal. Recuerde que cuantos más acciones exponga, más complicada será la interfaz de usuario. ¿Realmente necesita exponer las acciones secundarias en la interfaz de usuario de la lista principal o puede colocarlas en otro lugar?

Es posible que considere la posibilidad de exponer acciones adicionales en la interfaz de usuario de la lista principal cuando esas acciones deban ser accesibles por cualquier entrada en todo momento.

Si decide que no es necesario colocar acciones secundarias en la interfaz de usuario de la lista principal, hay otras maneras de exponerlas al usuario. Estas son algunas opciones que puede tener en cuenta para dónde colocar acciones secundarias.

Colocar acciones secundarias en la página de detalle

Coloque las acciones secundarias en la página a la que navega el elemento de lista cuando se presiona. Cuando se usa el patrón de lista y detalles, la página de detalles suele ser un buen lugar para colocar acciones secundarias.

Para obtener más información, consulta el patrón de lista y detalles.

Colocar acciones secundarias en un menú contextual

Coloque las acciones secundarias en un menú contextual al que el usuario puede acceder haciendo clic con el botón derecho del ratón o manteniendo presionado. Esto proporciona la ventaja de permitir que el usuario realice una acción, como eliminar un correo electrónico, sin tener que cargar la página de detalles. Es recomendable que estas opciones también estén disponibles en la página de detalles, ya que los menús contextuales están diseñados para ser aceleradores en lugar de la interfaz de usuario principal.

Para exponer acciones secundarias cuando la entrada procede de un controlador para juegos o un control remoto, se recomienda usar un menú contextual.

Para obtener más información, consulta Menús contextuales y paneles flotantes.

Colocar las acciones secundarias en la interfaz de usuario flotante para optimizar la interacción con el puntero.

Si esperas que tu aplicación se use con frecuencia con la entrada de puntero, como el ratón y el lápiz, y quieres que las acciones secundarias estén disponibles únicamente para esas entradas, puedes mostrar las acciones secundarias solo al pasar el puntero por encima. Este acelerador solo es visible cuando se usa una entrada de puntero, por lo que asegúrese de usar las otras opciones para admitir también otros tipos de entrada.

Interfaz de usuario anidada que se muestra al mantener el puntero

Para obtener más información, consulta Interacciones del mouse.

Selección de ubicación de la interfaz de usuario para acciones principales y secundarias

Si decide que las acciones secundarias deben exponerse en la interfaz de usuario de la lista principal, se recomiendan las siguientes instrucciones.

Al crear un elemento de lista con acciones principales y secundarias, coloque la acción principal a la izquierda y las acciones secundarias a la derecha. En las culturas con lectura de izquierda a derecha, los usuarios asocian las acciones en el lado izquierdo del elemento de la lista como la acción principal.

En estos ejemplos, hablamos de la interfaz de usuario de lista en la que el elemento fluye más horizontalmente (es más amplio que su alto). Sin embargo, es posible que tenga elementos de lista que sean más cuadrados en forma o más altos que su ancho. Normalmente, estos son elementos usados en una cuadrícula. Para estos elementos, si la lista no se desplaza verticalmente, puede colocar las acciones secundarias en la parte inferior del elemento de lista en lugar del lado derecho.

Considere todas las entradas

Al decidir usar la interfaz de usuario anidada, evalúe también la experiencia del usuario con todos los tipos de entrada. Como se mencionó anteriormente, la interfaz de usuario anidada funciona perfectamente para algunos tipos de entrada. Sin embargo, no siempre funciona muy bien para otros. En concreto, el teclado, el controlador y las entradas remotas pueden tener dificultades para acceder a los elementos anidados de la interfaz de usuario. Asegúrese de seguir las instrucciones siguientes para asegurarse de que Windows funciona con todos los tipos de entrada.

Gestión de la interfaz de usuario anidada

Cuando tengas más de una acción anidada en el elemento de lista, te recomendamos seguir esta guía para manejar la navegación con un teclado, mando de juegos, control remoto u otro tipo de entrada que no sea de puntero.

Interfaz de usuario anidada en la que los elementos de lista realizan una acción

Si la interfaz de usuario de lista con elementos anidados admite acciones como la invocación, la selección (única o múltiple) o las operaciones de arrastrar y colocar, recomendamos estas técnicas de navegación con flechas para navegar por los elementos anidados de la interfaz de usuario.

Captura de pantalla que muestra los elementos U I anidados etiquetados con las letras A, B, C y D.

Controlador para juegos

Cuando la entrada procede de un controlador para juegos, proporcione esta experiencia de usuario:

  • Desde A, la tecla direccional derecha coloca el foco en B.
  • Desde B, la tecla direccional derecha coloca el foco en C.
  • Desde C, la tecla direccional derecha es o una operación nula, o si hay un elemento de interfaz de usuario enfocable a la derecha de la Lista, enfóquelo allí.
  • Desde C, la tecla direccional izquierda coloca el foco en B.
  • Desde B, la tecla direccional izquierda coloca el foco en A.
  • Desde A, la tecla direccional izquierda no realiza ninguna operación o, si hay un elemento de interfaz de usuario enfocable a la derecha de List, se coloca el foco allí.
  • Desde A, B o C, la tecla direccional hacia abajo coloca el foco en D.
  • Desde el elemento de interfaz de usuario a la izquierda de Elemento de lista, la tecla direccional derecha coloca el foco en A.
  • Partiendo desde el elemento de interfaz de usuario a la derecha del Elemento de lista, la tecla direccional izquierda coloca el foco en A.

Keyboard

Cuando la entrada procede de un teclado, esta es la experiencia que obtiene el usuario:

  • En A, la tecla tab coloca el foco en B.
  • En B, la tecla tab coloca el foco en C.
  • En C, la tecla tab coloca el foco en el siguiente elemento de interfaz de usuario enfocable según el orden de tabulación.
  • En C, la tecla Shift+Tab coloca el enfoque en B.
  • En B, mantener presionado 'shift' y luego 'Tab' o la tecla de flecha izquierda enfoca en A.
  • En A, la combinación de teclas mayús+Tab coloca el foco en el siguiente elemento de la interfaz de usuario que puede recibir el foco, según el orden inverso de tabulación.
  • Desde A, B o C, la tecla de flecha abajo coloca el foco en D.
  • Desde el elemento de interfaz de usuario a la izquierda de Elemento de lista, la tecla de tabulación coloca el foco en A.
  • Desde el elemento de la interfaz de usuario a la derecha de Elemento de lista, la tecla de tabulación mayús coloca el foco en C.

Para lograr esta interfaz de usuario, ajuste IsItemClickEnabled a true en su lista. SelectionMode puede ser cualquier valor.

Para que el código lo implemente, consulte la sección Ejemplo de este artículo.

Interfaz de usuario anidada en la que los elementos de lista no realizan una acción

Puede usar una vista de lista porque proporciona un comportamiento de desplazamiento optimizado y virtualización, pero no tiene una acción asociada a un elemento de lista. Estas interfaces de usuario suelen usar el elemento de lista solo para agrupar elementos y asegurarse de que se desplazan como un conjunto.

Este tipo de interfaz de usuario tiende a ser mucho más complicado que los ejemplos anteriores, con muchos elementos anidados en los que el usuario puede tomar medidas.

Captura de pantalla de una U anidada compleja en la que se muestran muchos elementos anidados con los que el usuario puede interactuar.

Para lograr esta interfaz de usuario, establezca las siguientes propiedades en la lista:

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

Cuando los elementos de lista no realizan una acción, se recomienda esta guía para controlar la navegación con un controlador para juegos o un teclado.

Controlador para juegos

Cuando la entrada procede de un controlador para juegos, proporcione esta experiencia de usuario:

  • En Elemento de lista, la tecla direccional hacia abajo coloca el foco en el siguiente elemento de lista.
  • En "Elemento de lista", la tecla izquierda o derecha no realiza ninguna operación, o si hay un elemento de la interfaz de usuario enfocable a la derecha de "List", coloque el foco allí.
  • Desde el elemento de lista, el botón "A" coloca el foco en la interfaz de usuario anidada con prioridad de arriba/abajo e izquierda/derecha.
  • Cuando esté dentro de la interfaz de usuario anidada, siga el modelo de navegación XY Focus. El foco solo puede desplazarse por la interfaz de usuario anidada contenida dentro del elemento de lista actual hasta que el usuario presione el botón "B", lo que vuelve a colocar el foco en el elemento de lista.

Keyboard

Cuando la entrada procede de un teclado, esta es la experiencia que obtiene el usuario:

  • En Elemento de lista, la tecla de flecha abajo coloca el foco en el siguiente elemento de lista.
  • Desde el elemento de lista, presionar la tecla izquierda/derecha no tiene efecto.
  • Desde el elemento de lista, al presionar la tecla de tabulación, se coloca el foco en el siguiente punto de tabulación entre los elementos de interfaz de usuario anidados.
  • En uno de los elementos de la interfaz de usuario anidada, al presionar la pestaña se recorren los elementos anidados de la interfaz de usuario en orden de tabulación. Una vez que se han recorrido todos los elementos de la interfaz de usuario anidada, se coloca el foco en el siguiente control en el orden de tabulación después de ListView.
  • Mayús+Tab se comporta en dirección inversa desde el comportamiento de la pestaña.

Example

En este ejemplo se muestra cómo implementar la interfaz de usuario anidada en la que los elementos de lista realizan una acción.

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