Anpassen der Titelleiste

Windows bietet eine Standardtitelleiste für jedes Fenster und ermöglicht es Ihnen, sie an die Persönlichkeit Ihrer App anzupassen. Die Standardtitelleiste enthält einige Standardkomponenten und Kernfunktionen wie das Ziehen und Ändern der Größe des Fensters.

A Windows app showing the title bar

Im Artikel zum Entwurf der Titelleiste finden Sie Anleitungen zum Anpassen der Titelleiste Ihrer App, des zulässigen Inhalts der Titelleiste und der empfohlenen Benutzeroberflächenmuster.

Wichtig

In diesem Artikel wird gezeigt, wie Sie die Titelleiste für Apps anpassen, die das Windows App SDK verwenden, entweder mit oder ohne WinUI 3. Apps, die UWP und WinUI 2 verwenden, finden Sie unter Titelleistenanpassung für UWP.

Titelleistenkomponenten

In dieser Liste werden die Komponenten der Standardtitelleiste beschrieben.

  • Titelleistenrechteck
  • Titeltext
  • Systemsymbol
  • Systemmenü: Zugriff durch Klicken auf das App-Symbol oder Klicken mit der rechten Maustaste auf die Titelleiste
  • Beschriftungssteuerelemente
    • Schaltfläche „Minimieren“
    • Schaltfläche „Maximieren/Wiederherstellen“
    • Schaltfläche „Schließen“

Windowing

Die Fensterfunktion im Windows App SDK erfolgt über die Microsoft.UI.Windowing.AppWindow-Klasse, die auf dem Win32 HWND-Modell basiert. Es gibt eine 1:1-Zuordnung zwischen einem AppWindow und einem HWND der obersten Ebene in Ihrer App. AppWindow und die zugehörigen Klassen bieten APIs, mit denen Sie viele Aspekte der Fenster der obersten Ebene Ihrer App verwalten können, einschließlich der Anpassung der Titelleiste. Sie können die von Windows bereitgestellte Standardtitelleiste so ändern, dass sie mit der restlichen Benutzeroberfläche kombiniert wird, oder Ihren App-Zeichenbereich in den Titelleistenbereich erweitern und Ihren eigenen Titelleisteninhalt bereitstellen.

Die Fensterfunktion in WinUI 3 erfolgt über die Microsoft.UI.Xaml.Window-Klasse, die auch auf dem Win32 HWND-Modell basiert. Für XAML-Apps, die WinUI 3 verwenden, bieten XAML-Fenster-APIs eine einfachere Möglichkeit zum Anpassen der Titelleiste, während Sie bei Bedarf weiterhin auf die AppWindow-APIs zugreifen können.

Arbeiten mit AppWindow

Sie können AppWindow-APIs mit jedem Benutzeroberflächenframework verwenden, das vom Windows App SDK unterstützt wird – Win32, WPF, WinForms oder WinUI 3 – und Sie können sie inkrementell übernehmen, indem Sie nur die benötigten APIs verwenden.

Wenn Sie WinUI 3 XAML als Benutzeroberflächenframework Ihrer App verwenden, stehen Ihnen sowohl die Windows- als auch die AppWindow-APIs zur Verfügung. Ab Windows App SDK 1.4 verwenden das XAML-Fenster und AppWindow dasselbe AppWindowTitleBar-Objekt für die Anpassung der Titelleiste. Verwenden Sie die Window.AppWindow-Eigenschaft, um ein AppWindow-Objekt aus einem vorhandenen XAML-Fenster abzurufen. Mit diesem AppWindow-Objekt haben Sie Zugriff auf die Anpassungs-APIs der Titelleiste. Um auf zusätzliche Features der Titelleiste zuzugreifen, können Sie die AppWindow-APIs aus Ihrem XAML-Fenster wie folgt verwenden: AppWindow.TitleBar.ForegroundColor = Colors.White;

Wenn Sie WinUI 3 1.3 oder höher nicht verwenden, verwenden Sie Interop-APIs, um AppWindow abzurufen und die AppWindow-APIs zum Anpassen der Titelleiste zu verwenden. Weitere Informationen zu den Interop-APIs finden Sie unter Verwalten von App-Fenstern – UI-Framework und HWND-Interoperabilität sowie im Beispiel zum Fensterkatalog.

Anpassen der Titelleiste

Es gibt zwei Anpassungsebenen, die Sie auf die Titelleiste anwenden können: Wenden Sie geringfügige Änderungen auf die Standardtitelleiste an, oder erweitern Sie Ihren App-Zeichenbereich auf den Titelleistenbereich und stellen vollständig benutzerdefinierte Inhalte bereit.

Einfach

Für einfache Anpassungen, z. B. das Ändern der Farbe der Titelleiste, können Sie Eigenschaften für das AppWindowTitleBar-Objekt festlegen, um die Farben anzugeben, die Sie für Titelleistenelemente verwenden möchten. In diesem Fall behält das System die Verantwortung für alle anderen Aspekte der Titelleiste, z. B. das Zeichnen des App-Titels und das Definieren von Ziehbereichen.

Vollständig

Ihre andere Option besteht darin, die Standardtitelleiste des Systems auszublenden und durch Ihren eigenen benutzerdefinierten Inhalt zu ersetzen. Sie können beispielsweise Text, ein Suchfeld oder benutzerdefinierte Menüs im Titelleistenbereich platzieren. Sie müssen diese Option auch verwenden, um einen Material-Hintergrund wie Mica in den Titelleistenbereich zu erweitern.

Wenn Sie sich für die vollständige Anpassung entscheiden, sind Sie für das Einfügen von Inhalten im Titelleistenbereich verantwortlich, und Sie können Ihre eigenen Ziehbereiche definieren. Die Beschriftungssteuerelemente (Systemschaltflächen „Schließen“, „Minimieren“ und „Maximieren“) sind weiterhin verfügbar und werden vom System verarbeitet, Elemente wie der App-Titel jedoch nicht. Sie müssen diese Elemente selbst erstellen, wenn sie von Ihrer App benötigt werden.

Einfache Anpassung

Wenn Sie nur den Titel, die Farben oder das Symbol der Titelleiste anpassen möchten, können Sie Eigenschaften für das Titelleistenobjekt für Ihr App-Fenster festlegen.

Titel

Standardmäßig zeigt die Titelleiste den App-Typ als Fenstertitel an (z. B. „WinUI Desktop“). Sie sollten den Fenstertitel aktualisieren, um einen aussagekräftigen Anzeigenamen für Ihre App anzuzeigen.

Eine XAML-App hat einen Anzeigenamen, der in der Package.appxmanifest-Datei festgelegt ist. Sie können diesen Wert abrufen und verwenden, um die Title-Eigenschaft wie folgt festzulegen.

Title = AppInfo.Current.DisplayInfo.DisplayName;

Um den Fenstertitel zu ändern, legen Sie die Window.Title-Eigenschaft auf einen einzeiligen Textwert fest, wie hier gezeigt.

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

Um den Fenstertitel mithilfe von AppWindow-APIs zu ändern, legen Sie die AppWindow.Title-Eigenschaft auf einen einzeiligen Textwert fest, wie hier gezeigt. In diesem Beispiel wird gezeigt, wie Sie Interop-APIs verwenden, um das AppWindow abzurufen, das benötigt wird, wenn Ihre App nicht WinUI 3 1.3 oder höher verwendet.

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

Farben

Um die Standardfarben der Titelleiste anzupassen oder das Standardfenstersymbol zu ändern, müssen Sie die AppWindow-APIs verwenden oder ihre Titelleiste vollständig anpassen.

In diesem Beispiel wird gezeigt, wie Sie eine Instanz von AppWindowTitleBar abrufen und die Farbeigenschaften festlegen.

Wichtig

Farbanpassung wird ignoriert, wenn die App unter Windows 10 ausgeführt wird.

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

Beim Festlegen von Titelleistenfarben sind einige Punkte zu beachten:

  • Die Hintergrundfarbe der Schaltfläche wird nicht auf die Zustände darauf zeigen und gedrückt der Schließen-Schaltfläche angewendet. Die Schaltfläche zum Schließen verwendet für diese Zustände immer die systemdefinierte Farbe.
  • Wenn Sie eine Farbeigenschaft auf null festlegen, wird sie auf die Standardsystemfarbe zurückgesetzt.
  • Sie können keine transparenten Farben festlegen. Der Alphakanal der Farbe wird ignoriert.

Windows bietet einem Benutzer die Möglichkeit, die ausgewählte Akzentfarbe auf die Titelleiste anzuwenden. Wenn Sie eine Titelleistenfarbe festlegen, empfiehlt es sich, alle Farben explizit festzulegen. Dadurch wird sichergestellt, dass aufgrund benutzerdefinierter Farbeinstellungen keine unbeabsichtigten Farbkombinationen auftreten.

Symbol und Systemmenü

Sie können das Systemsymbol ausblenden oder durch ein benutzerdefiniertes Symbol ersetzen. Das Systemsymbol zeigt das Systemmenü an, wenn einmal mit der rechten Maustaste geklickt oder getippt wurde. Das Fenster wird geschlossen, wenn doppelt geklickt/getippt wird.

Um das Systemsymbol und die zugehörigen Verhaltensweisen ein- oder auszublenden, legen Sie die IconShowOptions-Eigenschaft der Titelleiste fest.

m_TitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu;

Um ein benutzerdefiniertes Fenstersymbol zu verwenden, rufen Sie eine der AppWindow.SetIcon-Methoden auf, um das neue Symbol festzulegen.

  • SetIcon(String)

    Die SetIcon(String)-Methode funktioniert derzeit nur mit ICO-Dateien. Die Zeichenfolge, die Sie an diese Methode übergeben, ist der vollqualifizierte Pfad zur ICO-Datei.

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

    Wenn Sie bereits über ein Handle für ein Symbol (HICON) aus einer der Symbolfunktionen wie CreateIcon verfügen, können Sie die GetIconIdFromIcon-Interop-API verwenden, um eine IconId abzurufen. Anschließend können Sie IconId an die SetIcon(IconId)-Methode übergeben, um das Fenstersymbol festzulegen.

    m_AppWindow.SetIcon(iconId));
    

Vollständige Anpassung

Wenn Sie sich für die vollständige Anpassung der Titelleiste entscheiden, wird der Clientbereich Ihrer App erweitert, um das gesamte Fenster einschließlich des Titelleistenbereichs abzudecken. Sie sind für das Zeichnen und die Eingabeverarbeitung für das gesamte Fenster mit Ausnahme der Titelleistenschaltflächen verantwortlich, die weiterhin vom Fenster bereitgestellt werden.

Um die Systemtitelleiste auszublenden und den Inhalt in den Titelleistenbereich zu erweitern, legen Sie die Eigenschaft fest, die App-Inhalte in den Titelleistenbereich auf true erweitert. In einer XAML-App kann diese Eigenschaft in der OnLaunched-Methode Ihrer App (App.xaml.cs) oder auf der ersten Seite Ihrer App festgelegt werden.

Tipp

Im Abschnitt Beispiel für vollständige Anpassung finden Sie den gesamten Code.

In diesem Beispiel wird gezeigt, wie die Window.ExtendsContentIntoTitleBar-Eigenschaft auf true festgelegt wird.

public MainWindow()
{
    this.InitializeComponent();

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

Achtung

ExtendsContentIntoTitleBar wird in XAML IntelliSense für Window angezeigt, aber das Festlegen in XAML verursacht einen Fehler. Legen Sie diese Eigenschaft stattdessen im Code fest.

In diesem Beispiel wird gezeigt, wie Sie die AppWindowTitleBar abrufen und die Eigenschaft AppWindow.ExtendsContentIntoTitleBar auf true festlegen. In diesem Beispiel wird gezeigt, wie Sie Interop-APIs verwenden, um das AppWindow abzurufen, das benötigt wird, wenn Ihre App nicht WinUI 3 1.3 oder höher verwendet.

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

Inhalt der Titelleiste und Standardziehbereich

Wenn Ihre App in den Titelleistenbereich erweitert wird, sind Sie für das Definieren und Verwalten der Benutzeroberfläche für die Titelleiste verantwortlich. Dies umfasst in der Regel mindestens die Angabe des Titeltexts und des Ziehbereichs. Der Ziehbereich der Titelleiste definiert, wo der Benutzer klicken und ziehen kann, um das Fenster zu verschieben. Außerdem kann der Benutzer mit der rechten Maustaste darauf klicken, um das Systemmenü anzuzeigen.

Weitere Informationen zu akzeptablen Titelleisteninhalten und empfohlenen Benutzeroberflächenmustern finden Sie unter Titelleistendesign.

Dieses Beispiel zeigt den XAML-Code für eine benutzerdefinierte Titelleistenbenutzeroberfläche ohne interaktiven Inhalt.

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

Wichtig

Die LeftPaddingColumn und RightPaddingColumn werden verwendet, um Platz für die Beschriftungsschaltflächen zu reservieren. Die Width-Werte für diese Spalten werden im Code festgelegt, der später gezeigt wird. Den Code und die Erklärung finden Sie im Abschnitt Beschriftungsschaltflächen des Systems.

Eine XAML-App weist einen Anzeigenamen auf, der in der Datei „Package.appxmanifest“ festgelegt ist. Sie können diesen Wert abrufen und in Ihrer benutzerdefinierten Titelleiste wie folgt verwenden.

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

Wenn Sie den Inhalt in den Titelleistenbereich erweitern, wird die Systemtitelleiste ausgeblendet, und eine standardmäßige AppWindowTitleBar wird erstellt, die Beschriftungsschaltflächen und einen Ziehbereich über die Breite des Bildschirms bereitstellt, identisch mit der Systemtitelleiste. Wenn Sie keine interaktiven Inhalte in der Titelleiste platzieren, können Sie diesen standardmäßigen Ziehbereich unverändert lassen. Wenn Sie interaktive Inhalte in der Titelleiste platzieren, müssen Sie die Regionen angeben, die interaktiv sind. Sie werden im nächsten Abschnitt behandelt.

Achtung

Wenn Sie benutzerdefinierte Ziehbereiche definieren, müssen sie sich nicht am oberen Rand des Fensters im Standardbereich der Titelleiste befinden. Sie können einen beliebigen Teil der Benutzeroberfläche als Ziehbereich definieren. Das Platzieren von Ziehbereichen an unterschiedlichen Stellen macht es Ihren Benutzer*innen jedoch möglicherweise schwer, sie zu entdecken.

Interaktiver Inhalt

Sie können interaktive Steuerelemente wie Schaltflächen, Menüs oder ein Suchfeld im oberen Teil der App platzieren, sodass sie in der Titelleiste angezeigt werden. Sie müssen jedoch angeben, welche Regionen interaktiv sind, um sicherzustellen, dass Ihre interaktiven Elemente Benutzereingaben erhalten und Benutzer*innen gleichzeitig das Verschieben des Fensters ermöglichen.

A Windows app with a search box in the title bar

Wenn Sie interaktive Inhalte im Titelleistenbereich hinzufügen, müssen Sie die InputNonClientPointerSource-Klasse verwenden, um Bereiche anzugeben, in denen die Eingaben an das interaktive Steuerelement weitergeleitet und nicht von der Titelleiste verarbeitet werden. Rufen Sie zum Festlegen der interaktiven Bereiche die InputNonClientPointerSource.SetRegionRects-Methode auf. Diese Methode verwendet einen Wert, der die Art der Region angibt, die festgelegt wird (in diesem Fall Passthrough), und ein Array von Rechtecken, die jeweils einen Passthrough-Bereich definieren. Wenn sich die Größe der Titelleiste ändert, müssen Sie die interaktiven Bereiche neu berechnen, damit sie der neuen Größe entsprechen, und SetRegionRects mit den neuen Werten aufrufen.

Dieses Beispiel zeigt eine benutzerdefinierte Benutzeroberfläche auf der Titelleiste mit einem Suchfeld und einem PersonPicture-Kontosteuerelement. Es veranschaulicht, wie die interaktiven Rechtecke für diese Steuerelemente berechnet und festgelegt werden, sodass die Eingabe an sie übergeben wird.

Bei diesem Code sind einige wichtige Punkte zu beachten:

  • Legen Sie die AppTitleBar-Rasterhöhe auf 48 fest, um den Leitfaden zum Entwurf der Titelleiste für interaktive Inhalte zu befolgen.
  • Legen Sie PreferredHeightOption auf Tall fest, sodass die Beschriftungsschaltflächen die gleiche Höhe wie die Titelleiste aufweisen.
  • Um die Größenänderung von Steuerelementen und das Berechnen von Bereichen zu vereinfachen, verwenden Sie ein Grid mit mehreren benannten Spalten für das Layout.
  • Verwenden Sie die Stern-Größe (*) mit MinWidth für die Spalte, die die AutoSuggestBox enthält, sodass sie automatisch mit dem Fenster geändert wird.
  • Legen Sie die MinWidth-Einstellung für die RightDragColumn fest, um einen kleinen Bereich zu reservieren, der immer gezogen werden kann, auch wenn die Größe des Fensters geändert wird.
  • Legen Sie ExtendsContentIntoTitleBar im MainWindow-Konstruktor auf true fest. Wenn Sie sie im Code festlegen, der später aufgerufen wird, wird die Standardtitelleiste des Systems möglicherweise zuerst angezeigt und dann ausgeblendet.
  • Berechnen interaktive Bereiche mit dem ersten Aufruf, nachdem das AppTitleBar-Element geladen wurde. Andernfalls gibt es keine Garantie dafür, dass die für die Berechnung verwendeten Elemente ihre richtigen Werte aufweisen.
  • Aktualisieren Sie die interaktiven Rechteckberechnungen erst, nachdem sich die Größe des AppTitleBar-Elements geändert hat (AppTitleBar_SizeChanged). Wenn Sie vom Fensterereignis Changed abhängig sind, gibt es Situationen (z. B. Fenster maximieren/minimieren), in denen das Ereignis auftritt, bevor die Größe von AppTitleBar geändert wird, und die Berechnungen verwenden falsche Werte.
  • Legen Sie Ihre benutzerdefinierten Ziehbereiche/interaktiven Bereiche erst fest, nachdem Sie ExtendsContentIntoTitleBar überprüft haben, um zu bestätigen, ob eine benutzerdefinierte Titelleiste verwendet wird.
<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>

Dieser Code zeigt, wie die interaktiven Bereiche berechnet und festgelegt werden, die den Steuerelementen AutoSuggestBox und PersonPicture entsprechen.

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

Warnung

AppWindow verwendet physische Pixel für die Kompatibilität mit Benutzeroberflächenframeworks, die keine logischen Koordinaten verwenden. Wenn Sie WPF oder WinUI 3 verwenden, müssen RightInset, LeftInset und die zum Berechnen von Regionen verwendeten Werte angepasst werden, wenn die Anzeigeskala nicht 100 % beträgt. In diesem Beispiel wird ein scaleAdjustment-Wert abgerufen, der die Einstellung für die Anzeigeskala berücksichtigt.

Beschriftungsschaltflächen des Systems

Das System reserviert die obere linke oder obere rechte Ecke des App-Fensters für Beschriftungsschaltflächen des Systems (Minimieren, Maximieren/Wiederherstellen, Schließen). Das System behält die Kontrolle über den Bereich der Beschriftungsschaltfläche, um sicherzustellen, dass minimale Funktionen zum Ziehen, Minimieren, Maximieren und Schließen des Fensters bereitgestellt werden. Das System zeichnet die Schaltfläche „Schließen“ in der oberen rechten für Sprachen von links nach rechts und die obere linke für Sprachen von rechts nach links.

Sie können Inhalte unter dem Beschriftungssteuerbereich zeichnen, z. B. den App-Hintergrund, aber Sie sollten keine Benutzeroberfläche platzieren, mit der Benutzer*innen möglicherweise interagieren werden. Es werden keine Eingaben empfangen, da Eingaben für die Beschriftungssteuerelemente vom System verarbeitet werden.

Diese Zeilen aus dem vorherigen Beispiel zeigen die Auffüllungsspalten im XAML-Code, der die Titelleiste definiert. Die Verwendung von Abstandsspalten anstelle von Rändern stellt sicher, dass der Hintergrund den Bereich unter den Beschriftungssteuerelementen (für transparente Schaltflächen) zeichnet. Durch die Verwendung von Auffüllungsspalten rechts und links wird sichergestellt, dass sich die Titelleiste in den Layouts von rechts nach links und von links nach rechts ordnungsgemäß verhält.

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

Die Dimensionen und die Position des Bereichs der Beschriftungssteuerelemente werden von der AppWindowTitleBar-Klasse mitgeteilt, sodass Sie sie im Layout Ihrer Titelleisten-Benutzeroberfläche berücksichtigen können. Die Breite des reservierten Bereichs auf jeder Seite wird durch die Eigenschaften LeftInset oder RightInset angegeben, und seine Höhe wird durch die Height-Eigenschaft angegeben.

Hier erfahren Sie, wie die Breite der Auffüllspalten angegeben wird, wenn die Ziehbereiche berechnet und festgelegt werden.

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

Wichtig

Im Abschnitt Interaktiver Inhalt finden Sie wichtige Informationen dazu, wie sich die Anzeigeskalierung auf diese Werte auswirkt.

Unterstützung für hohe Titelleisten bei benutzerdefinierte Titelleisten

Wenn Sie interaktive Inhalte wie ein Suchfeld oder ein Personenbild in der Titelleiste hinzufügen, wird empfohlen, die Höhe der Titelleiste zu erhöhen, um mehr Platz für diese Elemente zu schaffen. Eine größere Titelleiste erleichtert auch die Touchmanipulation. Mit der AppWindowTitleBar.PreferredHeightOption-Eigenschaft haben Sie die Möglichkeit, die Höhe der Titelleiste von der Standardhöhe, bei der es sich um die Standardeinstellung handelt, auf eine höhere Höhe zu erhöhen. Wenn Sie den Titelleistenmodus Tall auswählen, werden die Beschriftungsschaltflächen, die das System als Überlagerung im Clientbereich zeichnet, höher gerendert, wobei ihre Min/Max/Schließen-Glyphen zentriert sind. Wenn Sie keinen Ziehbereich angegeben haben, zeichnet das System einen Bereich, der die Breite des Fensters und die Höhe erweitert, die durch den von Ihnen festgelegten PreferredHeightOption-Wert bestimmt wird.

In diesem Beispiel wird gezeigt, wie Sie die PreferredHeightOption-Eigenschaft festlegen können.

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

Achtung

Die AppWindowTitleBar.ExtendsContentIntoTitleBar-Eigenschaft muss true sein, bevor Sie die PreferredHeightOption-Eigenschaft festlegen. Wenn Sie versuchen, PreferredHeightOption festzulegen, während ExtendsContentIntoTitleBarfalse ist, wird eine Ausnahme ausgelöst.

Farbe und Transparenz in Beschriftungsschaltflächen

Wenn Sie Ihre App-Inhalte in den Titelleistenbereich erweitern, können Sie den Hintergrund der Beschriftungsschaltflächen transparent machen, damit der App-Hintergrund angezeigt wird. Für vollständige Transparenz legen Sie den Hintergrund in der Regel auf Colors.Transparent fest. Legen Sie für teilweise Transparenz den Alphakanal für die Farbe fest, auf die Sie die Eigenschaft festlegen.

Diese Titelleisteneigenschaften können transparent sein:

Alle anderen Farbeigenschaften ignorieren den Alphakanal weiterhin. Wenn ExtendsContentIntoTitleBar auf false festgelegt ist, wird der Alphakanal für alle AppWindowTitleBar-Farbeigenschaften immer ignoriert.

Die Hintergrundfarbe der Schaltfläche wird nicht auf die Zustände darauf zeigen und gedrückt der Schließen-Schaltfläche angewendet. Die Schaltfläche zum Schließen verwendet für diese Zustände immer die systemdefinierte Farbe.

Tipp

Mica ist ein reizvolles Material, das hilft, das Fenster zu unterscheiden, das im Fokus steht. Es wird als Hintergrund für langlebige Fenster in Windows 11 empfohlen. Wenn Sie Mica im Clientbereich Ihres Fensters angewendet haben, können Sie es in den Titelleistenbereich erweitern und Ihre Beschriftungsschaltflächen für die Mica transparent machen, damit sie durchscheinen. Weitere Informationen finden Sie unter Mica-Material.

Dimmen der Titelleiste, wenn das Fenster inaktiv ist

Sie sollten deutlich machen, ob Ihr Fenster aktiv oder inaktiv ist. Sie sollten mindestens die Farbe des Texts, der Symbole und der Schaltflächen in der Titelleiste ändern.

Behandeln Sie für XAML-Apps das Window.Activated-Ereignis, um den Aktivierungsstatus des Fensters zu bestimmen, und aktualisieren Sie die Benutzeroberfläche der Titelleiste nach Bedarf.

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

Behandeln Sie für andere Benutzeroberflächenframeworks ein Ereignis, um den Aktivierungsstatus des Fensters zu bestimmen, und aktualisieren Sie die Benutzeroberfläche der Titelleiste nach Bedarf. Wie Sie den Status des Fensters bestimmen, hängt vom Benutzeroberflächenframework ab, das Sie für Ihre App verwenden.

Zurücksetzen der Titelleiste

Um die Systemtitelleiste zurückzusetzen oder zu wechseln, während Ihre App ausgeführt wird, können Sie AppWindowTitleBar.ResetToDefault aufrufen.

m_AppWindow.TitleBar.ResetToDefault();

Für XAML-Apps können Sie die Titelleiste auch wie folgt zurücksetzen:

  • Rufen Sie SetTitleBar auf, um zu einem neuen Titelleistenelement zu wechseln, während die App ausgeführt wird.
  • Rufen Sie SetTitleBar mit null als Parameter auf, um sie auf die standardmäßigen AppWindowTitleBar-Ziehbereiche zurückzusetzen.
  • Rufen Sie SetTitleBar mit null als Parameter auf, und legen Sie ExtendsContentIntoTitleBar auf false fest, um zur Standardtitelleiste des Systems zurückzukehren.

Anzeigen und Ausblenden der Titelleiste

Wenn Sie Ihrer App Unterstützung für die Modi Vollbild oder kompakte Überlagerung hinzufügen, müssen Sie möglicherweise Änderungen an der Titelleiste vornehmen, wenn Ihre App zwischen diesen Modi wechselt. Das XAML-Fenster stellt keine APIs bereit, um den Vollbildmodus zu unterstützen. Hierfür können Sie AppWindow-APIs verwenden.

Wenn Ihre App im Vollbildmodus ausgeführt wird, blendet das System die Titelleiste und Beschriftungssteuerelemente aus. Sie können das AppWindow.Changed-Ereignis behandeln und die DidPresenterChange-Eigenschaft überprüfen, um zu bestimmen, ob Sie die Titelleiste als Reaktion auf eine neue Fensterpräsentation ein- oder ausblenden oder ändern sollen.

In diesem Beispiel wird gezeigt, wie das Changed-Ereignis behandelt wird, um das AppTitleBar-Element aus früheren Beispielen anzuzeigen und auszublenden. Wenn das Fenster in den Modus kompakte Überlagerung versetzt wird, wird die Titelleiste auf die Standardtitelleiste des Systems zurückgesetzt (oder Sie können eine benutzerdefinierte Titelleiste bereitstellen, die für kompakte Überlagerung optimiert ist).

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

Hinweis

Die Modi Vollbild und kompakte Überlagerung können nur eingegeben werden, wenn sie von Ihrer App unterstützt werden. Weitere Informationen finden Sie unter Verwalten von App-Fenstern, FullScreenPresenter und CompactOverlayPresenter.

Empfohlene und nicht empfohlene Vorgehensweisen

  • Machen Sie deutlich, ob Ihr Fenster aktiv oder inaktiv ist. Ändern Sie mindestens die Farbe des Texts, der Symbole und der Schaltflächen in der Titelleiste.
  • Definieren Sie einen Ziehbereich am oberen Rand des App-Zeichenbereichs. Das Abgleichen der Platzierung von Systemtitelleisten erleichtert Benutzer*innen das Auffinden.
  • Definieren Sie einen Ziehbereich, der der visuellen Titelleiste (falls vorhanden) im Zeichenbereich der App entspricht.

Beispiel für vollständige Anpassung

In diesem Beispiel wird der gesamte Code gezeigt, der im Abschnitt „Vollständige Anpassung“ beschrieben wird.

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