UI berlapis dalam item daftar

UI berlapis adalah antarmuka pengguna (UI) yang mengekspos kontrol yang dapat ditindaklanjuti berlapis yang diapit di dalam kontainer yang juga dapat mengambil fokus independen.

Anda dapat menggunakan UI berlapis untuk menyajikan pengguna dengan opsi tambahan yang membantu mempercepat mengambil tindakan penting. Namun, semakin banyak tindakan yang Anda ekspos, semakin rumit UI Anda. Anda perlu berhati-hati ketika Anda memilih untuk menggunakan pola UI ini. Artikel ini menyediakan panduan untuk membantu Anda menentukan tindakan terbaik untuk UI tertentu.

API penting: kelas ListView, kelas GridView

Dalam artikel ini, kita membahas pembuatan UI berlapis di item ListView dan GridView . Meskipun bagian ini tidak berbicara tentang kasus UI berlapis lainnya, konsep ini dapat ditransfer. Sebelum memulai, Anda harus terbiasa dengan panduan umum untuk menggunakan kontrol ListView atau GridView di UI Anda, yang ditemukan di artikel tampilan Daftardan Daftar dan tampilan kisi .

Dalam artikel ini, kami menggunakan daftar istilah, item daftar, dan UI berlapis seperti yang didefinisikan di sini:

  • Daftar mengacu pada kumpulan item yang terkandung dalam tampilan daftar atau tampilan kisi.
  • Item daftar mengacu pada item individual yang dapat diambil tindakan pengguna dalam daftar.
  • UI berlapis mengacu pada elemen UI dalam item daftar bahwa pengguna dapat mengambil tindakan terpisah dari mengambil tindakan pada item daftar itu sendiri.

Cuplikan layar memperlihatkan bagian U I Berlapis.

CATATAN ListView dan GridView keduanya berasal dari kelas ListViewBase , sehingga mereka memiliki fungsionalitas yang sama, tetapi menampilkan data secara berbeda. Dalam artikel ini, saat kita berbicara tentang daftar, info berlaku untuk kontrol ListView dan GridView.

Tindakan primer dan sekunder

Saat membuat UI dengan daftar, pertimbangkan tindakan apa yang mungkin diambil pengguna dari item daftar tersebut.

  • Bisakah pengguna mengklik item untuk melakukan tindakan?
    • Biasanya, mengklik item daftar memulai tindakan, tetapi tidak memilikinya juga.
  • Apakah ada lebih dari satu tindakan yang dapat dilakukan pengguna?
    • Misalnya, mengetuk email dalam daftar akan membuka email tersebut. Namun, mungkin ada tindakan lain, seperti menghapus email, yang ingin diambil pengguna tanpa membukanya terlebih dahulu. Ini akan menguntungkan pengguna untuk mengakses tindakan ini langsung dalam daftar.
  • Bagaimana tindakan harus diekspos ke pengguna?
    • Pertimbangkan semua jenis input. Beberapa bentuk UI berlapis berfungsi dengan baik dengan satu metode input, tetapi mungkin tidak berfungsi dengan metode lain.

Tindakan utama adalah apa yang diharapkan pengguna terjadi ketika mereka menekan item daftar.

Tindakan sekunder biasanya akselerator yang terkait dengan item daftar. Akselerator ini dapat untuk manajemen daftar atau tindakan yang terkait dengan item daftar.

Opsi untuk tindakan sekunder

Saat membuat UI daftar, pertama-tama Anda perlu memastikan anda memperkirakan semua metode input yang didukung Windows. Untuk informasi selengkapnya tentang berbagai jenis input, lihat Input primer.

Setelah memastikan bahwa aplikasi Anda mendukung semua input yang didukung Windows, Anda harus memutuskan apakah tindakan sekunder aplikasi Anda cukup penting untuk diekspos sebagai akselerator dalam daftar utama. Ingatlah bahwa semakin banyak tindakan yang Anda ekspos, semakin rumit UI Anda. Apakah Anda benar-benar perlu mengekspos tindakan sekunder di UI daftar utama, atau dapatkah Anda menempatkannya di tempat lain?

Anda mungkin mempertimbangkan untuk mengekspos tindakan tambahan di UI daftar utama ketika tindakan tersebut harus dapat diakses oleh input apa pun setiap saat.

Jika Anda memutuskan bahwa menempatkan tindakan sekunder di UI daftar utama tidak diperlukan, ada beberapa cara lain untuk mengeksposnya kepada pengguna. Berikut adalah beberapa opsi yang dapat Anda pertimbangkan untuk tempat menempatkan tindakan sekunder.

Letakkan tindakan sekunder pada halaman detail

Letakkan tindakan sekunder pada halaman yang dinavigasi item daftar saat ditekan. Saat Anda menggunakan pola daftar/detail, halaman detail sering kali merupakan tempat yang baik untuk menempatkan tindakan sekunder.

Untuk informasi selengkapnya, lihat pola daftar/detail.

Menempatkan tindakan sekunder di menu konteks

Letakkan tindakan sekunder di menu konteks yang dapat diakses pengguna melalui klik kanan atau tekan dan tahan. Ini memberikan manfaat membiarkan pengguna melakukan tindakan, seperti menghapus email, tanpa harus memuat halaman detail. Ini adalah praktik yang baik untuk juga membuat opsi ini tersedia di halaman detail, karena menu konteks dimaksudkan untuk menjadi akselerator daripada UI utama.

Untuk mengekspos tindakan sekunder saat input berasal dari gamepad atau remote control, kami sarankan Anda menggunakan menu konteks.

Untuk informasi selengkapnya, lihat Menu konteks dan flyout.

Letakkan tindakan sekunder di UI hover untuk mengoptimalkan input penunjuk

Jika Anda mengharapkan aplikasi anda sering digunakan dengan input pointer seperti mouse dan pena, dan ingin membuat tindakan sekunder tersedia hanya untuk input tersebut, maka Anda dapat menampilkan tindakan sekunder hanya pada hover. Akselerator ini hanya terlihat ketika input pointer digunakan, jadi pastikan untuk menggunakan opsi lain untuk mendukung jenis input lain juga.

UI berlapis ditampilkan di hover

Untuk informasi selengkapnya, lihat Interaksi mouse.

Penempatan UI untuk tindakan primer dan sekunder

Jika Anda memutuskan bahwa tindakan sekunder harus diekspos di UI daftar utama, kami merekomendasikan panduan berikut.

Saat Anda membuat item daftar dengan tindakan utama dan sekunder, tempatkan tindakan utama di sebelah kiri dan sekunder di sebelah kanan. Dalam budaya membaca kiri-ke-kanan, pengguna mengaitkan tindakan di sisi kiri item daftar sebagai tindakan utama.

Dalam contoh ini, kita berbicara tentang UI daftar di mana item mengalir lebih horizontal (lebih lebar dari tingginya). Namun, Anda mungkin memiliki item daftar yang bentuknya lebih persegi, atau lebih tinggi dari lebarnya. Biasanya, ini adalah item yang digunakan dalam kisi. Untuk item ini, jika daftar tidak digulir secara vertikal, Anda dapat menempatkan tindakan sekunder di bagian bawah item daftar daripada ke sisi kanan.

Pertimbangkan semua input

Saat memutuskan untuk menggunakan UI berlapis, evaluasi juga pengalaman pengguna dengan semua jenis input. Seperti disebutkan sebelumnya, UI berlapis berfungsi dengan baik untuk beberapa jenis input. Namun, itu tidak selalu bekerja bagus untuk beberapa yang lain. Secara khusus, keyboard, pengontrol, dan input jarak jauh dapat mengalami kesulitan mengakses elemen UI berlapis. Pastikan untuk mengikuti panduan di bawah ini untuk memastikan Windows Anda berfungsi dengan semua jenis input.

Penanganan UI berlapis

Ketika Anda memiliki lebih dari satu tindakan yang berlapis dalam item daftar, kami sarankan panduan ini untuk menangani navigasi dengan keyboard, gamepad, remote control, atau input non-pointer lainnya.

UI berlapis tempat item daftar melakukan tindakan

Jika UI daftar Anda dengan elemen berlapis mendukung tindakan seperti memanggil, memilih (satu atau beberapa), atau operasi seret dan letakkan, kami sarankan teknik panah ini untuk menavigasi melalui elemen UI berlapis Anda.

Cuplikan layar memperlihatkan elemen U I berlapis berlabel huruf A, B, C, dan D.

Gamepad

Ketika input berasal dari gamepad, berikan pengalaman pengguna ini:

  • Dari A, kunci arah kanan memfokuskan pada B.
  • Dari B, kunci arah kanan menempatkan fokus pada C.
  • Dari C, kunci arah yang tepat tidak ada op, atau jika ada elemen UI yang dapat difokuskan di sebelah kanan Daftar, letakkan fokus di sana.
  • Dari C, kunci arah kiri memfokuskan pada B.
  • Dari B, kunci arah kiri memfokuskan pada A.
  • Dari A, kunci arah kiri tidak ada op, atau jika ada elemen UI yang dapat difokuskan di sebelah kanan Daftar, letakkan fokus di sana.
  • Dari A, B, atau C, tombol arah bawah menempatkan fokus pada D.
  • Dari elemen UI di sebelah kiri Item Daftar, kunci arah kanan memfokuskan pada A.
  • Dari elemen UI di sebelah kanan Item Daftar, kunci arah kiri memfokuskan pada A.

Keyboard

Ketika input berasal dari keyboard, ini adalah pengalaman yang didapat pengguna:

  • Dari A, tombol tab memfokuskan pada B.
  • Dari B, tombol tab menempatkan fokus pada C.
  • Dari C, tombol tab menempatkan fokus pada elemen UI berikutnya yang dapat difokuskan dalam urutan tab.
  • Dari C, tombol shift+tab memfokuskan pada B.
  • Dari B, tombol shift+tab atau panah kiri memfokuskan pada A.
  • Dari A, tombol shift+tab memfokuskan pada elemen UI berikutnya yang dapat difokuskan dalam urutan tab terbalik.
  • Dari A, B, atau C, tombol panah bawah menempatkan fokus pada D.
  • Dari elemen UI di sebelah kiri Item Daftar, tombol tab memfokuskan pada A.
  • Dari elemen UI di sebelah kanan Item Daftar, tombol tab shift memfokuskan pada C.

Untuk mencapai UI ini, atur IsItemClickEnabled ke true di daftar Anda. SelectionMode dapat berupa nilai apa pun.

Agar kode menerapkan ini, lihat bagian Contoh artikel ini.

UI berlapis di mana item daftar tidak melakukan tindakan

Anda mungkin menggunakan tampilan daftar karena menyediakan virtualisasi dan perilaku pengguliran yang dioptimalkan, tetapi tidak memiliki tindakan yang terkait dengan item daftar. UI ini biasanya menggunakan item daftar hanya untuk mengelompokkan elemen dan memastikan mereka menggulir sebagai satu set.

UI semacam ini cenderung jauh lebih rumit daripada contoh sebelumnya, dengan banyak elemen berlapis yang dapat diambil tindakan pengguna.

Cuplikan layar U Berlapis kompleks yang menunjukkan banyak elemen berlapis yang dapat berinteraksi dengan pengguna.

Untuk mencapai UI ini, atur properti berikut ini di daftar Anda:

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

Ketika item daftar tidak melakukan tindakan, kami merekomendasikan panduan ini untuk menangani navigasi dengan gamepad atau keyboard.

Gamepad

Ketika input berasal dari gamepad, berikan pengalaman pengguna ini:

  • Dari Item Daftar, tombol arah bawah memfokuskan pada Item Daftar berikutnya.
  • Dari Item Daftar, kunci kiri/kanan tidak ada op, atau jika ada elemen UI yang dapat difokuskan di sebelah kanan Daftar, letakkan fokus di sana.
  • Dari Item Daftar, tombol 'A' memfokuskan pada UI Berlapis di prioritas kiri/kanan atas/bawah.
  • Saat berada di dalam UI Berlapis, ikuti model navigasi Fokus XY. Fokus hanya dapat menavigasi di sekitar UI Berlapis yang terkandung di dalam Item Daftar saat ini hingga pengguna menekan tombol 'B', yang menempatkan fokus kembali ke Item Daftar.

Keyboard

Ketika input berasal dari keyboard, ini adalah pengalaman yang didapat pengguna:

  • Dari Item Daftar, tombol panah bawah memfokuskan pada Item Daftar berikutnya.
  • Dari Item Daftar, menekan tombol kiri/kanan bukanlah op.
  • Dari Item Daftar, menekan tombol tab menempatkan fokus pada perhentian tab berikutnya di antara item UI Berlapis.
  • Dari salah satu item UI Berlapis, tab penekanan melintasi item UI berlapis dalam urutan tab. Setelah semua item UI Berlapis dilalui, item akan fokus ke kontrol berikutnya dalam urutan tab setelah ListView.
  • Shift+Tab berulah dalam arah terbalik dari perilaku tab.

Contoh

Contoh ini menunjukkan cara mengimplementasikan UI berlapis di mana item daftar melakukan tindakan.

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