Personalização da barra de título

O Windows fornece uma barra de título padrão para cada janela e permite personalizá-la para corresponder à personalidade do aplicativo. A barra de título padrão vem com alguns componentes padrão e funcionalidade principal, como arrastar e redimensionar a janela.

A Windows app showing the title bar

Consulte o artigo de design da Barra de título para obter diretrizes sobre como personalizar a barra de título do aplicativo, o conteúdo aceitável da barra de título e os padrões de interface do usuário recomendados.

Importante

Este artigo mostra como personalizar a barra de título para aplicativos que usam o SDK do Aplicativo Windows, com ou sem WinUI 3. Para aplicativos que usam UWP e WinUI 2, consulte Personalização da barra de título para UWP.

Componentes da barra de título

Esta lista descreve os componentes da barra de título padrão.

  • Retângulo da barra de título
  • Texto do título
  • Ícone do sistema
  • Menu do sistema – acessado clicando no ícone do aplicativo ou clicando com o botão direito do mouse na barra de título
  • Controles de legenda
    • Botão Minimizar
    • Botão Maximizar/Restaurar
    • Botão Fechar

Janelas

A funcionalidade de janela no SDK do Aplicativo Windows é por meio da classe Microsoft.UI.Windowing.AppWindow, que se baseia no modelo Win32 HWND. Há um mapeamento 1:1 entre um AppWindow e um HWND de nível superior em seu aplicativo. O AppWindow e suas classes relacionadas fornecem APIs que permitem gerenciar muitos aspectos das janelas de nível superior do aplicativo, incluindo a personalização da barra de título. Você pode modificar a barra de título padrão que o Windows fornece para que ela se misture com o restante da interface do usuário ou estender a tela do aplicativo para a área da barra de título e fornecer o próprio conteúdo da barra de título.

A funcionalidade de janela no WinUI 3 é por meio da classe Microsoft.UI.Xaml.Window, que também é baseada no modelo HWND do Win32. Para aplicativos XAML que usam WinUI 3, as APIs Window do XAML fornecem uma maneira mais simples de personalizar a barra de título, enquanto ainda permitem que você acesse as APIs AppWindow quando necessário.

Como trabalhar com AppWindow

Você pode usar APIs AppWindow com qualquer estrutura de interface do usuário compatível com o SDK de Aplicativo do Windows – Win32, WPF, WinForms ou WinUI 3 – e você pode adotá-las incrementalmente, usando apenas as APIs necessárias.

Se você usar o WinUI 3 XAML como a estrutura de interface do usuário do seu aplicativo, as APIs Window e AppWindow estarão disponíveis para você. A partir do Windows App SDK 1.4, a Window do XAML e AppWindow usam o mesmo objeto AppWindowTitleBar para personalização da barra de título. Use a propriedade Window.AppWindow para obter um objeto AppWindow de uma janela XAML existente. Com esse objeto AppWindow, você tem acesso às APIs de personalização da barra de título. Para acessar recursos adicionais da barra de título, você pode usar as APIs AppWindow da Janela XAML da seguinte maneira: AppWindow.TitleBar.ForegroundColor = Colors.White;.

Se você não estiver usando o WinUI 3 1.3 ou posterior, use APIs de interoperabilidade para obter o AppWindow e use as APIs do AppWindow para personalizar a barra de título. Para obter mais informações sobre as APIs de interoperabilidade, consulte Gerenciar janelas de aplicativo – estrutura da interface do usuário e interoperabilidade do HWND e o exemplo da galeria de janelas.

Quanto personalizar a barra de título

Há dois níveis de personalização que você pode aplicar à barra de título: aplicar pequenas modificações à barra de título padrão ou estender a tela do aplicativo para a área da barra de título e fornecer conteúdo completamente personalizado.

Simples

Para personalização simples, como alterar a cor da barra de título, você pode definir propriedades no objeto AppWindowTitleBar para especificar as cores que deseja usar para elementos da barra de título. Nesse caso, o sistema mantém responsabilidade de todos os outros aspectos da barra de título, como o título do aplicativo de desenho e definindo áreas para arrastar.

Completo

A outra opção é ocultar a barra de título do sistema padrão e substituí-la com seu próprio conteúdo personalizado. Por exemplo, você pode colocar texto, uma caixa de pesquisa ou menus personalizados na área da barra de título. Você também precisará usar essa opção para estender um fundo de material, como Mica, na área da barra de título.

Quando você optar por personalização completa, você é responsável por colocar o conteúdo na área de barra de título, e você pode definir sua próprias regiões para arrastar. Os controles de legenda (botões Fechar, Minimizar e Maximizar o sistema) ainda estão disponíveis e são manipulados pelo sistema, mas não são como elementos, como o título do aplicativo. Você mesmo precisará criar esses elementos, conforme necessário, para seu aplicativo.

Personalização simples

Se quiser personalizar apenas o título, as cores ou o ícone da barra de título, você pode definir propriedades no objeto da barra de título para a janela do aplicativo.

Título

Por padrão, a barra de título mostra o tipo de aplicativo como o título da janela (por exemplo, "Área de trabalho WinUI"). Você deve atualizar o título da janela para mostrar um nome de exibição significativo para seu aplicativo.

Um aplicativo XAML tem um nome de exibição definido no arquivo Package.appxmanifest. Você pode obter esse valor e usá-lo para definir a propriedade Title dessa forma.

Title = AppInfo.Current.DisplayInfo.DisplayName;

Para alterar o título da janela, defina a propriedade Window.Title como um valor de texto de linha única, conforme mostrado aqui.

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

Para alterar o título da janela usando APIs AppWindow, defina a propriedade AppWindow.Title como um valor de texto de linha única, conforme mostrado aqui. Este exemplo mostra como usar APIs de interoperabilidade para obter o AppWindow, que é necessário para que seu aplicativo não use WinUI 3 1.3 ou posterior.

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

Cores

Para personalizar as cores padrão da barra de título ou alterar o ícone da janela padrão, você precisará usar as APIs do AppWindow ou optar por personalizar totalmente sua barra de título.

Este exemplo mostra como obter uma instância de AppWindowTitleBar e definir suas propriedades de cor.

Importante

A personalização de cores é ignorada quando o aplicativo é executado no 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;
}

Há alguns aspectos a serem observados ao definir as cores da barra de título:

  • A cor de fundo do botão não é aplicada ao botão Fechar quando você passa o mouse sobre ele ou clica nele. O botão fechar sempre usa a cor definida pelo sistema para esses estados.
  • Definir uma propriedade de cor para null restaura a cor padrão do sistema.
  • Não é possível definir cores transparentes. O canal alfa da cor é ignorado.

O Windows oferece ao usuário a opção de aplicar a cor de destaque selecionada à barra de título. Se você definir qualquer cor da barra de título, recomendamos que você defina explicitamente todas as cores. Isso garante que não haja combinações de cores não intencionais que ocorram devido às configurações de cores definidas pelo usuário.

Ícone e menu do sistema

Você pode ocultar o ícone do sistema ou substituí-lo por um ícone personalizado. O ícone do sistema mostra o menu do sistema quando o botão direito do mouse é clicado ou tocado uma vez. Ele fecha a janela quando é clicado/tocado duas vezes.

Para mostrar ou ocultar o ícone do sistema e os comportamentos associados, defina a propriedade IconShowOptions da barra de título.

m_TitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu;

Para usar um ícone de janela personalizado, chame um dos métodos AppWindow.SetIcon para definir o novo ícone.

  • SetIcon(String)

    O método SetIcon(String) atualmente funciona apenas com arquivos .ico. A cadeia de caracteres que você passa para esse método é o caminho totalmente qualificado para o arquivo .ico.

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

    Se você já tiver um identificador para um ícone (HICON) de uma das funções Icon como CreateIcon, poderá usar a API de interoperabilidade GetIconIdFromIcon para obter um IconId. Em seguida, você pode passar o IconId para o método SetIcon(IconId) para definir o ícone de janela.

    m_AppWindow.SetIcon(iconId));
    

Personalização completa

Quando você concorda com a personalização da barra de título completa, a área de cliente do seu aplicativo é estendida para cobrir toda a janela, incluindo a área da barra de título. Você é responsável por desenho e manipulação de entrada para toda a janela, exceto os botões de legenda, que são sobrepostos na parte superior da tela do aplicativo.

Para ocultar a barra de título do sistema e estender seu conteúdo para a área da barra de título, defina a propriedade que estende o conteúdo do aplicativo na área da barra de título como true. Em um aplicativo XAML, essa propriedade pode ser definida no método do aplicativo OnLaunched (App.xaml.cs) ou na primeira página do aplicativo.

Dica

Consulte a seção Exemplo de personalização completa para ver todo o código de uma só vez.

Este exemplo mostra como definir a propriedade Window.ExtendsContentIntoTitleBar como true.

public MainWindow()
{
    this.InitializeComponent();

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

Cuidado

ExtendsContentIntoTitleBar mostra no IntelliSense XAML para Window, mas defini-lo em XAML causa um erro. Em vez disso, defina essa propriedade no código.

Este exemplo mostra como obter a propriedade AppWindowTitleBar e definir a propriedade AppWindow.ExtendsContentIntoTitleBar como true. Este exemplo mostra como usar APIs de interoperabilidade para obter o AppWindow, que é necessário se o seu aplicativo não usa WinUI 3 1.3 ou posterior.

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

Conteúdo da barra de título e a região de arrastar padrão

Quando seu aplicativo é estendido para a área da barra de título, você é responsável por definir e gerenciar a interface do usuário para a barra de título. Normalmente, isso inclui, no mínimo, a especificação do texto do título e da região de arrastar. A região de arrastar da barra de título define onde o usuário pode clicar e arrastar para mover a janela. Também é onde o usuário pode clicar com o botão direito do mouse para mostrar o menu do sistema.

Para saber mais sobre o conteúdo aceitável da barra de título e os padrões de interface do usuário recomendados, consulte Design da barra de título.

Este exemplo mostra XAML para uma interface do usuário da barra de título personalizada sem conteúdo interativo.

<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

O LeftPaddingColumn e RightPaddingColumn são usados para reservar espaço para os botões legenda. Os valores Width dessas colunas são definidos no código, que é mostrado posteriormente. Consulte a seção Botões de legenda do sistema para obter o código e a explicação.

Um aplicativo XAML tem um nome de exibição definido no arquivo Package.appxmanifest. Você pode obter esse valor e usá-lo em sua barra de título personalizada como esta.

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

Quando você estende seu conteúdo para a área da barra de título, a barra de título do sistema fica oculta e um AppWindowTitleBar padrão é criado que fornece botões de legenda e uma região de arrastar pela largura da tela, idêntica à barra de título do sistema. Se você não colocar conteúdo interativo na barra de título, poderá deixar essa região de arrastar padrão no estado em que se encontra. Se você colocar conteúdo interativo na barra de título, precisará especificar as regiões que são interativas, que abordaremos na próxima seção.

Cuidado

Quando você define regiões de arraste personalizadas, elas não precisam estar na parte superior da janela, na área padrão da barra de título; você pode definir qualquer parte da interface do usuário como uma região de arrastar. No entanto, colocar regiões de arrastar em locais diferentes pode dificultar a descoberta pelos usuários.

Conteúdo interativo

Você pode colocar controles interativos, como botões, menus ou uma caixa de pesquisa, na parte superior do aplicativo para que eles pareçam estar na barra de título. No entanto, você precisa especificar quais regiões são interativas para garantir que os elementos interativos recebam a entrada do usuário e, ao mesmo tempo, permitir que os usuários movam sua janela.

A Windows app with a search box in the title bar

Quando você adiciona conteúdo interativo na área da barra de título, precisa usar a classe InputNonClientPointerSource para especificar áreas nais quais a entrada é passada para o controle interativo, em vez de manipulada pela barra de título. Para definir as regiões interativas, chame o método InputNonClientPointerSource.SetRegionRects. Esse método usa um valor que especifica o tipo de região que está sendo definida (neste caso, Passthrough) e uma matriz de retângulos, cada um dos quais define uma região Passthrough. Quando o tamanho da barra de título muda, você precisa recalcular as regiões interativas para corresponder ao novo tamanho e chamar SetRegionRects com os novos valores.

Este exemplo mostra uma interface do usuário personalizada da barra de título com uma caixa de pesquisa e um controle de conta PersonPicture. Ele demonstra como calcular e definir os retângulos interativos para esses controles, a fim de que a entrada seja passada para eles.

Aqui estão alguns pontos importantes a serem notados sobre este código:

  • Defina a altura da Grade AppTitleBar como 48 para seguir as diretrizes de design da barra de título para conteúdo interativo.
  • Defina PreferredHeightOption para Tall que os botões de legenda tenham a mesma altura que a barra de título.
  • Para facilitar o redimensionamento de controles e o cálculo de regiões, use um Grid com várias colunas nomeadas para o layout.
  • Use o dimensionamento em estrela (*) com MinWidth para a coluna que contém o AutoSuggestBox para que ela seja redimensionada automaticamente com a janela.
  • Defina MinWidth no RightDragColumn para reservar uma pequena área que é sempre arrastável, mesmo quando a janela é redimensionada.
  • Defina ExtendsContentIntoTitleBar para true no construtor MainWindow. Se você defini-lo no código que é chamado posteriormente, a barra de título do sistema padrão poderá ser mostrada primeiro e, em seguida, escondida.
  • Faça a chamada inicial para calcular regiões interativas depois que o elemento AppTitleBar for carregado. Caso contrário, não há garantia de que os elementos usados para o cálculo terão seus valores corretos.
  • Atualize os cálculos de retângulo interativo somente depois que o elemento AppTitleBar tiver mudado de tamanho (AppTitleBar_SizeChanged). Se você depender do evento de janela Changed, haverá situações (como maximizar/minimizar janela) em que o evento ocorre antes de redimensionar AppTitleBar, e os cálculos usarão valores incorretos.
  • Defina suas áreas de arraste/interativas personalizadas somente depois de verificar ExtendsContentIntoTitleBar para confirmar se uma barra de título personalizada está sendo usada.
<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>

Este código mostra como calcular e definir as regiões interativas que correspondem aos controles 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)
        );
    }
}

Aviso

AppWindow usa pixels físicos para compatibilidade com estruturas de interface do usuário que não usam coordenadas lógicas. Se você usar WPF ou WinUI 3, RightInset, LeftInset e os valores usados para calcular regiões precisarão ser ajustados se a escala de exibição não for 100%. Neste exemplo, obtemos um valor scaleAdjustment a ser considerado para a configuração de escala de exibição.

Botões de legenda do sistema

O sistema reserva o canto superior esquerdo ou direito superior da janela do aplicativo para os botões de legenda do sistema (minimizar, maximizar, fechar). O sistema mantém o controle da área do botão de legenda para garantir que a funcionalidade mínima seja fornecida para arrastar, minimizar, maximizar e fechar a janela. O sistema desenha o botão Fechar no canto superior direito para idiomas da esquerda para a direita e no canto superior esquerdo para idiomas da direita para a esquerda.

Você pode desenhar conteúdo sob a área de controle de legenda definida por essas propriedades, como seu plano de fundo do aplicativo, mas você não deve colocar qualquer interface do usuário com a qual você espera que o usuário possa interagir. Ela não recebe nenhuma entrada porque a entrada para os controles de legenda é manipulada pelo sistema.

Essas linhas do exemplo anterior mostram as colunas de preenchimento no XAML que define a barra de título. O uso de colunas de preenchimento em vez de margens garante que a tela de fundo pinte a área sob os botões de controle legenda (para botões transparentes). Usar colunas de preenchimento direita e esquerda garante que sua barra de título se comporte corretamente nos layouts da direita para a esquerda e da esquerda para a direita.

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

A dimensão e a posição da área de controle de legenda é comunicada pela classe AppWindowTitleBar para que você possa considerá-la no layout de sua interface do usuário da barra de títulos. A largura da região reservada em cada lado é determinada pelas propriedades LeftInset ou RightInset e a altura é determinado pela propriedade Altura.

Veja como a largura das colunas de preenchimento é especificada quando as regiões de arrastar são calculadas e definidas.

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

Importante

Confira informações importantes na seção Conteúdo interativo sobre como o dimensionamento de exibição afeta esses valores.

Suporte à barra de título alta para barras de título personalizadas

Quando você adiciona conteúdo interativo como uma caixa de pesquisa ou imagem de pessoa na barra de título, recomendamos que você aumente a altura da barra de título para fornecer mais espaço para esses elementos. Uma barra de título mais alta também facilita a manipulação de toque. A propriedade AppWindowTitleBar.PreferredHeightOption oferece a opção de aumentar a altura da barra de título da altura padrão, que é o padrão, para uma altura mais alta. Quando você seleciona Tall, o modo de barra de título, os botões de legenda que o sistema desenha como uma sobreposição na área do cliente são renderizados mais altos com seus glifos mín/máx/fechar centralizados. Se você não tiver especificado uma região de arrastar, o sistema desenhará uma que estende a largura da janela e a altura determinada pelo valor PreferredHeightOption definido.

Este exemplo mostra como você pode definir a propriedade PreferredHeightOption.

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

Cuidado

A propriedade AppWindowTitleBar.ExtendsContentIntoTitleBar deve ser true antes de definir a propriedade PreferredHeightOption. Se você tentar definir PreferredHeightOption enquanto ExtendsContentIntoTitleBar é false, uma exceção será lançada.

Cor e transparência nos botões de legenda

Ao estender o conteúdo do aplicativo para a área da barra de título, você pode tornar a tela de fundo dos botões de legenda transparente para permitir que a tela de fundo do aplicativo seja exibida. Você normalmente define o plano de fundo como Colors.Transparent para transparência total. Para transparência parcial, defina o canal alfa para a Cor para a qual você definiu a cor.

Estas propriedades da barra de título podem ser transparentes:

Todas as outras propriedades de cor continuarão a ignorar o canal alfa. Se ExtendsContentIntoTitleBar estiver definido como false, o canal alfa será sempre ignorado para todas as propriedades de cor AppWindowTitleBar.

A cor de fundo do botão não é aplicada ao botão Fechar quando você passa o mouse sobre ele ou clica nele. O botão fechar sempre usa a cor definida pelo sistema para esses estados.

Dica

Mica é um material agradável que ajuda a distinguir a janela que está em foco. Recomendamos isso como o plano de fundo para janelas de longa duração em Windows 11. Se você aplicou o Mica na área do cliente da sua janela, poderá estendê-lo para a área da barra de título e tornar os botões de legenda transparentes para que o Mica apareça. Consulte Material Mica para obter mais informações.

Diminua a barra de título quando a janela estiver inativa

Você deve deixar claro quando a janela está ativa ou inativa. No mínimo, você deve alterar a cor dos botões na barra de título, ícones e texto.

Para aplicativos XAML, identifique o evento Window.Activated para determinar o estado de ativação da janela e atualize a interface do usuário da barra de título conforme necessário.

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

Para outras estruturas da IU, identifique um evento para determinar o estado de ativação da janela e atualize a UI da barra de título conforme necessário. A forma como você determina o estado da janela depende da estrutura da IU usada para seu aplicativo.

Redefinir a barra de título

Para redefinir ou alternar para a barra de título do sistema enquanto o aplicativo estiver em execução, você pode chamar AppWindowTitleBar.ResetToDefault.

m_AppWindow.TitleBar.ResetToDefault();

Para aplicativos XAML, você também pode redefinir a barra de título das seguintes maneiras:

  • Chame SetTitleBar para alternar para um novo elemento de barra de título enquanto seu aplicativo está em execução.
  • Chame SetTitleBar com null como o parâmetro para redefinir para as regiões de arrastar padrão AppWindowTitleBar.
  • Chame SetTitleBar com null como o parâmetro e defina ExtendsContentIntoTitleBar para reverter para false a barra de título padrão do sistema.

Mostrar e ocultar a barra de título

Se você adicionar suporte para modos de sobreposição compacta ou de tela inteira ao seu aplicativo, talvez seja necessário fazer alterações na barra de título quando o aplicativo alternar entre esses modos. A janela XAML não fornece nenhuma API para dar suporte ao modo de tela cheia; você pode usar APIs AppWindow para isso.

Quando seu aplicativo é executado em modo de tela inteira, o sistema oculta a barra de título e os botões do controle de legenda. Você pode identificar o evento AppWindow.Changed e marcar a propriedade args didPresenterChange do evento para determinar se você deve mostrar, ocultar ou alterar a barra de título em resposta a uma nova apresentação de janela.

Este exemplo mostra como identificar o evento Changed para mostrar e ocultar o elemento AppTitleBar de exemplos anteriores. Se a janela for colocada no modo de sobreposição compacta, a barra de título será redefinida para a barra de título do sistema padrão (ou você poderá fornecer uma barra de título personalizada otimizada para sobreposição compacta).

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

Observação

Os modos detela inteira e sobreposição compacta só podem ser inseridos se aceitos pelo seu aplicativo. Consulte Gerenciar janelas de aplicativos, FullScreenPresenter e CompactOverlayPresenter para obter mais informações.

O que fazer e o que não fazer

  • Deixe claro quando a janela está ativa ou inativa. No mínimo, altere a cor do texto, dos ícones e dos botões na barra de título.
  • Defina uma região de arrastar ao longo da borda superior da tela do aplicativo. Combinar o posicionamento das barras de título do sistema facilita a localização pelos usuários.
  • Defina uma região de arrastar que corresponde a barra de título visual (se houver) na tela do aplicativo.

Exemplo de personalização completa

Este exemplo mostra todo o código descrito na seção Personalização 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);
            }
        }
    }
}