Udostępnij przez


Zagnieżdżony interfejs użytkownika w elementach listy

Zagnieżdżony interfejs użytkownika to interfejs, który ukazuje zagnieżdżone kontrolki działania w ramach kontenera, który może również uzyskać niezależne ustawienie ostrości.

Możesz użyć zagnieżdżonego interfejsu użytkownika, aby przedstawić użytkownikowi dodatkowe opcje, które pomagają przyspieszyć podejmowanie ważnych akcji. Jednak tym bardziej uwidaczniasz akcje, tym bardziej skomplikowany staje się interfejs użytkownika. Podczas wybierania tego wzorca interfejsu użytkownika należy zachować szczególną ostrożność. Ten artykuł zawiera wskazówki ułatwiające określenie najlepszego przebiegu działania dla określonego interfejsu użytkownika.

Ważne interfejsy API: klasa ListView, klasa GridView

W tym artykule omówiono tworzenie zagnieżdżonego interfejsu użytkownika w elementach ListView i GridView . Chociaż ta sekcja nie mówi o innych przypadkach zagnieżdżonego interfejsu użytkownika, te pojęcia można przenosić. Przed rozpoczęciem należy zapoznać się z ogólnymi wskazówkami dotyczącymi używania kontrolek ListView lub GridView w interfejsie użytkownika, które można znaleźć w artykułach Listy i Widok listy i widoku siatki .

W tym artykule używamy listy, elementu listy i zagnieżdżonego interfejsu użytkownika zdefiniowanych tutaj:

  • Lista odwołuje się do kolekcji elementów zawartych w widoku listy lub widoku siatki.
  • Element listy odwołuje się do pojedynczego elementu, na który użytkownik może podjąć akcję na liście.
  • Zagnieżdżony interfejs użytkownika oznacza elementy interfejsu użytkownika w elemencie listy, na których użytkownik może wykonywać akcje niezależnie od działań na samym elemencie listy.

Zrzut ekranu przedstawiający elementy zagnieżdżonego interfejsu użytkownika.

UWAGA Klasy ListView i GridView pochodzą z klasy ListViewBase , więc mają te same funkcje, ale wyświetlają dane inaczej. W tym artykule, gdy mówimy o listach, informacje dotyczą kontrolek ListView i GridView.

Akcje podstawowe i pomocnicze

Podczas tworzenia interfejsu użytkownika z listą należy wziąć pod uwagę akcje, które użytkownik może wykonać z tych elementów listy.

  • Czy użytkownik może kliknąć element, aby wykonać akcję?
    • Zazwyczaj kliknięcie elementu listy inicjuje akcję, ale nie musi tego robić.
  • Czy użytkownik może wykonać więcej niż jedną akcję?
    • Na przykład naciśnięcie wiadomości e-mail na liście spowoduje otwarcie tej wiadomości e-mail. Jednak mogą istnieć inne akcje, takie jak usunięcie wiadomości e-mail, które użytkownik chce wykonać bez wcześniejszego otwarcia. Dzięki temu użytkownik może uzyskać dostęp do tej akcji bezpośrednio na liście.
  • W jaki sposób akcje powinny być widoczne dla użytkownika?
    • Rozważ wszystkie typy danych wejściowych. Niektóre formy zagnieżdżonego interfejsu użytkownika działają świetnie z jedną metodą danych wejściowych, ale mogą nie działać z innymi metodami.

Akcja podstawowa to to, czego oczekuje użytkownik po naciśnięciu elementu listy.

Akcje pomocnicze to zazwyczaj akceleratory skojarzone z elementami listy. Akceleratory te mogą być przeznaczone do zarządzania listami lub akcji związanych z elementem listy.

Opcje dla akcji pomocniczych

Podczas tworzenia interfejsu użytkownika listy należy najpierw upewnić się, że uwzględniasz wszystkie metody wejściowe obsługiwane przez system Windows. Aby uzyskać więcej informacji na temat różnych rodzajów danych wejściowych, zobacz Podstawy danych wejściowych.

Po upewnieniu się, że aplikacja obsługuje wszystkie dane wejściowe obsługiwane przez system Windows, należy zdecydować, czy dodatkowe akcje aplikacji są wystarczająco ważne, aby uwidocznić jako akceleratory na głównej liście. Pamiętaj, że tym więcej akcji ujawniasz, tym bardziej skomplikowane staje się interfejs użytkownika. Czy naprawdę musisz uwidocznić akcje pomocnicze w interfejsie użytkownika listy głównej lub umieścić je gdzie indziej?

Możesz rozważyć uwidocznienie dodatkowych akcji w interfejsie użytkownika listy głównej, gdy te akcje muszą być dostępne przez wszystkie dane wejściowe przez cały czas.

Jeśli zdecydujesz, że umieszczanie akcji pomocniczych w interfejsie użytkownika listy głównej nie jest konieczne, istnieje kilka innych sposobów uwidaczniania ich użytkownikowi. Poniżej przedstawiono kilka opcji, które można rozważyć, gdzie należy umieścić akcje pomocnicze.

Umieść czynności pomocnicze na stronie szczegółów

Umieść akcje pomocnicze na stronie, do której przechodzi element listy po jego naciśnięciu. W przypadku korzystania ze wzorca listy/szczegółów strona szczegółów jest często dobrym miejscem do umieszczania akcji pomocniczych.

Aby uzyskać więcej informacji, zobacz wzorzec listy/szczegółów.

Umieszczanie akcji pomocniczych w menu kontekstowym

Umieść akcje pomocnicze w menu kontekstowym, do którego użytkownik może uzyskać dostęp, klikając prawym przyciskiem myszy lub naciskając i przytrzymaj. Zapewnia to korzyści wynikające z umożliwienia użytkownikowi wykonania akcji, takiej jak usunięcie wiadomości e-mail, bez konieczności ładowania strony szczegółów. Dobrym rozwiązaniem jest udostępnienie tych opcji na stronie szczegółów, ponieważ menu kontekstowe mają być akceleratorami, a nie podstawowym interfejsem użytkownika.

Aby uwidocznić akcje pomocnicze, gdy dane wejściowe pochodzą z gamepadu lub zdalnego sterowania, zalecamy użycie menu kontekstowego.

Aby uzyskać więcej informacji, przejdź do Menu kontekstowe i wyskakujące.

Umieść akcje pomocnicze w interfejsie użytkownika pojawiającym się po najechaniu kursorem, aby zoptymalizować interakcje przy użyciu wskaźnika.

Jeśli oczekujesz, że aplikacja będzie często używana z wprowadzaniem za pomocą wskaźnika, takim jak mysz i pióro, i chcesz, aby akcje dodatkowe były łatwo dostępne tylko przy tych wprowadzaniach, możesz wyświetlać akcje dodatkowe tylko po najechaniu wskaźnikiem. Ten akcelerator jest widoczny tylko wtedy, gdy jest używany wskaźnik wejściowy, dlatego należy użyć innych opcji do obsługi innych typów danych wejściowych.

Zagnieżdżony interfejs użytkownika wyświetlany po umieszczeniu wskaźnika myszy

Aby uzyskać więcej informacji, zobacz Interakcje myszy.

Umiejscowienie interfejsu użytkownika dla działań podstawowych i pomocniczych

Jeśli zdecydujesz, że akcje pomocnicze powinny być uwidocznione w interfejsie użytkownika listy głównej, zalecamy wykonanie poniższych wskazówek.

Podczas tworzenia elementu listy z akcjami podstawowymi i pomocniczymi umieść akcję podstawową po lewej stronie i akcje pomocnicze po prawej stronie. W kulturach odczytu od lewej do prawej użytkownicy kojarzą akcje po lewej stronie elementu listy jako akcję podstawową.

W tych przykładach mówimy o interfejsie użytkownika listy, w którym element przepływa bardziej w poziomie (jest szerszy niż jego wysokość). Jednak mogą istnieć elementy listy, które są bardziej kwadratowe w kształcie lub wyższe niż ich szerokość. Zazwyczaj są to elementy stosowane w siatce. W przypadku tych elementów, jeśli lista nie przewija się w pionie, możesz umieścić akcje pomocnicze w dolnej części elementu listy, a nie po prawej stronie.

Rozważ wszystkie dane wejściowe

Podczas podejmowania decyzji o użyciu zagnieżdżonego interfejsu użytkownika należy również ocenić środowisko użytkownika ze wszystkimi typami danych wejściowych. Jak wspomniano wcześniej, zagnieżdżony interfejs użytkownika działa świetnie w przypadku niektórych typów danych wejściowych. Jednak nie zawsze działa świetnie dla innych. W szczególności klawiatura, kontroler i pilot zdalnego sterowania mogą mieć trudności z dostępem do zagnieżdżonych elementów interfejsu użytkownika. Pamiętaj, aby postępować zgodnie z poniższymi wskazówkami, aby upewnić się, że system Windows współpracuje ze wszystkimi typami danych wejściowych.

Obsługa zagnieżdżonego interfejsu użytkownika

Jeśli w elemencie listy znajduje się więcej niż jedna akcja, zalecamy kierowanie się tymi wytycznymi w celu obsługi nawigacji za pomocą klawiatury, gamepadu, zdalnego sterowania lub innych metod wprowadzania danych niewymagających wskaźnika.

Zagnieżdżony interfejs użytkownika, w którym elementy listy wykonują czynność

Jeśli interfejs użytkownika listy z zagnieżdżonymi elementami obsługuje akcje, takie jak wywoływanie, zaznaczanie (pojedyncze lub wielokrotne) lub operacje przeciągania i upuszczania, zalecamy wykonanie tych technik strzałki w celu nawigowania po zagnieżdżonych elementach interfejsu użytkownika.

Zrzut ekranu przedstawiający zagnieżdżone elementy U I oznaczone literami A, B, C i D.

Gamepad

Gdy dane wejściowe pochodzą z gamepada, zapewnij to doświadczenie użytkownika:

  • Od A, prawy klawisz kierunkowy przenosi fokus na B.
  • Od B klawisz kierunkowy w prawo ustawia fokus na C.
  • W języku C prawy klawisz kierunkowy nie wykonuje żadnej operacji lub, jeśli możliwy do skupienia element interfejsu użytkownika znajduje się po prawej stronie listy, ustaw tam fokus.
  • W języku C lewy klucz kierunkowy koncentruje się na B.
  • Od B lewy klucz kierunkowy koncentruje się na A.
  • W obszarze A lewy klawisz kierunkowy nie wykonuje żadnej operacji lub, jeśli po prawej stronie listy znajduje się element interfejsu użytkownika możliwy do objęcia fokusem, ustaw tam fokus.
  • Od A, B lub C, klawisz kierunkowy w dół ustawia fokus na D.
  • Od elementu interfejsu użytkownika po lewej stronie elementu listy, klawisz kierunkowy w prawo ustawia fokus na A.
  • Od elementu interfejsu użytkownika po prawej stronie elementu listy, lewy klawisz kierunkowy ustawia fokus na A.

Klawiatura

Gdy dane wejściowe pochodzą z klawiatury, użytkownik ma takie doświadczenie:

  • Z A, klawisz Tabulatora przenosi fokus na B.
  • Z B klawisz tabulacji przenosi fokus na C.
  • Z C klawisz Tab ustawia fokus na następnym elemencie interfejsu użytkownika w kolejności tabulacji.
  • Od C, naciśnięcie Shift+Tab przenosi fokus na B.
  • Z B, klawisz Shift+Tab lub klawisz strzałki w lewo ustawia fokus na A.
  • Z poziomu A, klawisze shift+tab przenoszą fokus na następny element interfejsu użytkownika, który może przyjąć fokus, w odwrotnej kolejności tabulacji.
  • Od A, B lub C klawisz strzałki w dół umieszcza fokus na D.
  • Od elementu interfejsu użytkownika znajdującego się po lewej stronie elementu listy klawisz Tab ustawia fokus na A.
  • Przemieszczając się z elementu interfejsu użytkownika po prawej stronie elementu listy, klawisz Shift + Tab ustawia fokus na C.

Aby osiągnąć ten interfejs użytkownika, ustaw wartość IsItemClickEnabled na wartość true na liście. SelectionMode może być dowolną wartością.

Aby zaimplementować ten kod, zobacz sekcję Przykład tego artykułu.

Zagnieżdżony interfejs użytkownika, w którym elementy listy nie wykonują akcji

Możesz użyć widoku listy, ponieważ zapewnia wirtualizację i zoptymalizowane zachowanie przewijania, ale nie ma akcji skojarzonej z elementem listy. Te interfejsy użytkownika zazwyczaj używają elementu listy wyłącznie do grupowania elementów i zapewnienia, że przewijają się razem.

Ten rodzaj interfejsu użytkownika jest znacznie bardziej skomplikowany niż w poprzednich przykładach, z dużą częścią zagnieżdżonych elementów, nad którymi użytkownik może podjąć działania.

Zrzut ekranu przedstawiający złożony zagnieżdżony interfejs użytkownika z wieloma zagnieżdżonymi elementami, z którymi użytkownik może wchodzić w interakcję.

Aby osiągnąć ten interfejs użytkownika, ustaw następujące właściwości na liście:

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

Jeśli elementy listy nie wykonują akcji, zalecamy wykonanie tych wskazówek, aby obsługiwać nawigację za pomocą gamepadu lub klawiatury.

Gamepad

Gdy dane wejściowe pochodzą z kontrolera, zapewnij tę interakcję użytkownika.

  • W elemencie listy, klawisz kierunkowy w dół przenosi fokus na następny element listy.
  • Z elementu listy klawisz lewo/prawo nie wykonuje żadnej operacji, lub jeśli po prawej stronie Listy znajduje się element interfejsu użytkownika, na który można przenieść fokus, umieść tam fokus.
  • W obszarze Element listy przycisk "A" umieszcza fokus na zagnieżdżonym interfejsie użytkownika z priorytetem od góry do dołu i od lewej do prawej.
  • W zagnieżdżonym interfejsie użytkownika postępuj zgodnie z zalecanym modelem nawigacji XY Focus. Fokus może poruszać się tylko wokół zagnieżdżonego interfejsu użytkownika zawartego w bieżącym elemencie listy, dopóki użytkownik nie naciśnie przycisku "B", co powoduje powrót fokusu do elementu listy.

Klawiatura

Gdy dane wejściowe pochodzą z klawiatury, takie doświadczenie uzyskuje użytkownik.

  • W elemencie listy strzałka w dół przenosi fokus na następny element listy.
  • W elemencie listy naciśnięcie klawisza strzałki w lewo lub prawo nie powoduje żadnej akcji.
  • W elemencie listy naciśnięcie klawisza Tab powoduje przeniesienie fokusu na następny stop tabulacji wśród zagnieżdżonych elementów interfejsu użytkownika.
  • Z jednego z zagnieżdżonych elementów interfejsu użytkownika przejście za pomocą klawisza Tab prowadzi przez zagnieżdżone elementy interfejsu użytkownika w kolejności wciśnięć klawisza Tab. Po przejściu przez wszystkie zagnieżdżone elementy interfejsu użytkownika, fokus przenosi się na następną kontrolkę w kolejności tabulacji po kontrolce ListView.
  • Shift+Tab działa w przeciwnym kierunku niż Tab.

Example

W tym przykładzie pokazano, jak zaimplementować zagnieżdżony interfejs użytkownika, w którym elementy listy wykonują akcję.

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