Condividi tramite


Interfaccia utente annidata negli elementi dell'elenco

Un'interfaccia utente annidata è un'interfaccia utente che espone controlli interattivi annidati racchiusi all'interno di un contenitore che può anche prendere lo stato attivo in modo indipendente.

È possibile usare l'interfaccia utente annidata per presentare a un utente opzioni aggiuntive che consentono di accelerare l'esecuzione di azioni importanti. Tuttavia, più azioni si espongono, più complicata diventa l'interfaccia utente. È necessario prestare particolare attenzione quando si sceglie di usare questo modello di interfaccia utente. Questo articolo fornisce linee guida che consentono di determinare il miglior corso di azione per l'interfaccia utente specifica.

API importanti: classe ListView, classe GridView

In questo articolo viene descritta la creazione di un'interfaccia utente annidata negli elementi ListView e GridView . Sebbene questa sezione non parli di altri casi di interfaccia utente annidata, questi concetti sono trasferiscibili. Prima di iniziare, è necessario avere familiarità con le indicazioni generali per l'uso dei controlli ListView o GridView nell'interfaccia utente, disponibili negli articoli Visualizzazione elenchie visualizzazione elenco e visualizzazione griglia .

In questo articolo vengono usati i termini elenco, voce di elenco e interfaccia utente annidata , come definito di seguito:

  • L'elenco fa riferimento a una raccolta di elementi contenuti in una visualizzazione elenco o in una visualizzazione griglia.
  • L'elemento elenco fa riferimento a un singolo elemento su cui un utente può intervenire in un elenco.
  • L'interfaccia utente annidata fa riferimento agli elementi dell'interfaccia utente all'interno di una voce di elenco che un utente può intervenire separatamente dall'esecuzione di azioni sull'elemento dell'elenco stesso.

Screenshot che mostra le parti di un U I annidato.

NOTA ListView e GridView derivano entrambi dalla classe ListViewBase , quindi hanno le stesse funzionalità, ma visualizzano i dati in modo diverso. In questo articolo, quando parliamo di elenchi, le informazioni si applicano ai controlli ListView e GridView.

Azioni primarie e secondarie

Quando si crea un'interfaccia utente con un elenco, prendere in considerazione le azioni che l'utente potrebbe eseguire da tali voci di elenco.

  • Un utente può fare clic sull'elemento per eseguire un'azione?
    • In genere, facendo clic su una voce di elenco viene avviata un'azione, ma non è necessario.
  • L'utente può eseguire più di un'azione?
    • Ad esempio, toccando un messaggio di posta elettronica in un elenco viene aperto il messaggio di posta elettronica. Tuttavia, potrebbero essere presenti altre azioni, ad esempio l'eliminazione del messaggio di posta elettronica, che l'utente vuole eseguire senza aprirlo per primo. L'utente può accedere a questa azione direttamente nell'elenco.
  • Come devono essere esposte le azioni all'utente?
    • Prendere in considerazione tutti i tipi di input. Alcune forme di interfaccia utente annidata funzionano bene con un metodo di input, ma potrebbero non funzionare con altri metodi.

L'azione principale è quella che l'utente si aspetta quando preme l'elemento dell'elenco.

Le azioni secondarie sono in genere acceleratori associati alle voci di elenco. Questi acceleratori possono essere per la gestione degli elenchi o le azioni correlate all'elemento di elenco.

Opzioni per le azioni secondarie

Quando si crea l'interfaccia utente dell'elenco, è prima necessario assicurarsi di tenere conto di tutti i metodi di input supportati da Windows. Per altre informazioni sui diversi tipi di input, vedi Introduzione all'input.

Dopo aver verificato che l'app supporti tutti gli input supportati da Windows, devi decidere se le azioni secondarie dell'app sono sufficientemente importanti da esporre come acceleratori nell'elenco principale. Tenere presente che più azioni si espongono, più complicata diventa l'interfaccia utente. È davvero necessario esporre le azioni secondarie nell'interfaccia utente dell'elenco principale o inserirle in un'altra posizione?

È possibile valutare la possibilità di esporre azioni aggiuntive nell'interfaccia utente dell'elenco principale quando tali azioni devono essere accessibili da qualsiasi input in qualsiasi momento.

Se decidi che l'inserimento di azioni secondarie nell'interfaccia utente dell'elenco principale non è necessario, esistono diversi altri modi per esporli all'utente. Ecco alcune opzioni che è possibile prendere in considerazione per dove inserire le azioni secondarie.

Inserire le azioni secondarie nella pagina dei dettagli

Inserire le azioni secondarie nella pagina a cui si sposta l'elemento di elenco quando viene premuto. Quando si usa il modello elenco/dettagli, la pagina dei dettagli è spesso un buon posto per inserire azioni secondarie.

Per ulteriori informazioni, vedi lo schema elenco/dettaglio.

Inserire le azioni secondarie in un menu di scelta rapida

Inserire le azioni secondarie in un menu di scelta rapida a cui l'utente può accedere tramite clic con il pulsante destro del mouse o tenere premuto. Ciò offre il vantaggio di consentire all'utente di eseguire un'azione, ad esempio l'eliminazione di un messaggio di posta elettronica, senza dover caricare la pagina dei dettagli. È consigliabile rendere disponibili anche queste opzioni nella pagina dei dettagli, perché i menu di scelta rapida devono essere acceleratori anziché interfaccia utente primaria.

Per esporre le azioni secondarie quando l'input proviene da un game pad o da un telecomando, è consigliabile usare un menu di scelta rapida.

Per ulteriori informazioni, vedi Menu contestuale e menu di scelta rapida.

Inserire le azioni secondarie nell'interfaccia utente al passaggio del mouse per ottimizzare l'input del puntatore

Se prevedi che l'app venga usata di frequente con input del puntatore, ad esempio mouse e penna, e vuoi rendere le azioni secondarie facilmente disponibili solo per tali input, puoi visualizzare le azioni secondarie solo al passaggio del mouse. Questo acceleratore è visibile solo quando viene usato un input del puntatore, quindi assicurarsi di usare le altre opzioni per supportare anche altri tipi di input.

Interfaccia utente annidata visualizzata al passaggio del mouse

Per altre info, vedi Interazioni del mouse.

Posizionamento dell'interfaccia utente per azioni primarie e secondarie

Se si decide che le azioni secondarie devono essere esposte nell'interfaccia utente dell'elenco principale, è consigliabile seguire le linee guida seguenti.

Quando si crea una voce di elenco con azioni primarie e secondarie, posizionare l'azione primaria a sinistra e quella secondaria a destra. Nelle culture di lettura da sinistra a destra, gli utenti associano le azioni sul lato sinistro dell'elemento di elenco all'azione principale.

In questi esempi si parla dell'interfaccia utente dell'elenco in cui l'elemento scorre più orizzontalmente (è più ampio rispetto all'altezza). Tuttavia, è possibile che siano presenti elementi di elenco più quadrati in forma o più alti rispetto alla larghezza. In genere, si tratta di elementi usati in una griglia. Per questi elementi, se l'elenco non scorre verticalmente, è possibile posizionare le azioni secondarie nella parte inferiore dell'elemento di elenco anziché sul lato destro.

Prendere in considerazione tutti gli input

Quando si decide di usare l'interfaccia utente annidata, valutare anche l'esperienza utente con tutti i tipi di input. Come accennato in precedenza, l'interfaccia utente annidata funziona bene per alcuni tipi di input. Tuttavia, non funziona sempre bene per altri. In particolare, la tastiera, il controller e gli input remoti possono avere difficoltà ad accedere agli elementi dell'interfaccia utente annidati. Assicurarsi di seguire le indicazioni seguenti per assicurarsi che Windows funzioni con tutti i tipi di input.

Gestione di interfaccia utente innestata

Quando sono annidate più azioni nell'elemento dell'elenco, ti consigliamo di gestire lo spostamento con una tastiera, un game pad, un telecomando o un altro input non puntatore.

Interfaccia utente annidata in cui gli elementi dell'elenco eseguono un'azione

Se l'interfaccia utente dell'elenco con elementi annidati supporta azioni quali invocazione, selezione (singola o multipla) o operazioni di trascinamento della selezione, è consigliabile utilizzare queste tecniche di navigazione con le frecce per muoversi tra gli elementi dell'interfaccia utente annidati.

Screenshot che mostra gli elementi U I annidati con le lettere A, B, C e D.

Game pad

Quando l'input proviene da un game pad, fornire questa esperienza utente:

  • Da A, il tasto direzionale destro sposta lo stato attivo su B.
  • Da B, il tasto direzionale destro mette a fuoco su C.
  • Da C, il tasto direzionale destro non esegue operazioni o, se c'è un elemento dell'interfaccia utente attivabile a destra di List, sposta il focus lì.
  • Da C, il tasto direzionale sinistro porta l'attenzione su B.
  • Da B, il tasto direzionale sinistro concentra il focus su A.
  • Da A, il tasto direzionale sinistro è non operativo, oppure, se a destra dell'elenco è presente un elemento dell'interfaccia utente attivabile, metti il focus lì.
  • Da A, B o C, verso il basso il tasto direzionale sposta lo stato attivo su D.
  • Dall'elemento dell'interfaccia utente a sinistra dell'elemento della lista, il tasto direzionale destro sposta lo stato attivo su A.
  • Dall'elemento dell'interfaccia utente a destra dell'elemento della lista, il tasto direzionale sinistro mette a fuoco A.

Keyboard

Quando l'input proviene da una tastiera, si tratta dell'esperienza ottenuta dall'utente:

  • Da A, il tasto Tab sposta il focus su B.
  • Da B, il tasto Tab sposta lo stato attivo su C.
  • Da C, il tasto Tab sposta il focus sull'elemento successivo dell'interfaccia utente focalizzabile nell'ordine di tab.
  • Da C, maiusc+tab sposta lo stato attivo su B.
  • Da B, maiusc+tab o freccia sinistra sposta il focus su A.
  • Da A, MAIUSC+TAB sposta il focus sul successivo elemento dell'interfaccia utente focusabile nell'ordine di tabulazione inverso.
  • Da A, B o C, il tasto freccia giù porta la selezione su D.
  • Dall'elemento dell'interfaccia utente a sinistra dell'elemento elenco, il tasto TAB sposta lo stato attivo su A.
  • Dall'elemento dell'interfaccia utente a destra dell'elemento dell'elenco, il tasto Shift + Tab porterà il focus su C.

Per ottenere questa interfaccia utente, impostare IsItemClickEnabled su true nell'elenco. SelectionMode può essere qualsiasi valore.

Per implementare questo codice, vedere la sezione Esempio di questo articolo.

Interfaccia utente annidata in cui gli elementi dell'elenco non eseguono un'azione

È possibile usare una visualizzazione elenco perché fornisce il comportamento di virtualizzazione e scorrimento ottimizzato, ma non è associata un'azione a una voce di elenco. Queste interfacce utente utilizzano generalmente l'elemento di elenco unicamente per raggruppare gli elementi e assicurarsi che scorrono come un insieme.

Questo tipo di interfaccia utente tende a essere molto più complicato degli esempi precedenti, con molti elementi annidati su cui l'utente può intervenire.

Screenshot di un U annidato complesso che mostra molti elementi annidati con cui l'utente può interagire.

Per ottenere questa interfaccia utente, impostare le proprietà seguenti nell'elenco:

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

Quando le voci dell'elenco non eseguono un'azione, ti consigliamo di seguire questa guida per gestire la navigazione con un controller o una tastiera.

Game pad

Quando l'input proviene da un game pad, fornire questa esperienza utente:

  • Da Elemento elenco, il tasto direzionale verso il basso sposta lo stato attivo sull'elemento di elenco successivo.
  • Dall'elemento di elenco, il tasto sinistro/destro non svolge alcuna operazione, oppure, se è presente un elemento dell'interfaccia utente attivabile a destra dell'elenco, spostare il fuoco su di esso.
  • Nell'elemento elenco, il pulsante "A" imposta lo stato attivo sull'interfaccia utente annidata con priorità dall'alto al basso e da sinistra a destra.
  • Mentre si trova all'interno della Nested UI, seguire il modello di navigazione XY Focus. Il focus può spostarsi solo all'interno della UI annidata contenuta nell'elemento elenco corrente fino a quando l'utente non preme il pulsante "B", che riporta il focus sull'elemento elenco.

Keyboard

Quando l'input proviene da una tastiera, si tratta dell'esperienza ottenuta dall'utente:

  • Quando si è su un elemento dell'elenco, il tasto freccia giù pone il focus sull'elemento successivo dell'elenco.
  • Dall'elemento della lista, premendo il tasto freccia sinistra/destra non ha effetto.
  • Da Elemento elenco, premendo TAB lo stato attivo viene spostato sulla tabulazione successiva tra l'elemento dell'interfaccia utente annidata.
  • Da uno degli elementi dell'interfaccia utente annidata, premendo il tasto Tab gli elementi dell'interfaccia utente annidati vengono percorsi nell'ordine dei tab. Una volta spostati tutti gli elementi dell'interfaccia utente annidati, il focus viene spostato sul controllo successivo nell'ordine di tab dopo ListView.
  • MAIUSC+TAB si comporta in direzione opposta rispetto al comportamento del tasto Tab.

Example

Questo esempio illustra come implementare l'interfaccia utente annidata in cui gli elementi dell'elenco eseguono un'azione.

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