Bagikan melalui


Tampilan tab

Kontrol TabView adalah cara untuk menampilkan sekumpulan tab dan konten masing-masing. Kontrol TabView berguna untuk menampilkan beberapa halaman (atau dokumen) konten sambil memungkinkan pengguna mengatur ulang, menutup, atau membuka tab baru.

TabView Contoh

Apakah ini kontrol yang tepat?

Secara umum, UI bertab hadir dalam salah satu dari dua gaya berbeda yang berbeda dalam fungsi dan penampilan:

  • tab Statis adalah jenis tab yang sering ditemukan di jendela pengaturan. Mereka berisi sejumlah halaman yang ditetapkan dalam urutan tetap yang biasanya berisi konten yang telah ditentukan sebelumnya.
  • Tab dokumen adalah jenis tab yang biasa ditemukan di peramban, seperti Microsoft Edge. Pengguna dapat membuat, menghapus, dan mengatur ulang tab; pindahkan tab antar jendela; dan ubah konten tab.

Secara default, TabView dikonfigurasi untuk menyediakan tab dokumen. Kami merekomendasikan TabView ketika pengguna akan dapat:

  • Buka, tutup, atau susun ulang tab secara dinamis.
  • Buka dokumen atau halaman web langsung ke tab.
  • Seret dan letakkan tab di antara jendela.

API TabView memungkinkan konfigurasi kontrol untuk tab statis. Namun, untuk mengikuti panduan desain Windows dan jika ada lebih dari beberapa item navigasi statis, pertimbangkan untuk menggunakan kontrol NavigationView.

anatomi

UI bertab dibuat dengan kontrol TabView dan satu atau beberapa kontrol TabViewItem. TabView menghosting instans TabViewItem, yang mewakili satu tab beserta isinya.

Bagian TabView

Gambar ini menunjukkan bagian-bagian kontrol TabView. Strip tab memiliki header dan footer, tetapi tidak seperti dokumen, header dan footer strip tab masing-masing berada di ujung kiri dan paling kanan strip.

Gambar ini memperlihatkan bagian kontrol tampilan tab. Strip tab berisi empat tab dan memiliki header dan footer, yang masing-masing berada di ujung kiri dan paling kanan strip.

Bagian TabViewItem

Gambar ini menunjukkan bagian-bagian dari kontrol TabViewItem. Meskipun konten ditampilkan di dalam kontrol TabView, konten sebenarnya adalah bagian dari TabViewItem.

Gambar ini memperlihatkan bagian kontrol item tampilan tab. Tab individual dipilih, yang memiliki ikon dan label, dengan area konten di bawah tab.

Rekomendasi

Pilihan tab

Sebagian besar pengguna memiliki pengalaman menggunakan tab dokumen hanya dengan menggunakan browser web. Saat mereka menggunakan tab dokumen di aplikasi Anda, pengalaman mereka membentuk harapan mereka tentang bagaimana tab Anda harus berperilaku.

Tidak peduli bagaimana pengguna berinteraksi dengan sekumpulan tab dokumen, harus selalu ada tab aktif. Jika pengguna menutup tab yang dipilih atau memecah tab yang dipilih keluar ke jendela lain, tab lain akan menjadi tab aktif. TabView mencoba melakukan ini secara otomatis memilih tab berikutnya. Jika Anda memiliki alasan yang baik bahwa aplikasi Anda harus mengizinkan TabView dengan tab yang tidak dipilih, area konten TabView hanya akan kosong.

Navigasi papan ketik

TabView mendukung banyak skenario navigasi keyboard umum secara default. Bagian ini menjelaskan fungsionalitas bawaan, dan memberikan rekomendasi tentang fungsionalitas tambahan yang mungkin berguna untuk beberapa aplikasi.

Perilaku tab dan tombol kursor

Saat fokus berpindah ke area TabStrip, TabViewItem yang dipilih mendapatkan fokus. Pengguna kemudian dapat menggunakan tombol panah Kiri dan Kanan untuk memindahkan fokus (bukan pilihan) ke tab lain di strip tab. Fokus panah terperangkap di dalam strip tab dan tombol tambahkan tab (+), jika ada. Untuk memindahkan fokus keluar dari area strip tab, pengguna dapat menekan tombol Tab, yang akan memindahkan fokus ke elemen yang dapat difokuskan berikutnya.

Pindahkan fokus melalui tab

Pindahkan fokus melalui tab

Tombol panah tidak mengubah fokus

Tombol panah tidak mengubah fokus

Memilih tab

Saat TabViewItem memiliki fokus, tekan Space atau Enter untuk memilih TabViewItem tersebut.

Gunakan tombol panah untuk memindahkan fokus, lalu tekan Spasi untuk memilih tab.

Spasi untuk memilih tab

Pintasan untuk memilih tab yang berdekatan

Tekan Ctrl+Tab untuk memilih TabViewItemberikutnya. Tekan Ctrl+Shift+Tab untuk memilih TabViewItem sebelumnya. Untuk tujuan ini, daftar tab tersebut "dilanjutkan ke awal", sehingga ketika memilih tab berikutnya saat tab terakhir dipilih, tab pertama akan terpilih.

Menutup tab

Tekan Ctrl + F4 untuk memicu peristiwa TabCloseRequested. Tangani peristiwa dan tutup tab jika sesuai.

Kiat

Untuk informasi selengkapnya, lihat panduan Keyboard untuk pengembang nanti di artikel ini.

Membuat tampilan tab

Aplikasi WinUI 3 Gallery mencakup contoh interaktif sebagian besar kontrol, fitur, dan fungsi WinUI 3. Dapatkan aplikasi dari Microsoft Store atau dapatkan kode sumber di GitHub

Contoh di bagian ini menunjukkan berbagai cara untuk mengonfigurasi kontrol TabView.

Item tampilan tab

Setiap tab dalam TabView diwakili oleh kontrol TabViewItem, yang mencakup tab yang ditampilkan di strip tab dan konten yang ditunjukkan di bawah strip tab.

Mengonfigurasi tab

Untuk setiap TabViewItem, Anda dapat mengatur header dan ikon, dan menentukan apakah pengguna dapat menutup tab.

  • Properti Header biasanya diatur ke nilai string yang menyediakan label deskriptif untuk tab. Namun, properti Header dapat berupa objek apa pun. Anda juga dapat menggunakan properti HeaderTemplate untuk menentukan DataTemplate yang menentukan bagaimana data header terikat harus ditampilkan.
  • Atur properti IconSource untuk menentukan ikon untuk tab.
  • Secara default, tab memperlihatkan tombol tutup (X). Anda dapat mengatur properti IsClosable ke false untuk menyembunyikan tombol tutup dan memastikan bahwa pengguna tidak dapat menutup tab. (Jika Anda menutup tab dalam kode aplikasi Anda di luar peristiwa permintaan penutupan , Anda harus terlebih dahulu memeriksa bahwa IsClosable adalah true.)

Untuk TabView, Anda dapat mengonfigurasi beberapa opsi yang berlaku untuk semua tab.

  • Secara default, tombol tutup selalu ditampilkan untuk tab yang dapat ditutup. Anda dapat mengatur properti CloseButtonOverlayMode ke OnPointerOver untuk mengubah perilaku ini. Dalam hal ini, tab yang dipilih selalu menampilkan tombol tutup jika dapat ditutup, tetapi tab yang tidak dipilih memperlihatkan tombol tutup hanya ketika tab dapat ditutup dan pengguna memiliki penunjuk mereka di atasnya.
  • Anda dapat mengatur properti TabWidthMode untuk mengubah ukuran tab. (Properti Width diabaikan pada TabViewItem.) Ini adalah opsi dalam enumerasi TabViewWidthMode:
    • Equal - Setiap tab memiliki lebar yang sama. Ini adalah default.
    • SizeToContent - Setiap tab menyesuaikan lebarnya ke konten di dalam tab.
    • Compact - Tab yang tidak dipilih dikecilkan untuk hanya memperlihatkan ikonnya. Tab yang dipilih menyesuaikan untuk menampilkan konten di dalam tab.

Konten

Elemen yang ditampilkan di tab yang dipilih ditambahkan ke properti Konten dari TabViewItem. TabViewItem adalah ContentControl, sehingga Anda dapat menambahkan semua jenis objek sebagai konten. Anda juga dapat menerapkan DataTemplate ke properti ContentTemplate. Lihat kelas ContentControl untuk informasi selengkapnya.

Contoh dalam artikel ini menunjukkan kasus sederhana menambahkan teks langsung ke elemen Content di XAML. Namun, UI nyata biasanya lebih kompleks. Cara umum untuk menambahkan UI kompleks sebagai konten dari sebuah tab adalah dengan merangkumnya dalam UserControl atau Halaman, dan menambahkannya sebagai konten dari TabViewItem. Contoh ini mengasumsikan aplikasi Anda memiliki UserControl XAML yang disebut PictureSettingsControl.

<TabViewItem>
    <TabViewItem.Content>
        <local:PictureSettingsControl/>
    </TabViewItem.Content>
</TabViewItem>

Tab statis

Contoh ini menunjukkan TabView sederhana dengan dua tab statis . Kedua item tab ditambahkan di XAML sebagai konten TabView.

Untuk membuat TabView statis, gunakan pengaturan ini:

  • Atur properti IsAddTabButtonVisible ke false untuk menyembunyikan tombol tambahkan tab dan mencegah peristiwa AddTabButtonClick agar tidak diaktifkan.
  • Atur properti CanReorderTabs ke false untuk mencegah pengguna menyeret tab ke dalam urutan yang berbeda.
  • Pada setiap TabViewItem, atur properti IsClosable ke false untuk menyembunyikan tombol tutup tab dan mencegah pengguna memicu peristiwa TabCloseRequested.
<TabView VerticalAlignment="Stretch"
         IsAddTabButtonVisible="False"
         CanReorderTabs="False">
    <TabViewItem Header="Picture" IsClosable="False">
        <TabViewItem.IconSource>
            <SymbolIconSource Symbol="Pictures"/>
        </TabViewItem.IconSource>
        <TabViewItem.Content>
            <StackPanel Padding="12">
                <TextBlock Text="Picture settings" 
                    Style="{ThemeResource TitleTextBlockStyle}"/>
            </StackPanel>
        </TabViewItem.Content>
    </TabViewItem>
    <TabViewItem Header="Sound" IsClosable="False">
        <TabViewItem.IconSource>
            <SymbolIconSource Symbol="Audio"/>
        </TabViewItem.IconSource>
        <TabViewItem.Content>
            <StackPanel Padding="12">
                <TextBlock Text="Sound settings" 
                    Style="{ThemeResource TitleTextBlockStyle}"/>
            </StackPanel>
        </TabViewItem.Content>
    </TabViewItem>
</TabView>

Tab Dokumen

Secara default, TabView dikonfigurasi untuk tab dokumen . Pengguna dapat menambahkan tab baru, mengatur ulang tab, dan menutup tab. Dalam konfigurasi ini, Anda perlu menangani AddTabButtonClick dan TabCloseRequested event untuk mengaktifkan fungsionalitas.

Saat tab ditambahkan ke TabView, pada akhirnya mungkin ada terlalu banyak tab untuk ditampilkan di strip tab Anda. Dalam hal ini, bumper gulir akan muncul yang memungkinkan pengguna menggulir strip tab ke kiri dan kanan untuk mengakses tab tersembunyi.

Contoh ini membuat TabView sederhana bersama dengan penanganan aktivitas untuk mendukung tab pembukaan dan penutupan. Penanganan aktivitas TabView_AddTabButtonClick menunjukkan cara menambahkan TabViewItem dalam kode.

<TabView VerticalAlignment="Stretch"
         AddTabButtonClick="TabView_AddTabButtonClick"
         TabCloseRequested="TabView_TabCloseRequested">
    <TabViewItem Header="Home" IsClosable="False">
        <TabViewItem.IconSource>
            <SymbolIconSource Symbol="Home" />
        </TabViewItem.IconSource>
        <TabViewItem.Content>
            <StackPanel Padding="12">
                <TextBlock Text="TabView content" 
                           Style="{ThemeResource TitleTextBlockStyle}"/>
            </StackPanel>
        </TabViewItem.Content>
    </TabViewItem>
</TabView>
// Add a new tab to the TabView.
private void TabView_AddTabButtonClick(TabView sender, object args)
{
    var newTab = new TabViewItem();
    newTab.Header = $"New Document {sender.TabItems.Count}";
    newTab.IconSource = new SymbolIconSource() { Symbol = Symbol.Document };
    newTab.Content = new TextBlock() { Text = $"Content for new tab {sender.TabItems.Count}.",
                                       Padding = new Thickness(12) };
    sender.TabItems.Add(newTab);
    sender.SelectedItem = newTab;
}

// Remove the requested tab from the TabView.
private void TabView_TabCloseRequested(TabView sender, 
                                       TabViewTabCloseRequestedEventArgs args)
{
    sender.TabItems.Remove(args.Tab);
}

Tutup jendela saat tab terakhir ditutup

Jika semua tab di aplikasi Anda dapat ditutup dan jendela aplikasi Anda harus ditutup saat tab terakhir ditutup, Anda juga harus menutup jendela di penanganan peristiwa TabCloseRequested.

Pertama, dalam file App.xaml.cs, tambahkan properti public static yang akan memungkinkan Anda mengakses instans Window dari Page yang menghosting TabView. (Lihat migrasi antarmuka pengguna.)

public partial class App : Application
{
    // ... code removed.

    // Add this.
    public static Window Window { get { return m_window; } }
    // Update this to make it static.
    private static Window m_window;
}

Kemudian, ubah penanganan aktivitas TabCloseRequested untuk memanggil Window.Close jika semua tab telah dihapus dari TabView.

// Remove the requested tab from the TabView.
// If all tabs have been removed, close the Window.
private void TabView_TabCloseRequested(TabView sender, 
                                       TabViewTabCloseRequestedEventArgs args)
{
    sender.TabItems.Remove(args.Tab);

    if (sender.TabItems.Count == 0)
    {
        App.Window.Close();
    }
}

Catatan

Contoh ini berfungsi untuk aplikasi dengan satu jendela (MainWindow). Jika aplikasi Anda memiliki beberapa jendela, atau Anda telah mengaktifkan pemisah tab, Anda perlu melacak jendela lalu menemukan jendela yang benar untuk ditutup. Lihat bagian berikutnya untuk contoh ini.

Pelepasan Tab

Pelepasan Tab menjelaskan apa yang terjadi ketika pengguna menyeret tab keluar dari strip tab TabView dan memindahkannya ke kontrol TabView lain, dalam kebanyakan kasus di jendela baru.

Mulai Windows App SDK 1.6, TabView memiliki properti CanTearOutTabs yang dapat Anda atur untuk memberikan pengalaman yang disempurnakan dalam menyeret tab ke jendela baru. Saat pengguna menyeret tab keluar dari strip tab dengan opsi ini diaktifkan, jendela baru segera dibuat selama seret, memungkinkan pengguna untuk menyeretnya ke tepi layar untuk memaksimalkan atau memposisikan jendela dalam satu gerakan halus. Implementasi ini juga tidak menggunakan API seret dan letakkan, sehingga tidak terpengaruh oleh batasan apa pun dalam API tersebut.

Saat Anda mengatur properti CanTearOutTabs ke true, hal ini menyebabkan tab merobek peristiwa dinaikkan alih-alih peristiwa seret dan letakkan. Untuk mengimplementasikan pencabutan tab, Anda harus menangani event ini:

  • TabTearOutWindowRequested

    Kejadian ini terjadi ketika tab pertama kali diseret keluar dari strip tab. Gunakan metode ini untuk membuat jendela dan tabView baru tempat tab akan dipindahkan.

  • PermintaanPemisahanTab

    Kejadian ini terjadi setelah Jendela baru disediakan. Tangani untuk memindahkan tab robek dari TabView asal ke TabView di jendela baru.

  • Tab-TercabutEksternalJatuh

    Kejadian ini terjadi ketika tab robek diseret melalui TabView yang ada. Tangani di TabView yang menerima tab yang terlepas untuk menunjukkan apakah tab tersebut sebaiknya diterima atau tidak.

  • TabTerlepasEksternalDijatuhkan

    Peristiwa ini terjadi ketika tab robek diseret melalui TabView yang ada dan peristiwa ExternalTornOutTabsDropping telah menunjukkan bahwa penurunan diizinkan. Tangani di TabView yang menerima tab robek untuk menghapus tab dari TabView asal dan sisipkan ke tabView penerimaan pada indeks yang ditentukan.

Peristiwa ini tidak terjadi ketika pemisahan tab diaktifkan: TabDragStarting, TabStripDragOver, TabStripDrop, TabDragCompleted, TabDroppedOutside.

Peringatan

Dukungan pemisahan tab tersedia dalam proses yang dijalankan dengan hak akses tinggi sebagai Administrator.

Contoh berikut menunjukkan cara mengimplementasikan penanganan aktivitas untuk mendukung tab robek.

Menyiapkan TabView

XAML ini mengonfigurasi properti CanTearOutTabs ke true dan menyiapkan penanganan kejadian pemecah tab.

<TabView x:Name="tabView"
     CanTearOutTabs="True"
     TabTearOutWindowRequested="TabView_TabTearOutWindowRequested"
     TabTearOutRequested="TabView_TabTearOutRequested"
     ExternalTornOutTabsDropping="TabView_ExternalTornOutTabsDropping"
     ExternalTornOutTabsDropped="TabView_ExternalTornOutTabsDropped">
    <!-- TabView content -->
</TabView>

Membuat dan melacak jendela baru

Pemindahan tab mengharuskan Anda membuat dan mengelola jendela baru di aplikasi Anda.

Kiat

Aplikasi Galeri WinUI menyertakan kelas WindowHelper yang memudahkan pengelolaan jendela di aplikasi Anda. Anda dapat menyalinnya dari GitHub di repositori Galeri WinUI: WindowHelper.cs. Kami merekomendasikan kelas bantu ini untuk mengimplementasikan memisahkan tab. Lihat TabViewWindowingSamplePage di GitHub untuk melihat cara menggunakannya.

Dalam artikel ini, metode pembantu disalin dari WindowHelper.cs, tetapi dimodifikasi dan ditampilkan secara langsung untuk kemudahan membaca.

Di sini, daftar untuk melacak semua jendela aktif dibuat di App.xaml.cs. Metode OnLaunched diperbarui untuk melacak jendela setelah dibuat. (Ini tidak diperlukan jika Anda menggunakan kelas WindowHelper.)

static public List<Window> ActiveWindows = new List<Window>();

protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    m_window = new MainWindow();
    // Track this window.
    ActiveWindows.Add(m_window);
    m_window.Activate();
}

Saat tab robek dimulai, jendela baru diminta. Di sini, variabel tabTearOutWindow menyediakan akses ke jendela baru setelah dibuat. Metode CreateWindow dan TrackWindow helper membuat jendela baru dan menambahkannya ke daftar pelacakan jendela aktif.

Setelah membuat jendela baru, Anda perlu membuat Halaman baru dan mengaturnya sebagai konten jendela. Halaman baru harus berisi kontrol TabView yang akan Anda pindahkan tab yang dikoyak ke dalam penanganan aktivitas TabTearOutRequested.

Tip

Dalam contoh ini, kami membuat kelas MainPage baru, karena hanya berisi TabView kosong (tidak ada tab yang ditambahkan langsung di XAML). Jika MainPage menyertakan elemen UI lain yang seharusnya tidak muncul di jendela robek, Anda dapat membuat halaman terpisah yang hanya menyertakan elemen yang Anda butuhkan (termasuk setidaknya TabView), dan membuat instans halaman tersebut.

Terakhir, tetapkan AppWindow.Id jendela baru ke propertiargs. NewWindowId. Ini akan digunakan di properti TabViewTabTearOutRequestedEventArgs.NewWindowId sehingga Anda dapat mengakses jendela dari penanganan aktivitas tersebut.

private Window? tabTearOutWindow = null;

private void TabView_TabTearOutWindowRequested(TabView sender, TabViewTabTearOutWindowRequestedEventArgs args)
{
    tabTearOutWindow = CreateWindow();
    tabTearOutWindow.Content = new MainPage();
    // Optional window setup, such as setting the icon or
    // extending content into the title bar happens here.
    args.NewWindowId = tabTearOutWindow.AppWindow.Id;
}

private Window CreateWindow()
{
    Window newWindow = new Window
    {
        SystemBackdrop = new MicaBackdrop()
    };
    newWindow.Title = "Torn Out Window";
    TrackWindow(newWindow);
    return newWindow;
}

private void TrackWindow(Window window)
{
    window.Closed += (sender, args) => {
        App.ActiveWindows.Remove(window);
    };
    App.ActiveWindows.Add(window);
}

Tutup jendela saat tab terakhir ditutup

Seperti disebutkan sebelumnya, Anda, mungkin ingin menutup jendela saat tab terakhir di TabView ditutup. Jika aplikasi Anda memiliki beberapa jendela, Anda perlu menemukan jendela yang benar untuk menutup dalam daftar jendela yang dilacak. Contoh ini menunjukkan cara melakukannya.

// Remove the requested tab from the TabView.
// If all tabs have been removed, close the Window.
private void TabView_TabCloseRequested(TabView sender, TabViewTabCloseRequestedEventArgs args)
{
    sender.TabItems.Remove(args.Tab);

    if (sender.TabItems.Count == 0)
    {
        GetWindowForElement(this)?.Close();
    }
}

public Window? GetWindowForElement(UIElement element)
{
    if (element.XamlRoot != null)
    {
        foreach (Window window in App.ActiveWindows)
        {
            if (element.XamlRoot == window.Content.XamlRoot)
            {
                return window;
            }
        }
    }
    return null;
}

Memindahkan tab ke jendela baru

Setelah jendela baru disediakan, Anda perlu menghapus tab robek dari sender TabView dan menambahkannya ke TabView di jendela baru. Dalam contoh ini, metode bantu public AddTabToTabs memungkinkan Anda mengakses TabView pada instance MainPage yang baru dari instance halaman asli untuk menambahkan tab yang terlepas ke dalamnya.

private void TabView_TabTearOutRequested(TabView sender, TabViewTabTearOutRequestedEventArgs args)
{
    if (tabTearOutWindow?.Content is MainPage newPage
        && args.Tabs.FirstOrDefault() is TabViewItem tab)
    {
        sender.TabItems.Remove(tab);
        newPage.AddTabToTabs(tab);
    }
}

// This method provides access to the TabView from
// another page instance so you can add the torn-out tab.
public void AddTabToTabs(TabViewItem tab)
{
    tabView.TabItems.Add(tab);
}

Seret tab robek ke TabView lain

Ketika tab telah dicabik-cabik dan ditempatkan ke jendela baru, seperti yang ditunjukkan pada langkah-langkah sebelumnya, salah satu dari dua hal dapat terjadi:

  • Pengguna dapat menjatuhkan tab dan tetap berada di jendela baru. Proses air mata berakhir di sini dan tidak ada lagi peristiwa yang diangkat.
  • Pengguna dapat terus menyeret tab robek kembali ke kontrol TabView yang ada. Dalam hal ini, proses berlanjut dan beberapa peristiwa lagi dinaikkan untuk memungkinkan Anda menghapus tab dari TabView asli dan menyisipkan tab eksternal ke TabView yang ada.

Saat tab diseret ke atas TabView yang ada, peristiwa ExternalTornOutTabsDropping diaktifkan. Di penanganan aktivitas, Anda dapat menentukan apakah menyisipkan tab ke dalam TabView ini diizinkan. Dalam kebanyakan kasus, Anda hanya perlu mengatur propertiargs. AllowDrop ke true. Namun, jika Anda perlu melakukan pemeriksaan sebelum mengatur properti tersebut, Anda dapat melakukannya di sini. Jika AllowDrop diatur ke false, tindakan seret tab berlanjut dan peristiwa ExternalTornOutTabsDropped tidak diaktifkan.

private void TabView_ExternalTornOutTabsDropping(TabView sender, 
                        TabViewExternalTornOutTabsDroppingEventArgs args)
{
    args.AllowDrop = true;
}

Jika AllowDrop diatur ke true di pengendali acara ExternalTornOutTabsDropping, peristiwa ExternalTornOutTabsDropped segera dipicu.

Catatan

Dropped dalam nama peristiwa tidak langsung berkaitan dengan konsep tindakan menjatuhkan di API drag-and-drop. Di sini, pengguna tidak perlu merilis tab untuk melakukan tindakan drop. Peristiwa dipicu saat tab ditahan di atas strip tab, dan kode dijalankan untuk menjatuhkan tab ke dalam TabView.

Penanganan acara ExternalTornOutTabsDropped mengikuti pola yang sama dengan acara TabTearOutRequested, tetapi terbalik, Anda perlu menghapus tab dari TabView asal dan menyisipkannya ke TabView sender.

TabView sender adalah kontrol tempat tab dimasukkan, jadi kami menggunakan metode pembantu GetParentTabView untuk menemukan tab asal. Proses ini dimulai dengan TabViewItem yang ditarik keluar dan menggunakan VisualTreeHelper untuk berjalan menaiki pohon visual dan menemukan TabView yang menjadi milik item tersebut. Setelah TabView ditemukan, TabViewItem dihapus dari koleksi TabItems dan disisipkan ke dalam koleksi TabItems TabView sender pada indeks yang ditentukan oleh args.DropIndex.

private void TabView_ExternalTornOutTabsDropped(TabView sender, 
                             TabViewExternalTornOutTabsDroppedEventArgs args)
{
    if (args.Tabs.FirstOrDefault() is TabViewItem tab)
    {
        GetParentTabView(tab)?.TabItems.Remove(tab);
        sender.TabItems.Insert(args.DropIndex, tab);
    }
}

// Starting with the TabViewItem, walk up the
// visual tree until you get to the TabView.
private TabView? GetParentTabView(TabViewItem tab)
{
    DependencyObject current = tab;
    while (current != null)
    {
        if (current is TabView tabView)
        {
            return tabView;
        }
        current = VisualTreeHelper.GetParent(current);
    }
    return null;
}

Tips

Jika Anda menggunakan Windows Community Toolkit, Anda dapat menggunakan metode pembantu FindAscendant pada DependencyObjectExtensions milik toolkit, bukan GetParentTabView.

Tampilkan tab "TabView" di bilah judul jendela

Alih-alih memiliki tab yang menempati barisnya sendiri di bawah bilah judul Jendela, Anda dapat menggabungkan keduanya ke area yang sama. Ini menghemat ruang vertikal untuk konten Anda, dan memberi aplikasi Anda nuansa modern.

Karena pengguna dapat menyeret jendela dengan bilah judulnya untuk memposisikan ulang Jendela, penting bahwa bilah judul tidak sepenuhnya diisi dengan tab. Oleh karena itu, saat menampilkan tab di bilah judul, Anda harus menentukan sebagian bilah judul untuk dijadikan area yang dapat diseret. Jika Anda tidak menentukan wilayah yang dapat diseret, seluruh bilah judul akan dapat diseret, yang mencegah tab Anda menerima peristiwa input. Jika TabView Anda akan ditampilkan di bilah judul jendela, Anda harus selalu menyertakan TabStripFooter di TabView Anda dan menandainya sebagai wilayah yang dapat diseret.

Untuk informasi selengkapnya, lihat Kustomisasi bilah judul

Tab di bilah judul

<TabView VerticalAlignment="Stretch">
    <TabViewItem Header="Home" IsClosable="False">
        <TabViewItem.IconSource>
            <SymbolIconSource Symbol="Home" />
        </TabViewItem.IconSource>
    </TabViewItem>

    <TabView.TabStripFooter>
        <Grid x:Name="CustomDragRegion" Background="Transparent" />
    </TabView.TabStripFooter>
</TabView>
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    App.Window.ExtendsContentIntoTitleBar = true;
    App.Window.SetTitleBar(CustomDragRegion);
    CustomDragRegion.MinWidth = 188;
}

Catatan

Cara Anda mendapatkan referensi ke jendela dapat bervariasi tergantung pada cara Anda melacak jendela di aplikasi Anda. Untuk informasi selengkapnya, lihat Tutup jendela saat tab terakhir ditutup dan Buat dan lacak jendela baru di artikel ini.

Panduan keyboard untuk pengembang

Tip

Untuk informasi selengkapnya tentang dukungan keyboard bawaan, lihat navigasi keyboard yang dibahas sebelumnya di artikel ini.

Beberapa aplikasi mungkin memerlukan kontrol keyboard yang lebih canggih. Pertimbangkan untuk menerapkan pintasan berikut jika sesuai untuk aplikasi Anda.

Peringatan

Jika Anda menambahkan TabView ke aplikasi yang sudah ada, Anda mungkin telah membuat pintasan keyboard yang memetakan ke kombinasi tombol pintasan keyboard TabView yang direkomendasikan. Dalam hal ini, Anda harus mempertimbangkan apakah akan menyimpan pintasan yang ada atau menawarkan pengalaman tab intuitif bagi pengguna.

  • Ctrl + T akan membuka tab baru. Umumnya tab ini diisi dengan dokumen yang telah ditentukan sebelumnya, atau dibuat kosong dengan cara sederhana untuk memilih kontennya. Jika pengguna harus memilih konten untuk tab baru, pertimbangkan untuk memberikan fokus input ke kontrol pemilihan konten.
  • Ctrl + W harus menutup tab yang dipilih. Ingat, TabView akan memilih tab berikutnya secara otomatis.
  • Ctrl + Shift + T harus membuka tab tertutup baru-baru ini (atau lebih akurat, membuka tab baru dengan konten yang sama seperti tab yang baru saja ditutup). Mulailah dengan tab yang terakhir ditutup, dan pindah berurutan ke belakang setiap kali pintasan digunakan. Perhatikan bahwa ini akan mengharuskan mempertahankan daftar tab yang baru saja ditutup.
  • Ctrl + 1 harus memilih tab pertama di daftar tab. Demikian juga, Ctrl + 2 harus memilih tab kedua, Ctrl + 3 harus memilih yang ketiga, dan sebagainya melalui Ctrl + 8.
  • Ctrl + 9 harus memilih tab terakhir dalam daftar tab, terlepas dari berapa banyak tab dalam daftar.
  • Jika tab menawarkan lebih dari sekadar perintah tutup (seperti menduplikasi atau menyematkan tab), gunakan menu konteks untuk menampilkan semua tindakan yang tersedia yang dapat dilakukan pada tab.

Menerapkan perilaku pengetikan seperti browser

Contoh ini mengimplementasikan sejumlah rekomendasi di atas pada TabView. Secara khusus, Contoh ini mengimplementasikan Ctrl + T, Ctrl + W, Ctrl + 1-8, dan Ctrl + 9.

<TabView>
    <!-- ... some tabs ... -->
    <TabView.KeyboardAccelerators>
        <KeyboardAccelerator Key="T" Modifiers="Control"
                             Invoked="NewTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="W" Modifiers="Control"
                             Invoked="CloseSelectedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number1" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number2" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number3" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number4" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number5" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number6" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number7" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number8" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
        <KeyboardAccelerator Key="Number9" Modifiers="Control"
                             Invoked="NavigateToNumberedTabKeyboardAccelerator_Invoked" />
    </TabView.KeyboardAccelerators>
</TabView>

private void NewTabKeyboardAccelerator_Invoked(KeyboardAccelerator sender,
                                      KeyboardAcceleratorInvokedEventArgs args)
{
    // Create new tab.
    TabView senderTabView = (TabView)args.Element;
    if (senderTabView is not null)
    {
        // (Click handler defined in previous example.)
        TabView_AddTabButtonClick(senderTabView, new EventArgs());
    }
    args.Handled = true;
}

private void CloseSelectedTabKeyboardAccelerator_Invoked(KeyboardAccelerator sender,
                                                KeyboardAcceleratorInvokedEventArgs args)
{
    TabView tabView = (TabView)args.Element;
    TabViewItem tab = (TabViewItem)tabView.SelectedItem;
    if (tab is not null)
    {
        CloseSelectedTab(tabView, tab);
    }
    args.Handled = true;
}

private void TabView_TabCloseRequested(TabView sender, TabViewTabCloseRequestedEventArgs args)
{
    CloseSelectedTab(sender, args.Tab);
}

private void CloseSelectedTab(TabView tabView, TabViewItem tab)
{
    // Only remove the selected tab if it can be closed.
    if (tab.IsClosable == true)
    {
        tabView.TabItems.Remove(tab);
    }
}


private void NavigateToNumberedTabKeyboardAccelerator_Invoked(KeyboardAccelerator sender,
                                                     KeyboardAcceleratorInvokedEventArgs args)
{
    TabView tabView = (TabView)args.Element;
    int tabToSelect = 0;

    switch (sender.Key)
    {
        case Windows.System.VirtualKey.Number1:
            tabToSelect = 0;
            break;
        case Windows.System.VirtualKey.Number2:
            tabToSelect = 1;
            break;
        case Windows.System.VirtualKey.Number3:
            tabToSelect = 2;
            break;
        case Windows.System.VirtualKey.Number4:
            tabToSelect = 3;
            break;
        case Windows.System.VirtualKey.Number5:
            tabToSelect = 4;
            break;
        case Windows.System.VirtualKey.Number6:
            tabToSelect = 5;
            break;
        case Windows.System.VirtualKey.Number7:
            tabToSelect = 6;
            break;
        case Windows.System.VirtualKey.Number8:
            tabToSelect = 7;
            break;
        case Windows.System.VirtualKey.Number9:
            // Select the last tab
            tabToSelect = tabView.TabItems.Count - 1;
            break;
    }

    // Only select the tab if it is in the list.
    if (tabToSelect < tabView.TabItems.Count)
    {
        tabView.SelectedIndex = tabToSelect;
    }
}

UWP dan WinUI 2

Penting

Informasi dan contoh dalam artikel ini dioptimalkan untuk aplikasi yang menggunakan Windows App SDK dan WinUI 3, tetapi umumnya berlaku untuk aplikasi UWP yang menggunakan WinUI 2. Lihat referensi API UWP untuk informasi dan contoh spesifik platform.

Bagian ini berisi informasi yang Anda butuhkan untuk menggunakan kontrol di aplikasi UWP atau WinUI 2.

Kontrol TabView untuk aplikasi UWP disertakan sebagai bagian dari WinUI 2. Untuk informasi selengkapnya, termasuk instruksi penginstalan, lihat WinUI 2. API untuk kontrol ini ada di microsoft.UI.Xaml.Controls namespace.

API untuk pemisahan tab tidak tersedia di TabView versi WinUI 2.

Kami merekomendasikan menggunakan WinUI 2 terbaru untuk mendapatkan gaya, templat, dan fitur terbaru untuk semua kontrol. WinUI 2.2 atau yang lebih baru menyertakan templat baru untuk kontrol ini yang menggunakan sudut bulat. Untuk informasi selengkapnya, lihat Radius Sudut.

Untuk menggunakan kode dalam artikel ini dengan WinUI 2, gunakan alias di XAML (kami menggunakan muxc) untuk mewakili API Pustaka UI Windows yang disertakan dalam proyek Anda. Lihat Mulai menggunakan WinUI 2 untuk informasi selengkapnya.

xmlns:muxc="using:Microsoft.UI.Xaml.Controls"

<muxc:TabView />