Personalizzazione della barra del titolo

Windows fornisce una barra del titolo predefinita per ogni finestra e consente di personalizzarla in modo che corrisponda alla personalità dell'app. La barra del titolo predefinita include alcuni componenti standard e funzionalità di base, ad esempio il trascinamento e il ridimensionamento della finestra.

A Windows app showing the title bar

Consultare l'articolo progettazione Barra del titolo per indicazioni sulla personalizzazione della barra del titolo dell'app, sul contenuto dell'area della barra del titolo accettabile e sui modelli di interfaccia utente consigliati.

Importante

Questo articolo illustra come personalizzare la barra del titolo per le app che usano Windows App SDK, con o senza WinUI 3. Per le app che usano UWP e WinUI 2, vedere Personalizzazione della barra del titolo per UWP.

Componenti della barra del titolo

Questo elenco descrive i componenti della barra del titolo standard.

  • Rettangolo barra del titolo
  • Testo titolo
  • Icona di sistema
  • Menu di sistema: accessibile facendo clic sull'icona dell'app o facendo clic con il pulsante destro del mouse sulla barra del titolo
  • Controlli didascalia
    • Pulsante Riduci a icona
    • Pulsante Ingrandisci/Ripristina
    • Pulsante Chiudi

Windowing

La funzionalità di Windowing in Windows App SDK avviene tramite la classe Microsoft.UI.Windowing.AppWindow, basata sul modello HWND Win32. Esiste un mapping 1:1 tra AppWindow e HWND di primo livello nell'app. AppWindow e le relative classi forniscono API che consentono di gestire molti aspetti delle finestre di primo livello dell'app, inclusa la personalizzazione della barra del titolo. È possibile modificare la barra del titolo predefinita fornita da Windows in modo che sia uniforme con il resto dell'interfaccia utente o estendere l'area di disegno dell'app nell'area della barra del titolo e fornire il contenuto della barra del titolo.

La funzionalità Windowing in WinUI 3 è basata sulla classe Microsoft.UI.Xaml.Window, basata anche sul modello HWND Win32. Per le app XAML che usano WinUI 3, le API Window XAML offrono un modo più semplice per personalizzare la barra del titolo, consentendo comunque di accedere alle API AppWindow quando necessario.

Come usare AppWindow

È possibile usare le API AppWindow con qualsiasi framework dell'interfaccia utente supportato da Windows App SDK, ovvero Win32, WPF, WinForms o WinUI 3, ed è possibile adottarli in modo incrementale, usando solo le API necessarie.

Se si usa XAML WinUI 3 come framework dell'interfaccia utente dell'app, sono disponibili sia le API Window che le API AppWindow. A partire da Windows App SDK 1.4, la Window XAML e AppWindow usano lo stesso oggetto AppWindowTitleBar per la personalizzazione della barra del titolo. Utilizzare la proprietà Window.AppWindow per ottenere un oggetto AppWindow da una Window XAML esistente. Con questo oggetto AppWindow è possibile accedere alle API di personalizzazione della barra del titolo. Per accedere a funzionalità aggiuntive della barra del titolo, puoi usare le API AppWindow dalla Window XAML come segue: AppWindow.TitleBar.ForegroundColor = Colors.White;.

Se non si usa WinUI 3 1.3 o versione successiva, usare le API di interoperabilità per ottenere AppWindow e usare le API AppWindow per personalizzare la barra del titolo. Per altre informazioni sulle API di interoperabilità, vedere Gestire le finestre delle app - Framework dell'interfaccia utente e interoperabilità HWND e l'esempio raccolta Windowing.

Quanto personalizzare la barra del titolo

Alla barra del titolo è possibile applicare due livelli di personalizzazione: applicare modifiche minime alla barra del titolo predefinita o estendere l'area di disegno dell'app nell'area della barra del titolo e fornire contenuto completamente personalizzato.

Semplice

Per una personalizzazione semplice, ad esempio la modifica del colore della barra del titolo, puoi impostare le proprietà nell'oggetto AppWindowTitleBar per specificare i colori che vuoi usare per gli elementi della barra del titolo. In questo caso, il sistema mantiene la responsabilità di tutti gli altri aspetti della barra del titolo, ad esempio disegnare il titolo dell'app e definire le aree di trascinamento.

Completa

L'altra opzione consiste nel nascondere la barra del titolo di sistema predefinita e sostituirla con il contenuto personalizzato. Ad esempio, è possibile inserire testo, una casella di ricerca o menu personalizzati nell'area della barra del titolo. Inoltre è necessario usare questa opzione per estendere uno sfondo materiale, ad esempio Mica, nell'area della barra del titolo.

Quando si sceglie la personalizzazione completa, si è responsabili dell'inserimento del contenuto nell'area della barra del titolo e si possono definire aree di trascinamento personalizzate. I controlli didascalia (pulsanti Chiudi, Riduci a icona e Ingrandisci) sono ancora disponibili e gestiti dal sistema, ma gli elementi come il titolo dell'app non sono presenti. È necessario creare questi elementi in base alle esigenze dell'app.

Personalizzazione semplice

Se vuoi personalizzare solo il titolo, i colori o l'icona della barra del titolo, puoi impostare le proprietà sull'oggetto barra del titolo per la finestra dell'app.

Title

Per impostazione predefinita, la barra del titolo mostra il tipo di app come titolo della finestra (ad esempio "WinUI Desktop"). È consigliabile aggiornare il titolo della finestra per visualizzare un nome visualizzato significativo per l'app.

Un'app XAML ha un nome visualizzato impostato nel file Package.appxmanifest. È possibile ottenere questo valore e usarlo per impostare la proprietà Title in questo modo.

Title = AppInfo.Current.DisplayInfo.DisplayName;

Per modificare il titolo della finestra, impostare la proprietà Window.Title su un valore di testo a riga singola, come illustrato di seguito.

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

Per modificare il titolo della finestra usando le API AppWindow, impostare la proprietà AppWindow.Title su un valore di testo a riga singola, come illustrato di seguito. Questo esempio mostra come usare le API di interoperabilità per ottenere AppWindow, necessario per app che non usa WinUI 3 1.3 o versione successiva.

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

Colori

Per personalizzare i colori predefiniti della barra del titolo o per modificare l'icona della finestra predefinita, è necessario usare le API AppWindow o scegliere di personalizzare completamente la barra del titolo.

Questo esempio mostra come ottenere un'istanza di AppWindowTitleBar e impostarne le proprietà del colore.

Importante

La personalizzazione dei colori viene ignorata quando l'app viene eseguita in 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;
}

Quando si impostano i colori della barra del titolo, tenere presenti alcuni aspetti:

  • Il colore di sfondo del pulsante non viene applicato agli stati passaggio e pressione del pulsante di chiusura. Il pulsante di chiusura usa sempre il colore definito dal sistema per tali stati.
  • L'impostazione di una proprietà colore su null la reimposta sul colore di sistema predefinito.
  • Non è possibile impostare colori trasparenti. Il canale alfa del colore viene ignorato.

Windows offre a un utente la possibilità di applicare il colore principale selezionato alla barra del titolo. Se si imposta un colore della barra del titolo, è consigliabile impostare in modo esplicito tutti i colori. Ciò garantisce che non ci siano combinazioni di colori indesiderate che si verificano a causa delle impostazioni dei colori definite dall'utente.

Icona e menu di sistema

È possibile nascondere l'icona di sistema o sostituirla con un'icona personalizzata. L'icona di sistema mostra il menu di sistema quando si fa clic con il pulsante destro del mouse o si tocca una volta. Chiude la finestra quando si fa doppio clic o viene toccato.

Per visualizzare o nascondere l'icona di sistema e i comportamenti associati, impostare la proprietà della barra del titolo IconShowOptions.

m_TitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu;

Per usare un'icona di finestra personalizzata, chiamare uno dei metodi AppWindow.SetIcon per impostare la nuova icona.

  • SetIcon(String)

    Il metodo SetIcon(String) attualmente funziona solo con i file .ico. La stringa passata a questo metodo è il percorso completo del file .ico.

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

    Se si dispone già di un handle per un'icona (HICON) da una delle Funzioni icona come CreateIcon, è possibile usare l'API di interoperabità GetIconIdFromIcon per ottenere IconId. È quindi possibile passare IconId al metodo SetIcon(IconId) per impostare l'icona della finestra.

    m_AppWindow.SetIcon(iconId));
    

Personalizzazione completa

Quando si acconsente esplicitamente alla personalizzazione completa della barra del titolo, l'area client dell'app viene estesa per coprire l'intera finestra, inclusa l'area della barra del titolo. L'utente è responsabile della gestione dell'input e del disegno per l'intera finestra, ad eccezione dei pulsanti didascalia, ancora forniti dalla finestra.

Per nascondere la barra del titolo di sistema ed estendere il contenuto nell'area della barra del titolo, impostare la proprietà che estende il contenuto dell'app nell'area della barra del titolo su true. In un'app XAML questa proprietà può essere impostata nel metodo OnLaunched dell'app (App.xaml.cs) o nella prima pagina dell'app.

Suggerimento

Consultare la sezione Esempio di personalizzazione completa per vedere tutto il codice in una volta.

In questo esempio viene illustrato come impostare la proprietà Window.ExtendsContentIntoTitleBar su true.

public MainWindow()
{
    this.InitializeComponent();

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

Attenzione

ExtendsContentIntoTitleBar mostra in XAML IntelliSense per Window, ma impostando questo in XAML genera un errore. Impostare questa proprietà nel codice.

Questo esempio mostra come ottenere AppWindowTitleBar e impostare la proprietà AppWindow.ExtendsContentIntoTitleBar su true. Questo esempio mostra come usare le API di interoperabilità per ottenere AppWindow, necessario se l'app non usa WinUI 3 1.3 o versione successiva.

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

Contenuto della barra del titolo e area di trascinamento predefinita

Quando l'app viene estesa nell'area della barra del titolo, si è responsabili della definizione e della gestione dell'interfaccia utente per la barra del titolo. Ciò include in genere almeno il testo del titolo e l'area di trascinamento. L'area di trascinamento della barra del titolo definisce la posizione in cui l'utente può fare clic e trascinare per spostare la finestra. È anche la posizione in cui l'utente può fare clic con il pulsante destro del mouse per visualizzare il menu di sistema.

Per altre informazioni sul contenuto della barra del titolo accettabile e sui modelli di interfaccia utente consigliati, consultare Progettazione della barra del titolo.

Questo esempio mostra il codice XAML per un'interfaccia utente della barra del titolo personalizzata senza contenuto interattivo.

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

Importante

LeftPaddingColumn e RightPaddingColumn vengono utilizzati per riservare spazio per i pulsanti di didascalia. I valori Width per queste colonne vengono impostati nel codice, come illustrato più avanti. Per informazioni sul codice e sulla spiegazione, vedere la sezione Pulsanti di didascalia di sistema.

Un'app XAML ha un nome visualizzato impostato nel file Package.appxmanifest. È possibile ottenere questo valore e usarlo nella barra del titolo personalizzata in questo modo.

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

Quando si estende il contenuto nell'area della barra del titolo, la barra del titolo di sistema è nascosta e viene creata una AppWindowTitleBar predefinita che fornisce pulsanti didascalia e un'area di trascinamento nella larghezza dello schermo, identica alla barra del titolo di sistema. Se non si inserisce contenuto interattivo nella barra del titolo, è possibile lasciare invariata questa area di trascinamento predefinita. Se si inserisce contenuto interattivo nella barra del titolo, è necessario specificare le aree interattive, illustrate nella sezione successiva.

Attenzione

Quando si definiscono aree di trascinamento personalizzate, non è necessario che si trovino nella parte superiore della finestra nell'area della barra del titolo predefinita; è possibile definire qualsiasi parte dell'interfaccia utente come area di trascinamento. Tuttavia, l'inserimento di aree di trascinamento in posizioni diverse potrebbe rendere difficile per gli utenti l'individuazione.

Contenuto interattivo

È possibile posizionare controlli interattivi, ad esempio pulsanti, menu o una casella di ricerca, nella parte superiore dell'app in modo che appaiano nella barra del titolo. Tuttavia, è necessario specificare quali aree sono interattive per garantire che gli elementi interattivi ricevano l'input dell'utente, consentendo comunque agli utenti di spostare la finestra.

A Windows app with a search box in the title bar

Quando si aggiunge contenuto interattivo nell'area della barra del titolo, è necessario usare la classe InputNonClientPointerSource per specificare le aree in cui l'input viene passato al controllo interattivo, anziché gestito dalla barra del titolo. Per impostare le aree interattive, chiamare il metodo InputNonClientPointerSource.SetRegionRects. Questo metodo accetta un valore che specifica il tipo di area da impostare (in questo caso , Passthrough) e una matrice di rettangoli, ognuno dei quali definisce un'area Passthrough. Quando cambiano le dimensioni della barra del titolo, è necessario ricalcolare le aree interattive in modo che corrispondano alle nuove dimensioni e chiamare SetRegionRects con i nuovi valori.

Questo esempio mostra un'interfaccia utente della barra del titolo personalizzata con una casella di ricerca e un controllo account PersonPicture. Illustra come calcolare e impostare i rettangoli interattivi per questi controlli in modo che l'input venga passato attraverso questi.

Ci sono alcuni punti importanti da tenere presenti in relazione a questo codice:

  • Impostare AppTitleBar L'altezza della griglia a 48 per seguire le linee guida per la progettazione della Barra del titolo per il contenuto interattivo.
  • Impostare PreferredHeightOption su Tall in modo che i pulsanti didascalia corrispondano alla stessa altezza della barra del titolo.
  • Per semplificare il ridimensionamento dei controlli e il calcolo delle aree, usare Grid con più colonne denominate per il layout.
  • Usare il dimensionamento stelle (*) con MinWidth per la colonna che contiene AutoSuggestBox in modo che il dimensionamento avvenga automaticamente con la finestra.
  • Impostare MinWidth su RightDragColumn per riservare una piccola area che è sempre trascinabile anche quando la finestra viene ridimensionata.
  • Impostare ExtendsContentIntoTitleBar a true nel costruttore MainWindow. Se imposti ciò nel codice che viene chiamato in un secondo momento, la barra del titolo di sistema predefinita potrebbe essere visualizzata prima e poi nascosta.
  • Effettuare la chiamata iniziale per calcolare le aree interattive dopo il caricamento dell'elemento AppTitleBar. In caso contrario, non esiste alcuna garanzia che gli elementi usati per il calcolo presentino i valori corretti.
  • Aggiornare i calcoli del rettangolo interattivo solo dopo la modifica delle dimensioni dell'elemento AppTitleBar (AppTitleBar_SizeChanged). Se si dipende dall'evento della finestra Changed , ci saranno situazioni (ad esempio finestra ingrandisce/riduci a icona) in cui l'evento si verifica prima che AppTitleBar venga ridimensionata e i calcoli utilizzeranno valori errati.
  • Impostare le aree interattive/di trascinamento personalizzate solo dopo aver verificato ExtendsContentIntoTitleBar per confermare che viene utilizzata una barra del titolo personalizzata.
<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>

Questo codice illustra come calcolare e impostare le aree interattive corrispondenti ai controlli AutoSuggestBox e 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)
        );
    }
}

Avviso

AppWindow usa i pixel fisici per la compatibilità con i framework dell'interfaccia utente che non usano coordinate logiche. Se si usa WPF o WinUI 3, RightInset, LeftInset e i valori usati per calcolare le aree devono essere regolati se la scala di visualizzazione non è 100%. In questo esempio si ottiene un valore scaleAdjustment per tenere conto dell'impostazione di scalabilità di visualizzazione.

Pulsanti didascalia di sistema

Il sistema riserva l'angolo superiore sinistro o superiore destro della finestra dell'app per i pulsanti di didascalia di sistema (ridurre al minimo, ingrandire/ripristinare, chiudere). Il sistema mantiene il controllo dell'area del pulsante didascalia per garantire che venga fornita la funzionalità minima per il trascinamento, la riduzione al minimo, l'ottimizzazione e la chiusura della finestra. Il sistema disegna il pulsante Chiudi in alto a destra per le lingue da sinistra a destra e in alto a sinistra per le lingue da destra a sinistra.

È possibile disegnare il contenuto sotto l'area di controllo didascalia, ad esempio lo sfondo dell'app, ma non devi inserire alcuna interfaccia utente con cui prevedi che l'utente possa interagire. Non riceve alcun input perché l'input per i controlli didascalia viene gestito dal sistema.

Queste righe dell'esempio precedente mostrano le colonne di spaziatura in XAML che definisce la barra del titolo. L'uso delle colonne di spaziatura anziché dei margini garantisce che lo sfondo dipinga l'area sotto i pulsanti di controllo didascalia (per i pulsanti trasparenti). L'uso sia delle colonne di spaziatura interna destra che sinistra garantisce che la barra del titolo si comporti correttamente sia nei layout da destra a sinistra che da sinistra a destra.

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

Le dimensioni e la posizione dell'area di controllo didascalia viene comunicata dalla classe AppWindowTitleBar in modo che sia possibile tenerne conto nel layout dell'interfaccia utente della barra del titolo. La larghezza dell'area riservata su ogni lato viene assegnata dalle proprietà LeftInset o RightInset e l'altezza viene assegnata dalla proprietà Altezza.

Ecco come viene specificata la larghezza delle colonne di spaziatura quando vengono calcolate e impostate le aree di trascinamento.

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

Importante

Vedere informazioni importanti nella sezione Contenuto interattivo riguardo a come il ridimensionamento della visualizzazione influisce su questi valori.

Supporto della barra del titolo con altezza maggiore per le barre del titolo personalizzate

Quando si aggiunge contenuto interattivo come una casella di ricerca o un'immagine di persona nella barra del titolo, si consiglia di aumentare l'altezza della barra del titolo per fornire maggiore spazio per questi elementi. Una barra del titolo più alta semplifica anche la manipolazione tramite tocco. La proprietà AppWindowTitleBar.PreferredHeightOption consente di aumentare l'altezza della barra del titolo rispetto all'altezza standard, ovvero l'impostazione predefinita, portandola a un'altezza maggiore. Quando si seleziona la modalità barra del titolo Tall, i pulsanti didascalia disegnati dal sistema come sovrapposizione nell'area client vengono resi più alti con i relativi glifi chiusi/min/max centrati. Se non è stata specificata un'area di trascinamento, il sistema disegnare uno che estende la larghezza della finestra e l'altezza determinata dal valore PreferredHeightOption impostato.

In questo esempio viene illustrato come impostare la proprietà PreferredHeightOption.

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

Attenzione

La proprietà AppWindowTitleBar.ExtendsContentIntoTitleBar deve essere true prima di impostare la proprietà PreferredHeightOption. Se si tenta di impostare PreferredHeightOption mentre ExtendsContentIntoTitleBar è false, viene generata un'eccezione.

Colore e trasparenza nei pulsanti didascalia

Quando si estende il contenuto dell'app nell'area della barra del titolo, è possibile rendere trasparente lo sfondo dei pulsanti didascalia per consentire la visualizzazione dello sfondo dell'app. In genere si imposta lo sfondo su Colors.Transparent per la trasparenza completa. Per la trasparenza parziale, impostare il canale alfa per Colore su cui si imposta la proprietà.

Queste proprietà della barra del titolo possono essere trasparenti:

Tutte le altre proprietà di colore continueranno a ignorare il canale alfa. Se ExtendsContentIntoTitleBar è impostato su false, il canale alfa viene sempre ignorato per tutte le proprietà del colore AppWindowTitleBar.

Il colore di sfondo del pulsante non viene applicato agli stati passaggio e pressione del pulsante Chiudi. Il pulsante di chiusura usa sempre il colore definito dal sistema per tali stati.

Suggerimento

Mica è un materiale piacevole che aiuta a distinguere la finestra che viene messa a fuoco. È consigliabile usarlo come sfondo per le finestre di lunga durata in Windows 11. Se è stata applicato Mica nell'area client della finestra, è possibile estenderla nell'area della barra del titolo e rendere i pulsanti didascalia trasparenti per visualizzare Mica. Per altre informazioni, vedere materiale Mica.

Disattivare la barra del titolo quando la finestra è inattiva

È consigliabile rendere evidente quando la finestra è attiva o inattiva. È necessario modificare almeno il colore del testo, delle icone e dei pulsanti nella barra del titolo.

Per le app XAML, gestire l'evento Window.Activated per determinare lo stato di attivazione della finestra e aggiornare l'interfaccia utente della barra del titolo in base alle esigenze.

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

Per altri framework dell'interfaccia utente, gestire un evento per determinare lo stato di attivazione della finestra e aggiornare l'interfaccia utente della barra del titolo in base alle esigenze. La modalità di determinazione dello stato della finestra dipende dal framework dell'interfaccia utente usato per l'app.

Reimpostare la barra del titolo

Per reimpostare o passare alla barra del titolo di sistema mentre l'app è in esecuzione, è possibile chiamare AppWindowTitleBar.ResetToDefault.

m_AppWindow.TitleBar.ResetToDefault();

Per le app XAML, puoi anche reimpostare la barra del titolo nei modi seguenti:

  • Chiamare SetTitleBar per passare a un nuovo elemento della barra del titolo mentre l'app è in esecuzione.
  • Chiamare SetTitleBar con null come parametro per reimpostare le aree di trascinamento predefinite AppWindowTitleBar.
  • Chiamare SetTitleBar con null come parametro e impostare ExtendsContentIntoTitleBar su false per ripristinare la barra del titolo di sistema predefinita.

Mostra e nascondi la barra del titolo

Se si aggiunge il supporto per le modalità a schermo intero o sovrapposizione compatta all'app, potrebbe essere necessario dover apportare modifiche alla barra del titolo quando l'app passa da una modalità all'altra. La Window XAML non fornisce API per supportare la modalità schermo intero; è possibile usare le API AppWindow per questa operazione.

Quando l'app viene eseguita in modalità schermo intero, il sistema nasconde la barra del titolo e i pulsanti di controllo didascalia. È possibile gestire l'evento AppWindow.Changed e controllare la proprietà degli argomenti dell'evento DidPresenterChange, per determinare se bisogna mostrare, nascondere o modificare la barra del titolo in risposta a una nuova presentazione della finestra.

In questo esempio viene illustrato come gestire l'evento Changed per mostrare e nascondere l'elemento AppTitleBar dagli esempi precedenti. Se la finestra viene inserita in modalità sovrapposizione compatta, la barra del titolo viene reimpostata sulla barra del titolo di sistema predefinita (oppure è possibile fornire una barra del titolo personalizzata ottimizzata per la sovrapposizione compatta).

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

Nota

Le modalità schermo intero e sovrapposizione compatta possono essere immesse solo se supportate dall'app. Per altre informazioni, vedere Gestire le finestre delle app, FullScreenPresenter e CompactOverlayPresenter.

Cosa fare e cosa non fare

  • È consigliabile rendere evidente quando la finestra è attiva o inattiva. È necessario modificare almeno il colore di testo, icone e pulsanti nella barra del titolo.
  • Definire un'area di trascinamento lungo il bordo superiore dell'area di disegno dell'app. La corrispondenza della posizione delle barre del titolo di sistema semplifica la ricerca da parte degli utenti.
  • Definire un'area di trascinamento corrispondente alla barra del titolo oggetto visivo (se presente) nell'area di disegno dell'app.

Esempio di personalizzazione completa

In questo esempio viene illustrato tutto il codice descritto nella sezione Personalizzazione completa.

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