Bagikan melalui


UI tersarang dalam elemen 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 antarmuka pengguna khusus Anda.

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 Daftar, dan Tampilan daftar dan tampilan kisi.

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

  • Daftar mengacu pada kumpulan item yang terdapat dalam tampilan daftar atau tampilan kisi.
  • Item daftar merujuk ke item individual tempat pengguna dapat mengambil tindakan dalam daftar.
  • UI bersarang mengacu pada elemen UI dalam item daftar yang dapat diakses pengguna untuk melakukan tindakan yang terpisah dari 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, ketika kita berbicara tentang daftar, informasi berlaku untuk kontrol ListView serta 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 sebuah tindakan, tetapi tidak harus begitu.
  • 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 saat mereka menekan item daftar.

Tindakan sekunder biasa merupakan akselerator yang terkait pada item daftar. Alat percepatan ini dapat digunakan untuk pengelolaan daftar atau tindakan yang terkait dengan item dalam daftar.

Opsi untuk tindakan sekunder

Saat membuat antarmuka pengguna daftar, Pertama-tama Anda perlu memastikan bahwa Anda memperhitungkan semua metode input yang didukung Windows. Untuk informasi selengkapnya tentang berbagai jenis input, lihat Input primer.

Setelah memastikan bahwa aplikasi 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 antarmuka pengguna daftar utama, atau bisakah Anda menempatkannya di tempat lain?

Anda mungkin mempertimbangkan untuk mengekspos tindakan tambahan di UI daftar utama ketika tindakan tersebut perlu 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 ke 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 diarahkan oleh item daftar ketika ditekan. Ketika Anda menggunakan pola daftar/detail, halaman detail sering kali merupakan tempat yang baik untuk menempatkan tindakan sekunder.

Untuk informasi selengkapnya, lihat pola daftar/detail.

Letakkan 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 antarmuka pengguna 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 pointer

Jika Anda memperkirakan aplikasi Anda akan sering digunakan dengan input penunjuk seperti mouse dan pena, dan ingin agar tindakan sekunder mudah diakses hanya untuk input tersebut, maka Anda dapat menampilkan tindakan sekunder hanya saat melayang di atasnya. Akselerator ini hanya terlihat ketika input pointer digunakan, jadi pastikan untuk menggunakan opsi lain untuk mendukung jenis input lainnya juga.

UI bersarang ditampilkan saat

Untuk informasi selengkapnya, lihat Interaksi mouse.

Penempatan antarmuka pengguna untuk tindakan primer dan sekunder

Jika Anda memutuskan bahwa tindakan sekunder harus diekspos di antarmuka pengguna 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-contoh ini, kita berbicara tentang antarmuka 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 grid. 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 berfungsi dengan baik untuk orang 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 tersemat dalam item daftar, kami merekomendasikan 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 menjalankan, memilih (tunggal atau beberapa), atau operasi seret dan lepas, kami merekomendasikan teknik penggunaan tombol 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, tombol arah kanan menggeser fokus ke B.
  • Dari B, kunci arah kanan menempatkan fokus pada C.
  • Dari C, tombol arah kanan tidak melakukan operasi apa pun, atau jika ada elemen UI yang dapat difokuskan di sebelah kanan Daftar, fokus dipindahkan ke situ.
  • 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, tombol panah kanan mengarahkan fokus pada A.
  • Dari elemen UI di sebelah kanan Item Daftar, tombol panah kiri memfokuskan pada A.

Papan ketik

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

  • Dari A, tombol tab menempatkan fokus 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 menempatkan fokus pada elemen UI berikutnya yang dapat difokuskan dalam urutan tab terbalik.
  • Dari A, B, atau C, tombol panah bawah memfokuskan 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 di artikel ini.

UI berlapis di mana item daftar tidak melakukan tindakan

Anda mungkin menggunakan tampilan daftar karena menyediakan virtualisasi dan perilaku pengguliran yang optimal, tetapi tidak ada tindakan yang terkait dengan item daftar. Antarmuka pengguna ini biasanya menggunakan item daftar dengan tujuan mengelompokkan elemen dan memastikan bahwa elemen-elemen tersebut dapat digulir sebagai satu kesatuan.

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

Cuplikan layar dari UI Bersarang yang kompleks, menunjukkan banyak elemen bersarang yang dapat diinteraksi oleh 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 panah bawah memfokuskan pada Item Daftar berikutnya.
  • Dari Item Daftar, tombol kiri/kanan tidak melakukan operasi, 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.

Papan ketik

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 Bersarang dilalui, fokus akan diarahkan ke kontrol berikutnya dalam urutan tab setelah ListView.
  • Shift+Tab berfungsi dalam arah yang berlawanan dari perilaku tab.

Example

Contoh ini menunjukkan cara menerapkan UI berlapis tempat 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;
    }
}