Bagikan melalui


Kustomisasi bilah judul

Windows menyediakan bilah judul default untuk setiap jendela dan memungkinkan Anda menyesuaikannya agar sesuai dengan kepribadian aplikasi Anda. Bilah judul default dilengkapi dengan beberapa komponen standar dan fungsionalitas inti seperti menyeret dan mengubah ukuran jendela.

Aplikasi Windows memperlihatkan bilah judul

Lihat artikel Desain bilah judul untuk panduan tentang menyesuaikan bilah judul aplikasi Anda, konten area bilah judul yang dapat diterima, dan pola UI yang direkomendasikan.

Penting

Artikel ini memperlihatkan cara mengkustomisasi bilah judul untuk aplikasi yang menggunakan SDK Aplikasi Windows, baik dengan atau tanpa WinUI 3. Untuk aplikasi yang menggunakan UWP dan WinUI 2, lihat Kustomisasi bilah judul untuk UWP.

Komponen bilah judul

Daftar ini menjelaskan komponen bilah judul standar.

  • Persegi bilah judul
  • Teks judul
  • Ikon sistem
  • Menu sistem - diakses dengan mengklik ikon aplikasi atau mengklik kanan bilah judul
  • Kontrol keterangan
    • Tombol Minimalkan
    • Tombol Maksimalkan/Pulihkan
    • Tombol Tutup

Windowing

Fungsionalitas windowing di SDK Aplikasi Windows adalah melalui kelas Microsoft.UI.Windowing.AppWindow, yang didasarkan pada model Win32 HWND. Ada pemetaan 1:1 antara AppWindow dan HWND tingkat atas di aplikasi Anda. AppWindow dan kelas terkait menyediakan API yang memungkinkan Anda mengelola banyak aspek jendela tingkat atas aplikasi Anda, termasuk penyesuaian bilah judul. Anda dapat mengubah bilah judul default yang disediakan Windows sehingga menyatu dengan UI Anda lainnya, atau memperluas kanvas aplikasi Anda ke area bilah judul dan menyediakan konten bilah judul Anda sendiri.

Fungsionalitas windowing di WinUI 3 adalah melalui kelas Microsoft.UI.Xaml.Window , yang juga didasarkan pada model Win32 HWND. Untuk aplikasi XAML yang menggunakan WinUI 3, XAML Window API menyediakan cara yang lebih sederhana untuk menyesuaikan bilah judul, sambil tetap memungkinkan Anda mengakses API AppWindow saat diperlukan.

Cara bekerja dengan AppWindow

Anda dapat menggunakan API AppWindow dengan kerangka kerja UI apa pun yang didukung SDK Aplikasi Windows - Win32, WPF, WinForms, atau WinUI 3 - dan Anda dapat mengadopsinya secara bertahap, hanya menggunakan API yang Anda butuhkan.

Jika Anda menggunakan WinUI 3 XAML sebagai kerangka kerja UI aplikasi Anda, Baik Jendela maupun API AppWindow tersedia untuk Anda. Mulai SDK Aplikasi Windows 1.4, Jendela XAML dan AppWindow menggunakan objek AppWindowTitleBar yang sama untuk kustomisasi bilah judul. Gunakan properti Window.AppWindow untuk mendapatkan objek AppWindow dari jendela XAML yang ada. Dengan objek AppWindow ini, Anda memiliki akses ke API kustomisasi bilah judul. Untuk mengakses fitur tambahan bilah judul, Anda dapat menggunakan API AppWindow dari Jendela XAML Anda seperti ini: AppWindow.TitleBar.ForegroundColor = Colors.White;.

Jika Anda tidak menggunakan WinUI 3 1.3 atau yang lebih baru, gunakan API interop untuk mendapatkan AppWindow dan gunakan API AppWindow untuk menyesuaikan bilah judul. Untuk informasi selengkapnya tentang API interop, lihat Mengelola jendela aplikasi - kerangka kerja UI dan interop HWND dan sampel galeri Windowing.

Berapa banyak untuk menyesuaikan bilah judul

Ada dua tingkat kustomisasi yang dapat Anda terapkan ke bilah judul: terapkan modifikasi kecil pada bilah judul default, atau perluas kanvas aplikasi Anda ke area bilah judul dan berikan konten kustom sepenuhnya.

Sederhana

Untuk kustomisasi sederhana, seperti mengubah warna bilah judul, Anda dapat mengatur properti pada objek AppWindowTitleBar untuk menentukan warna yang ingin Anda gunakan untuk elemen bilah judul. Dalam hal ini, sistem mempertahankan tanggung jawab untuk semua aspek lain dari bilah judul, seperti menggambar judul aplikasi dan menentukan area seret.

Penuh

Opsi Anda yang lain adalah menyembunyikan bilah judul sistem default dan menggantinya dengan konten kustom Anda sendiri. Misalnya, Anda dapat menempatkan teks, kotak pencarian, atau menu kustom di area bilah judul. Anda juga perlu menggunakan opsi ini untuk memperluas backdrop material , seperti Mica, ke area bilah judul.

Saat Anda memilih kustomisasi penuh, Anda bertanggung jawab untuk menempatkan konten di area bilah judul, dan Anda dapat menentukan wilayah seret Anda sendiri. Kontrol keterangan (tombol Tutup, Minimalkan, dan Maksimalkan sistem) masih tersedia dan ditangani oleh sistem, tetapi elemen seperti judul aplikasi tidak. Anda harus membuat elemen tersebut sendiri sesuai kebutuhan aplikasi Anda.

Kustomisasi sederhana

Jika Anda hanya ingin mengkustomisasi judul, warna, atau ikon bilah judul, Anda dapat mengatur properti pada objek bilah judul untuk jendela aplikasi Anda.

Judul

Secara default, bilah judul menampilkan jenis aplikasi sebagai judul jendela (misalnya, "WinUI Desktop"). Anda harus memperbarui judul jendela untuk menampilkan nama tampilan yang bermakna untuk aplikasi Anda.

Aplikasi XAML memiliki nama tampilan yang diatur dalam Package.appxmanifest file. Anda bisa mendapatkan nilai ini dan menggunakannya untuk mengatur Title properti seperti ini.

Title = AppInfo.Current.DisplayInfo.DisplayName;

Untuk mengubah judul jendela, atur properti Window.Title ke nilai teks baris tunggal, seperti yang diperlihatkan di sini.

<Window
    ...
    Title="App title">
    ...
</Window>
public MainWindow()
{
    InitializeComponent();
    Title = "App title";
}

Untuk mengubah judul jendela menggunakan API AppWindow, atur properti AppWindow.Title ke nilai teks satu baris, seperti yang ditunjukkan di sini. Contoh ini menunjukkan cara menggunakan API interop untuk mendapatkan AppWindow, yang diperlukan aplikasi Anda tidak menggunakan WinUI 3 1.3 atau yang lebih baru.

using Microsoft.UI;           // Needed for WindowId.
using Microsoft.UI.Windowing; // Needed for AppWindow.
using WinRT.Interop;          // Needed for XAML/HWND interop.

private AppWindow m_AppWindow;

public MainWindow()
{
    this.InitializeComponent();

    m_AppWindow = GetAppWindowForCurrentWindow();
    m_AppWindow.Title = "App title";
}

private AppWindow GetAppWindowForCurrentWindow()
{
    IntPtr hWnd = WindowNative.GetWindowHandle(this);
    WindowId wndId = Win32Interop.GetWindowIdFromWindow(hWnd);
    return AppWindow.GetFromWindowId(wndId);
}

Warna

Untuk menyesuaikan warna bilah judul default atau mengubah ikon jendela default, Anda harus menggunakan API AppWindow atau memilih untuk sepenuhnya menyesuaikan bilah judul Anda.

Contoh ini menunjukkan cara mendapatkan instans AppWindowTitleBar dan mengatur properti warnanya.

Penting

Kustomisasi warna diabaikan saat aplikasi berjalan pada Windows 10.

// Assumes "this" is a XAML Window. In projects that don't use 
// WinUI 3 1.3 or later, use interop APIs to get the AppWindow.
AppWindow m_AppWindow = this.AppWindow;

private bool SetTitleBarColors()
{
    // Check to see if customization is supported.
    // The method returns true on Windows 10 since Windows App SDK 1.2,
    // and on all versions of Windows App SDK on Windows 11.
    if (AppWindowTitleBar.IsCustomizationSupported())
    {
        AppWindowTitleBar m_TitleBar = m_AppWindow.TitleBar;

        // Set active window colors.
        // Note: No effect when app is running on Windows 10
        // because color customization is not supported.
        m_TitleBar.ForegroundColor = Colors.White;
        m_TitleBar.BackgroundColor = Colors.Green;
        m_TitleBar.ButtonForegroundColor = Colors.White;
        m_TitleBar.ButtonBackgroundColor = Colors.SeaGreen;
        m_TitleBar.ButtonHoverForegroundColor = Colors.Gainsboro;
        m_TitleBar.ButtonHoverBackgroundColor = Colors.DarkSeaGreen;
        m_TitleBar.ButtonPressedForegroundColor = Colors.Gray;
        m_TitleBar.ButtonPressedBackgroundColor = Colors.LightGreen;

        // Set inactive window colors.
        // Note: No effect when app is running on Windows 10
        // because color customization is not supported.
        m_TitleBar.InactiveForegroundColor = Colors.Gainsboro;
        m_TitleBar.InactiveBackgroundColor = Colors.SeaGreen;
        m_TitleBar.ButtonInactiveForegroundColor = Colors.Gainsboro;
        m_TitleBar.ButtonInactiveBackgroundColor = Colors.SeaGreen;
        return true;
    }
    return false;
}

Ada beberapa hal yang perlu diperhatikan saat mengatur warna bilah judul:

  • Warna latar belakang tombol tidak diterapkan ke tombol tutup melayang dan status ditekan . Tombol tutup selalu menggunakan warna yang ditentukan sistem untuk status tersebut.
  • Mengatur properti warna untuk null meresetnya ke warna sistem default.
  • Anda tidak dapat mengatur warna transparan. Saluran alfa warna diabaikan.

Windows memberi pengguna opsi untuk menerapkan warna aksen yang dipilih ke bilah judul. Jika Anda mengatur warna bilah judul apa pun, kami sarankan Anda secara eksplisit mengatur semua warna. Ini memastikan bahwa tidak ada kombinasi warna yang tidak diinginkan yang terjadi karena pengaturan warna yang ditentukan pengguna.

Menu ikon dan sistem

Anda dapat menyembunyikan ikon sistem, atau menggantinya dengan ikon kustom. Ikon sistem menunjukkan menu sistem saat diklik kanan atau diketuk sekali. Ini menutup jendela saat diklik/diketuk dua kali.

Untuk menampilkan atau menyembunyikan ikon sistem dan perilaku terkait, atur properti bilah judul IconShowOptions .

m_TitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu;

Untuk menggunakan ikon jendela kustom, panggil salah satu metode AppWindow.SetIcon untuk mengatur ikon baru.

  • SetIcon(String)

    Metode SetIcon(String) saat ini hanya berfungsi dengan file .ico. String yang Anda teruskan ke metode ini adalah jalur yang sepenuhnya memenuhi syarat ke file .ico.

    m_AppWindow.SetIcon("iconPath/iconName.ico");
    
  • SetIcon(IconId)

    Jika Anda sudah memiliki handel ke ikon (HICON) dari salah satu fungsi Ikon seperti CreateIcon, Anda dapat menggunakan API interop GetIconIdFromIcon untuk mendapatkan IconId. Anda kemudian dapat meneruskan IconId ke metode SetIcon(IconId) untuk mengatur ikon jendela Anda.

    m_AppWindow.SetIcon(iconId));
    

Kustomisasi penuh

Saat Anda ikut serta dalam penyesuaian bilah judul lengkap, area klien aplikasi Anda diperluas untuk menutupi seluruh jendela, termasuk area bilah judul. Anda bertanggung jawab untuk menggambar dan menangani input untuk seluruh jendela kecuali tombol keterangan, yang masih disediakan oleh jendela.

Untuk menyembunyikan bilah judul sistem dan memperluas konten Anda ke area bilah judul, atur properti yang memperluas konten aplikasi ke area bilah judul ke true. Di aplikasi XAML, properti ini dapat diatur dalam metode aplikasi OnLaunched Anda (App.xaml.cs), atau di halaman pertama aplikasi Anda.

Tip

Lihat bagian Contoh kustomisasi lengkap untuk melihat semua kode sekaligus.

Contoh ini menunjukkan cara mengatur properti Window.ExtendsContentIntoTitleBar ke true.

public MainWindow()
{
    this.InitializeComponent();

    // Hide system title bar.
    ExtendsContentIntoTitleBar = true;
}

Perhatian

ExtendsContentIntoTitleBar menunjukkan di XAML IntelliSense untuk Window, tetapi mengaturnya di XAML menyebabkan kesalahan. Atur properti ini dalam kode sebagai gantinya.

Contoh ini menunjukkan cara mendapatkan AppWindowTitleBar dan mengatur properti AppWindow.ExtendsContentIntoTitleBar ke true. Contoh ini menunjukkan cara menggunakan API interop untuk mendapatkan AppWindow, yang diperlukan jika aplikasi Anda tidak menggunakan WinUI 3 1.3 atau yang lebih baru.

using Microsoft.UI;           // Needed for WindowId.
using Microsoft.UI.Windowing; // Needed for AppWindow.
using WinRT.Interop;          // Needed for XAML/HWND interop.

private AppWindow m_AppWindow;

public MainWindow()
{
    this.InitializeComponent();

    m_AppWindow = GetAppWindowForCurrentWindow();
    var titleBar = m_AppWindow.TitleBar;
    // Hide system title bar.
    titleBar.ExtendsContentIntoTitleBar = true;
}

private AppWindow GetAppWindowForCurrentWindow()
{
    IntPtr hWnd = WindowNative.GetWindowHandle(this);
    WindowId wndId = Win32Interop.GetWindowIdFromWindow(hWnd);
    return AppWindow.GetFromWindowId(wndId);
}

Konten bilah judul dan wilayah seret default

Saat aplikasi diperluas ke area bilah judul, Anda bertanggung jawab untuk menentukan dan mengelola UI untuk bilah judul. Ini biasanya mencakup, minimal, menentukan teks judul dan wilayah seret. Wilayah seret bilah judul menentukan tempat pengguna dapat mengklik dan menyeret untuk memindahkan jendela. Ini juga tempat pengguna dapat mengklik kanan untuk menampilkan menu sistem.

Untuk mempelajari selengkapnya tentang konten bilah judul yang dapat diterima dan pola antarmuka pengguna yang direkomendasikan, lihat Desain bilah judul.

Contoh ini menunjukkan XAML untuk antarmuka pengguna bilah judul kustom tanpa konten interaktif.

<Grid x:Name="AppTitleBar"  
      Height="32">
    <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>
        <ColumnDefinition/>
        <ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>
    </Grid.ColumnDefinitions>
    <Image x:Name="TitleBarIcon" Source="ms-appx:///Assets/StoreLogo.png"
           Grid.Column="1"
           HorizontalAlignment="Left"
           Width="16" Height="16"
           Margin="8,0,0,0"/>
    <TextBlock x:Name="TitleBarTextBlock" 
               Text="App title" 
               Style="{StaticResource CaptionTextBlockStyle}"
               Grid.Column="1"
               VerticalAlignment="Center"
               Margin="28,0,0,0"/>
</Grid>

Penting

LeftPaddingColumn dan RightPaddingColumn digunakan untuk memesan ruang untuk tombol keterangan. Nilai Width untuk kolom ini diatur dalam kode, yang ditampilkan nanti. Lihat bagian Tombol keterangan sistem untuk kode dan penjelasan.

Aplikasi XAML memiliki nama tampilan yang diatur dalam file Package.appxmanifest. Anda bisa mendapatkan nilai ini dan menggunakannya di bilah judul kustom Anda seperti ini.

TitleBarTextBlock.Text = AppInfo.Current.DisplayInfo.DisplayName;

Saat Anda memperluas konten ke area bilah judul, bilah judul sistem disembunyikan dan AppWindowTitleBar default dibuat yang menyediakan tombol keterangan dan wilayah seret di seluruh lebar layar, identik dengan bilah judul sistem. Jika Anda tidak menempatkan konten interaktif di bilah judul, Anda dapat membiarkan wilayah seret default ini apa adanya. Jika Anda menempatkan konten interaktif di bilah judul, Anda perlu menentukan wilayah yang interaktif, yang kami bahas di bagian berikutnya.

Perhatian

Saat Anda menentukan wilayah seret kustom, wilayah tersebut tidak harus berada di bagian atas jendela di area bilah judul default; Anda dapat menentukan bagian mana pun dari UI Anda sebagai wilayah seret. Namun, menempatkan wilayah seret di tempat yang berbeda mungkin menyulitkan pengguna Anda untuk menemukannya.

Konten interaktif

Anda dapat menempatkan kontrol interaktif, seperti tombol, menu, atau kotak pencarian, di bagian atas aplikasi sehingga terlihat berada di bilah judul. Namun, Anda perlu menentukan wilayah mana yang interaktif untuk memastikan bahwa elemen interaktif Anda menerima input pengguna sambil tetap memungkinkan pengguna untuk memindahkan jendela Anda.

Aplikasi Windows dengan kotak pencarian di bilah judul

Saat Anda menambahkan konten interaktif di area bilah judul, Anda perlu menggunakan kelas InputNonClientPointerSource untuk menentukan area tempat input diteruskan ke kontrol interaktif, daripada ditangani oleh bilah judul. Untuk mengatur wilayah interaktif, panggil metode InputNonClientPointerSource.SetRegionRects . Metode ini mengambil nilai yang menentukan jenis wilayah yang ditetapkan (dalam hal ini, Passthrough), dan array persegi panjang, yang masing-masing mendefinisikan Passthrough wilayah. Saat ukuran bilah judul berubah, Anda perlu menghitung ulang wilayah interaktif agar sesuai dengan ukuran baru, dan memanggil SetRegionRects dengan nilai baru.

Contoh ini memperlihatkan antarmuka pengguna bilah judul kustom dengan kotak pencarian dan kontrol akun PersonPicture. Ini menunjukkan cara menghitung dan mengatur persegi panjang interaktif untuk kontrol ini sehingga input diteruskan ke kontrol tersebut.

Berikut adalah beberapa poin penting yang perlu diperhatikan tentang kode ini:

  • Atur AppTitleBar tinggi Kisi ke 48 untuk mengikuti panduan desain bilah Judul untuk konten interaktif.
  • Atur PreferredHeightOption ke Tall sehingga tombol keterangan memiliki tinggi yang sama dengan bilah judul.
  • Untuk mempermudah mengubah ukuran kontrol dan menghitung wilayah, gunakan Grid dengan beberapa kolom bernama untuk tata letak.
  • Gunakan ukuran bintang (*) dengan MinWidth untuk kolom yang berisi AutoSuggestBox sehingga akan secara otomatis mengubah ukuran dengan jendela.
  • Atur MinWidth pada RightDragColumn untuk memesan area kecil yang selalu dapat diseret bahkan ketika jendela diubah ukurannya.
  • Atur ExtendsContentIntoTitleBar ke true di konstruktor MainWindow. Jika Anda mengaturnya dalam kode yang dipanggil nanti, bilah judul sistem default mungkin ditampilkan terlebih dahulu, lalu disembunyikan.
  • Lakukan panggilan awal untuk menghitung wilayah interaktif setelah elemen dimuat AppTitleBar . Jika tidak, tidak ada jaminan bahwa elemen yang digunakan untuk perhitungan akan memiliki nilai yang benar.
  • Perbarui perhitungan persegi panjang interaktif hanya setelah AppTitleBar elemen berubah ukuran (AppTitleBar_SizeChanged). Jika Anda bergantung pada peristiwa jendela Changed , akan ada situasi (seperti jendela memaksimalkan/meminimalkan) di mana peristiwa terjadi sebelum AppTitleBar diubah ukurannya dan perhitungan akan menggunakan nilai yang salah.
  • Atur area seret/interaktif kustom hanya setelah Anda memeriksa ExtendsContentIntoTitleBar untuk mengonfirmasi bahwa bilah judul kustom sedang digunakan.
<Grid x:Name="AppTitleBar"
      Height="48">
    <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>
        <ColumnDefinition x:Name="IconColumn" Width="Auto"/>
        <ColumnDefinition x:Name="TitleColumn" Width="Auto"/>
        <ColumnDefinition x:Name="LeftDragColumn" Width="*"/>
        <ColumnDefinition x:Name="SearchColumn" Width="4*" MinWidth="220"/>
        <ColumnDefinition x:Name="RightDragColumn" Width="*" MinWidth="48"/>
        <ColumnDefinition x:Name="AccountColumn" Width="Auto"/>
        <ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>
    </Grid.ColumnDefinitions>
    <Image x:Name="TitleBarIcon" 
           Source="ms-appx:///Assets/StoreLogo.png"
           Grid.Column="1"
           Width="16" Height="16"
           Margin="8,0,4,0"/>
    <TextBlock x:Name="TitleBarTextBlock"
               Text="App title" 
               Style="{StaticResource CaptionTextBlockStyle}"
               Grid.Column="2"
               VerticalAlignment="Center">
    </TextBlock>
    <AutoSuggestBox x:Name="TitleBarSearchBox" 
                    Grid.Column="4" 
                    QueryIcon="Find"
                    PlaceholderText="Search"
                    VerticalAlignment="Center"
                    MaxWidth="600"/>
    <PersonPicture x:Name="PersonPic" 
                   Grid.Column="6" 
                   Height="32" Margin="0,0,16,0"/>
</Grid>

Kode ini menunjukkan cara menghitung dan mengatur wilayah interaktif yang sesuai dengan kontrol AutoSuggestBox dan PersonPicture .

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();

        // Assumes "this" is a XAML Window. In projects that don't use 
        // WinUI 3 1.3 or later, use interop APIs to get the AppWindow.
        m_AppWindow = this.AppWindow;
        AppTitleBar.Loaded += AppTitleBar_Loaded;
        AppTitleBar.SizeChanged += AppTitleBar_SizeChanged;
        ExtendsContentIntoTitleBar = true;
        TitleBarTextBlock.Text = AppInfo.Current.DisplayInfo.DisplayName;
    }

    private void AppTitleBar_Loaded(object sender, RoutedEventArgs e)
    {
        if (ExtendsContentIntoTitleBar == true)
        {
            // Set the initial interactive regions.
            SetRegionsForCustomTitleBar();
        }
    }

    private void AppTitleBar_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (ExtendsContentIntoTitleBar == true)
        {
            // Update interactive regions if the size of the window changes.
            SetRegionsForCustomTitleBar();
        }
    }

    private void SetRegionsForCustomTitleBar()
    {
        // Specify the interactive regions of the title bar.

        double scaleAdjustment = AppTitleBar.XamlRoot.RasterizationScale;

        RightPaddingColumn.Width = new GridLength(m_AppWindow.TitleBar.RightInset / scaleAdjustment);
        LeftPaddingColumn.Width = new GridLength(m_AppWindow.TitleBar.LeftInset / scaleAdjustment);

        GeneralTransform transform = TitleBarSearchBox.TransformToVisual(null);
        Rect bounds = transform.TransformBounds(new Rect(0, 0, 
                                                         TitleBarSearchBox.ActualWidth,
                                                         TitleBarSearchBox.ActualHeight));
        Windows.Graphics.RectInt32 SearchBoxRect = GetRect(bounds, scaleAdjustment);
        
        transform = PersonPic.TransformToVisual(null);
        bounds = transform.TransformBounds(new Rect(0, 0,
                                                    PersonPic.ActualWidth,
                                                    PersonPic.ActualHeight));
        Windows.Graphics.RectInt32 PersonPicRect = GetRect(bounds, scaleAdjustment);

        var rectArray = new Windows.Graphics.RectInt32[] { SearchBoxRect, PersonPicRect };

        InputNonClientPointerSource nonClientInputSrc =
            InputNonClientPointerSource.GetForWindowId(this.AppWindow.Id);
        nonClientInputSrc.SetRegionRects(NonClientRegionKind.Passthrough, rectArray);
    }

    private Windows.Graphics.RectInt32 GetRect(Rect bounds, double scale)
    {
        return new Windows.Graphics.RectInt32(
            _X: (int)Math.Round(bounds.X * scale),
            _Y: (int)Math.Round(bounds.Y * scale),
            _Width: (int)Math.Round(bounds.Width * scale),
            _Height: (int)Math.Round(bounds.Height * scale)
        );
    }
}

Peringatan

AppWindow menggunakan piksel fisik untuk kompatibilitas dengan kerangka kerja UI yang tidak menggunakan koordinat logis. Jika Anda menggunakan WPF atau WinUI 3, RightInset, , LeftInset, dan nilai yang digunakan untuk menghitung wilayah perlu disesuaikan jika skala tampilan tidak 100%. Dalam contoh ini, kita mendapatkan scaleAdjustment nilai untuk memperhitungkan pengaturan skala tampilan.

Tombol keterangan sistem

Sistem mencadangkan sudut kiri atas atau kanan atas jendela aplikasi untuk tombol keterangan sistem (minimalkan, maksimalkan/pulihkan, tutup). Sistem mempertahankan kontrol area tombol keterangan untuk menjamin bahwa fungsionalitas minimum disediakan untuk menyeret, meminimalkan, memaksimalkan, dan menutup jendela. Sistem menggambar tombol Tutup di kanan atas untuk bahasa kiri-ke-kanan dan kiri atas untuk bahasa kanan-ke-kiri.

Anda dapat menggambar konten di bawah area kontrol keterangan, seperti latar belakang aplikasi, tetapi Anda tidak boleh menempatkan UI apa pun yang Anda harapkan dapat berinteraksi dengan pengguna. Ini tidak menerima input apa pun karena input untuk kontrol keterangan ditangani oleh sistem.

Baris ini dari contoh sebelumnya menunjukkan kolom padding di XAML yang menentukan bilah judul. Menggunakan kolom padding alih-alih margin memastikan bahwa latar belakang melukis area di bawah tombol kontrol keterangan (untuk tombol transparan). Menggunakan kolom padding kanan dan kiri memastikan bahwa bilah judul Anda bereaksi dengan benar di tata letak kanan-ke-kiri dan kiri-ke-kanan.

<Grid.ColumnDefinitions>
    <ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>
    <ColumnDefinition/>
    <ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>
</Grid.ColumnDefinitions>

Dimensi dan posisi area kontrol keterangan dikomunikasikan oleh kelas AppWindowTitleBar sehingga Anda dapat memperhitungkannya dalam tata letak antarmuka pengguna bilah judul Anda. Lebar wilayah yang dipesan di setiap sisi diberikan oleh properti LeftInset atau RightInset , dan tingginya diberikan oleh properti Tinggi .

Berikut adalah bagaimana lebar kolom padding ditentukan saat wilayah seret dihitung dan diatur.

RightPaddingColumn.Width = 
    new GridLength(m_AppWindow.TitleBar.RightInset / scaleAdjustment);
LeftPaddingColumn.Width = 
    new GridLength(m_AppWindow.TitleBar.LeftInset / scaleAdjustment);

Penting

Lihat informasi penting di bagian Konten interaktif tentang bagaimana penskalakan tampilan memengaruhi nilai-nilai ini.

Dukungan bilah judul tinggi untuk bilah judul kustom

Saat Anda menambahkan konten interaktif seperti kotak pencarian atau gambar orang di bilah judul, kami sarankan Anda meningkatkan tinggi bilah judul Anda untuk memberikan lebih banyak ruang untuk elemen-elemen ini. Bilah judul yang lebih tinggi juga mempermudah manipulasi sentuh. Properti AppWindowTitleBar.PreferredHeightOption memberi Anda opsi untuk meningkatkan tinggi bilah judul Anda dari tinggi standar, yang merupakan default, ke tinggi yang lebih tinggi. Saat Anda memilih Tall mode bilah judul, tombol keterangan yang digambar sistem sebagai overlay di area klien dirender lebih tinggi dengan glyph min/max/close mereka berpusat. Jika Anda belum menentukan wilayah seret, sistem akan menggambar yang memperluas lebar jendela Anda dan tinggi yang ditentukan oleh PreferredHeightOption nilai yang Anda tetapkan.

Contoh ini menunjukkan bagaimana Anda dapat mengatur PreferredHeightOption properti .

// A taller title bar is only supported when drawing a fully custom title bar.
if (ExtendsContentIntoTitleBar == true)
{
    m_AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
}

Perhatian

Properti AppWindowTitleBar.ExtendsContentIntoTitleBar harus true sebelum Anda mengatur PreferredHeightOption properti . Jika Anda mencoba mengatur PreferredHeightOption sementara ExtendsContentIntoTitleBar adalah false, pengecualian akan dilemparkan.

Warna dan transparansi dalam tombol keterangan

Saat memperluas konten aplikasi ke area bilah judul, Anda dapat membuat latar belakang tombol keterangan transparan untuk memungkinkan latar belakang aplikasi ditampilkan. Anda biasanya mengatur latar belakang ke Colors.Transparent untuk transparansi penuh. Untuk transparansi parsial, atur saluran alfa untuk Warna tempat Anda mengatur properti.

Properti bilah judul ini bisa transparan:

Semua properti warna lainnya akan terus mengabaikan saluran alfa. Jika ExtendsContentIntoTitleBar diatur ke false, saluran alfa selalu diabaikan untuk semua AppWindowTitleBar properti warna.

Warna latar belakang tombol tidak diterapkan ke tombol Tutup dan status ditekan . Tombol tutup selalu menggunakan warna yang ditentukan sistem untuk status tersebut.

Tip

Mica adalah bahan menyenangkan yang membantu membedakan jendela yang fokus. Kami merekomendasikannya sebagai latar belakang untuk jendela berumur panjang di Windows 11. Jika Anda telah menerapkan Mica di area klien jendela Anda, Anda dapat memperluasnya ke area bilah judul dan membuat tombol keterangan Anda transparan bagi Mica untuk ditampilkan. Lihat Materi Mica untuk informasi selengkapnya.

Redupkan bilah judul saat jendela tidak aktif

Anda harus membuatnya jelas ketika jendela Anda aktif atau tidak aktif. Minimal, Anda harus mengubah warna teks, ikon, dan tombol di bilah judul Anda.

Untuk aplikasi XAML, tangani peristiwa Window.Activated untuk menentukan status aktivasi jendela, dan perbarui antarmuka pengguna bilah judul Anda sesuai kebutuhan.

public MainWindow()
{
    ...
    Activated += MainWindow_Activated;
}

private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
{
    if (args.WindowActivationState == WindowActivationState.Deactivated)
    {
        TitleBarTextBlock.Foreground =
            (SolidColorBrush)App.Current.Resources["WindowCaptionForegroundDisabled"];
    }
    else
    {
        TitleBarTextBlock.Foreground =
            (SolidColorBrush)App.Current.Resources["WindowCaptionForeground"];
    }
}

Untuk kerangka kerja UI lainnya, tangani peristiwa untuk menentukan status aktivasi jendela, dan perbarui antarmuka pengguna bilah judul Anda sesuai kebutuhan. Cara Anda menentukan status jendela bergantung pada kerangka kerja UI yang Anda gunakan untuk aplikasi Anda.

Mereset bilah judul

Untuk mengatur ulang atau beralih ke bilah judul sistem saat aplikasi berjalan, Anda dapat memanggil AppWindowTitleBar.ResetToDefault.

m_AppWindow.TitleBar.ResetToDefault();

Untuk aplikasi XAML, Anda juga dapat mengatur ulang bilah judul adalah cara berikut:

  • Panggil SetTitleBar untuk beralih ke elemen bilah judul baru saat aplikasi Anda berjalan.
  • Panggil SetTitleBar dengan null sebagai parameter untuk mengatur ulang ke wilayah seret default AppWindowTitleBar .
  • Panggil SetTitleBar dengan null sebagai parameter dan atur ExtendsContentIntoTitleBar ke untuk false kembali ke bilah judul sistem default.

Perlihatkan dan sembunyikan bilah judul

Jika Menambahkan dukungan untuk mode layar penuh atau overlay ringkas ke aplikasi, Anda mungkin perlu membuat perubahan pada bilah judul saat aplikasi beralih di antara mode ini. Jendela XAML tidak menyediakan API apa pun untuk mendukung mode layar penuh; Anda dapat menggunakan API AppWindow untuk ini.

Saat aplikasi Anda berjalan dalam mode layar penuh, sistem menyembunyikan bilah judul dan tombol kontrol keterangan. Anda dapat menangani peristiwa AppWindow.Changed dan memeriksa properti event args DidPresenterChange untuk menentukan apakah Anda harus menampilkan, menyembunyikan, atau mengubah bilah judul sebagai respons terhadap presentasi jendela baru.

Contoh ini menunjukkan cara menangani Changed peristiwa untuk menampilkan dan menyembunyikan AppTitleBar elemen dari contoh sebelumnya. Jika jendela dimasukkan ke dalam mode overlay ringkas, bilah judul diatur ulang ke bilah judul sistem default (atau Anda dapat menyediakan bilah judul kustom yang dioptimalkan untuk overlay ringkas).

public MainWindow()
{
    this.InitializeComponent();

    m_AppWindow = this.AppWindow;
    m_AppWindow.Changed += AppWindow_Changed;
}

private void AppWindow_Changed(AppWindow sender, AppWindowChangedEventArgs args)
{
    if (args.DidPresenterChange)
    {
        switch (sender.Presenter.Kind)
        {
            case AppWindowPresenterKind.CompactOverlay:
                // Compact overlay - hide custom title bar
                // and use the default system title bar instead.
                AppTitleBar.Visibility = Visibility.Collapsed;
                sender.TitleBar.ResetToDefault();
                break;

            case AppWindowPresenterKind.FullScreen:
                // Full screen - hide the custom title bar
                // and the default system title bar.
                AppTitleBar.Visibility = Visibility.Collapsed;
                sender.TitleBar.ExtendsContentIntoTitleBar = true;
                break;

            case AppWindowPresenterKind.Overlapped:
                // Normal - hide the system title bar
                // and use the custom title bar instead.
                AppTitleBar.Visibility = Visibility.Visible;
                sender.TitleBar.ExtendsContentIntoTitleBar = true;
                break;

            default:
                // Use the default system title bar.
                sender.TitleBar.ResetToDefault();
                break;
        }
    }
}

Catatan

Mode layar penuh dan overlay ringkas hanya dapat dimasukkan jika didukung oleh aplikasi Anda. Lihat Mengelola jendela aplikasi, FullScreenPresenter, dan CompactOverlayPresenter untuk informasi selengkapnya.

Lakukan dan jangan lakukan

  • Buatlah jelas ketika jendela Anda aktif atau tidak aktif. Minimal, ubah warna teks, ikon, dan tombol di bilah judul Anda.
  • Tentukan wilayah seret di sepanjang tepi atas kanvas aplikasi. Mencocokkan penempatan bilah judul sistem memudahkan pengguna untuk menemukan.
  • Tentukan wilayah seret yang cocok dengan bilah judul visual (jika ada) di kanvas aplikasi.

Contoh kustomisasi lengkap

Contoh ini menunjukkan semua kode yang dijelaskan di bagian Kustomisasi penuh.

<Window
    x:Class="WinUI3_CustomTitleBar.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid x:Name="AppTitleBar"
      Height="48">
            <Grid.ColumnDefinitions>
                <ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>
                <ColumnDefinition x:Name="IconColumn" Width="Auto"/>
                <ColumnDefinition x:Name="TitleColumn" Width="Auto"/>
                <ColumnDefinition x:Name="LeftDragColumn" Width="*"/>
                <ColumnDefinition x:Name="SearchColumn" Width="4*" MinWidth="220"/>
                <ColumnDefinition x:Name="RightDragColumn" Width="*" MinWidth="48"/>
                <ColumnDefinition x:Name="AccountColumn" Width="Auto"/>
                <ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>
            </Grid.ColumnDefinitions>
            <Image x:Name="TitleBarIcon" 
           Source="ms-appx:///Assets/StoreLogo.png"
           Grid.Column="1"
           Width="16" Height="16"
           Margin="8,0,4,0"/>
            <TextBlock x:Name="TitleBarTextBlock"
                       Text="App title" 
                       Style="{StaticResource CaptionTextBlockStyle}"
                       Grid.Column="2"
                       VerticalAlignment="Center">
            </TextBlock>
            <AutoSuggestBox x:Name="TitleBarSearchBox" 
                            Grid.Column="4" 
                            QueryIcon="Find"
                            PlaceholderText="Search"
                            VerticalAlignment="Center"
                            MaxWidth="600"/>
            <PersonPicture x:Name="PersonPic" 
                           Grid.Column="6" 
                           Height="32" Margin="0,0,16,0"/>
        </Grid>

        <NavigationView Grid.Row="1"
                        IsBackButtonVisible="Collapsed"
                        IsSettingsVisible="False">
            <StackPanel>
                <TextBlock Text="Content" 
                           Style="{ThemeResource TitleTextBlockStyle}"
                           Margin="32,0,0,0"/>
                <StackPanel Grid.Row="1" VerticalAlignment="Center">
                    <Button Margin="4" x:Name="CompactoverlaytBtn"
                            Content="Enter CompactOverlay"
                            Click="SwitchPresenter"/>
                    <Button Margin="4" x:Name="FullscreenBtn" 
                            Content="Enter FullScreen"
                            Click="SwitchPresenter"/>
                    <Button Margin="4" x:Name="OverlappedBtn"
                            Content="Revert to default (Overlapped)"
                            Click="SwitchPresenter"/>
                </StackPanel>
            </StackPanel>
        </NavigationView>
    </Grid>
</Window>
using Microsoft.UI.Input;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using System;
using Windows.ApplicationModel;
using Rect = Windows.Foundation.Rect;

public sealed partial class MainWindow : Window
{
    private AppWindow m_AppWindow;

    public MainWindow()
    {
        this.InitializeComponent();

        // Assumes "this" is a XAML Window. In projects that don't use 
        // WinUI 3 1.3 or later, use interop APIs to get the AppWindow.
        m_AppWindow = this.AppWindow;
        m_AppWindow.Changed += AppWindow_Changed;
        Activated += MainWindow_Activated;
        AppTitleBar.SizeChanged += AppTitleBar_SizeChanged;
        AppTitleBar.Loaded += AppTitleBar_Loaded;

        ExtendsContentIntoTitleBar = true;
        if (ExtendsContentIntoTitleBar == true)
        {
            m_AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
        }
        TitleBarTextBlock.Text = AppInfo.Current.DisplayInfo.DisplayName;
    }

    private void AppTitleBar_Loaded(object sender, RoutedEventArgs e)
        {
            if (ExtendsContentIntoTitleBar == true)
            {
                // Set the initial interactive regions.
                SetRegionsForCustomTitleBar();
            }
        }

    private void AppTitleBar_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (ExtendsContentIntoTitleBar == true)
            {
                // Update interactive regions if the size of the window changes.
                SetRegionsForCustomTitleBar();
            }
        }

    private void SetRegionsForCustomTitleBar()
    {
        // Specify the interactive regions of the title bar.

        double scaleAdjustment = AppTitleBar.XamlRoot.RasterizationScale;

        RightPaddingColumn.Width = new GridLength(m_AppWindow.TitleBar.RightInset / scaleAdjustment);
        LeftPaddingColumn.Width = new GridLength(m_AppWindow.TitleBar.LeftInset / scaleAdjustment);

        // Get the rectangle around the AutoSuggestBox control.
        GeneralTransform transform = TitleBarSearchBox.TransformToVisual(null);
        Rect bounds = transform.TransformBounds(new Rect(0, 0,
                                                         TitleBarSearchBox.ActualWidth,
                                                         TitleBarSearchBox.ActualHeight));
        Windows.Graphics.RectInt32 SearchBoxRect = GetRect(bounds, scaleAdjustment);

        // Get the rectangle around the PersonPicture control.
        transform = PersonPic.TransformToVisual(null);
        bounds = transform.TransformBounds(new Rect(0, 0,
                                                    PersonPic.ActualWidth,
                                                    PersonPic.ActualHeight));
        Windows.Graphics.RectInt32 PersonPicRect = GetRect(bounds, scaleAdjustment);

        var rectArray = new Windows.Graphics.RectInt32[] { SearchBoxRect, PersonPicRect };

        InputNonClientPointerSource nonClientInputSrc =
            InputNonClientPointerSource.GetForWindowId(this.AppWindow.Id);
        nonClientInputSrc.SetRegionRects(NonClientRegionKind.Passthrough, rectArray);
    }

    private Windows.Graphics.RectInt32 GetRect(Rect bounds, double scale)
    {
        return new Windows.Graphics.RectInt32(
            _X: (int)Math.Round(bounds.X * scale),
            _Y: (int)Math.Round(bounds.Y * scale),
            _Width: (int)Math.Round(bounds.Width * scale),
            _Height: (int)Math.Round(bounds.Height * scale)
        );
    }

    private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
    {
        if (args.WindowActivationState == WindowActivationState.Deactivated)
        {
            TitleBarTextBlock.Foreground =
                (SolidColorBrush)App.Current.Resources["WindowCaptionForegroundDisabled"];
        }
        else
        {
            TitleBarTextBlock.Foreground =
                (SolidColorBrush)App.Current.Resources["WindowCaptionForeground"];
        }
    }

    private void AppWindow_Changed(AppWindow sender, AppWindowChangedEventArgs args)
    {
        if (args.DidPresenterChange)
        {
            switch (sender.Presenter.Kind)
            {
                case AppWindowPresenterKind.CompactOverlay:
                    // Compact overlay - hide custom title bar
                    // and use the default system title bar instead.
                    AppTitleBar.Visibility = Visibility.Collapsed;
                    sender.TitleBar.ResetToDefault();
                    break;

                case AppWindowPresenterKind.FullScreen:
                    // Full screen - hide the custom title bar
                    // and the default system title bar.
                    AppTitleBar.Visibility = Visibility.Collapsed;
                    sender.TitleBar.ExtendsContentIntoTitleBar = true;
                    break;

                case AppWindowPresenterKind.Overlapped:
                    // Normal - hide the system title bar
                    // and use the custom title bar instead.
                    AppTitleBar.Visibility = Visibility.Visible;
                    sender.TitleBar.ExtendsContentIntoTitleBar = true;
                    break;

                default:
                    // Use the default system title bar.
                    sender.TitleBar.ResetToDefault();
                    break;
            }
        }
    }

    private void SwitchPresenter(object sender, RoutedEventArgs e)
    {
        if (AppWindow != null)
        {
            AppWindowPresenterKind newPresenterKind;
            switch ((sender as Button).Name)
            {
                case "CompactoverlaytBtn":
                    newPresenterKind = AppWindowPresenterKind.CompactOverlay;
                    break;

                case "FullscreenBtn":
                    newPresenterKind = AppWindowPresenterKind.FullScreen;
                    break;

                case "OverlappedBtn":
                    newPresenterKind = AppWindowPresenterKind.Overlapped;
                    break;

                default:
                    newPresenterKind = AppWindowPresenterKind.Default;
                    break;
            }

            // If the same presenter button was pressed as the
            // mode we're in, toggle the window back to Default.
            if (newPresenterKind == AppWindow.Presenter.Kind)
            {
                AppWindow.SetPresenter(AppWindowPresenterKind.Default);
            }
            else
            {
                // Else request a presenter of the selected kind
                // to be created and applied to the window.
                AppWindow.SetPresenter(newPresenterKind);
            }
        }
    }
}