Настройка заголовка окна

Windows предоставляет строку заголовка по умолчанию для каждого окна и позволяет настроить ее в соответствии с личностью приложения. Строка заголовка по умолчанию поставляется с некоторыми стандартными компонентами и основными функциями, такими как перетаскивание и изменение размера окна.

Приложение Windows с заголовком

Сведения о настройке заголовка строки заголовка, допустимом содержимом области заголовка приложения и рекомендуемых шаблонах пользовательского интерфейса см. в статье о конструкторе заголовков.

Внимание

В этой статье показано, как настроить заголовок для приложений, использующих пакет SDK для приложений Windows, либо без WinUI 3. Сведения о приложениях, использующих UWP и WinUI 2, см. в разделе "Настройка строки заголовка" для UWP.

Компоненты строки заголовка

В этом списке описываются компоненты стандартной строки заголовка.

  • Прямоугольник строки заголовка
  • Текст заголовка
  • Значок системы
  • Системное меню: доступ к ней, щелкнув значок приложения или щелкнув правой кнопкой мыши строку заголовка
  • Элементы управления субтитрами
    • Кнопка "Свернуть"
    • Кнопка "Развернуть"/ "Восстановить"
    • Кнопка "Закрыть"

Оконное расширение

Функции окна в пакете SDK для приложений Windows проходят через класс Microsoft.UI.Windowing.AppWindow , основанный на модели Win32 HWND. Существует сопоставление 1:1 между AppWindow и HWND верхнего уровня в приложении. AppWindow и его связанные классы предоставляют API, которые позволяют управлять многими аспектами окон верхнего уровня приложения, включая настройку строки заголовка. Вы можете изменить строку заголовка по умолчанию, предоставляемую Windows, чтобы она смешивается с остальной частью пользовательского интерфейса, или расширить холст приложения в области заголовков и предоставить собственное содержимое строки заголовка.

Функции окна в WinUI 3 предоставляются через класс Microsoft.UI.Xaml.Window , который также основан на модели Win32 HWND. Для приложений XAML, использующих WinUI 3, API окна XAML предоставляют более простой способ настройки строки заголовка, при этом вы по-прежнему предоставляете доступ к API AppWindow при необходимости.

Как работать с AppWindow

Api AppWindow можно использовать с любой платформой пользовательского интерфейса, поддерживающей пакет SDK для приложений Windows : Win32, WPF, WinForms или WinUI 3, и их можно применять постепенно, используя только необходимые API.

Если вы используете WinUI 3 XAML в качестве платформы пользовательского интерфейса приложения, вам доступны интерфейсы API Window и AppWindow . Начиная с пакета SDK для приложений Windows 1.4, окно XAML и AppWindow используют тот же объект AppWindowTitleBar для настройки строки заголовка. Используйте свойство Window.AppWindow, чтобы получить объект AppWindow из существующего окна XAML. С помощью этого объекта AppWindow у вас есть доступ к API настройки строки заголовка. Чтобы получить доступ к дополнительным функциям строки заголовков, можно использовать API AppWindow из окна XAML, как показано ниже AppWindow.TitleBar.ForegroundColor = Colors.White;.

Если вы не используете WinUI 3 1.3 или более поздней версии, используйте API взаимодействия, чтобы получить AppWindow и использовать API AppWindow для настройки строки заголовка. Дополнительные сведения об API взаимодействия см. в разделе "Управление окнами приложений " Платформа пользовательского интерфейса и взаимодействие HWND " и пример коллекции окон.

Сколько нужно настроить строку заголовка

Существует два уровня настройки, которые можно применить к строке заголовка: применение незначительных изменений к строке заголовка по умолчанию или расширение холста приложения в области заголовка и предоставление полностью настраиваемого содержимого.

Простая

Для простой настройки, например изменение цвета строки заголовка, можно задать свойства объекта AppWindowTitleBar, чтобы указать цвета, которые вы хотите использовать для элементов строки заголовка. В этом случае система несет ответственность за все остальные аспекты строки заголовка, например рисование названия приложения и определение областей перетаскивания.

Полностью

Другой вариант — скрыть строку заголовка системы по умолчанию и заменить ее собственным пользовательским содержимым. Например, можно разместить текст, поле поиска или настраиваемые меню в области заголовка. Кроме того, вам потребуется использовать этот параметр для расширения материального фона, например Мика, в область заголовка.

При выборе полной настройки вы несете ответственность за размещение содержимого в области заголовков, и вы можете определить собственные области перетаскивания. Элементы управления субтитрами (системные кнопки закрытия, свертывания и развертывания) по-прежнему доступны и обрабатываются системой, но элементы, такие как название приложения, не являются. Вам потребуется создать эти элементы самостоятельно при необходимости в приложении.

Простая настройка

Если вы хотите настроить только заголовок, цвета или значок заголовка, можно задать свойства в объекте строки заголовка для окна приложения.

Заголовок

По умолчанию в строке заголовка отображается тип приложения в качестве заголовка окна (например, "WinUI Desktop"). Необходимо обновить заголовок окна, чтобы отобразить понятное отображаемое имя приложения.

Приложение XAML имеет отображаемое имя, заданное Package.appxmanifest в файле. Это значение можно получить и использовать для задания Title свойства следующим образом.

Title = AppInfo.Current.DisplayInfo.DisplayName;

Чтобы изменить заголовок окна, задайте свойству Window.Title значение однострочного текста, как показано ниже.

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

Чтобы изменить заголовок окна с помощью API AppWindow, задайте свойству AppWindow.Title значение однострочного текста, как показано здесь. В этом примере показано, как использовать API взаимодействия для получения AppWindow, который необходим для приложения, не использует WinUI 3 1.3 или более поздней версии.

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

Цвета

Чтобы настроить цвета строк заголовка по умолчанию или изменить значок окна по умолчанию, необходимо использовать API AppWindow или полностью настроить строку заголовка.

В этом примере показано, как получить экземпляр AppWindowTitleBar и задать его свойства цвета.

Внимание

Настройка цвета игнорируется при запуске приложения в 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;
}

При настройке цветов строки заголовка следует учитывать несколько действий.

  • Цвет фона кнопки не применяется к наведении указателя кнопки закрытия и нажатии состояний. Кнопка закрытия всегда использует системный цвет для этих состояний.
  • Задание свойства цвета для null сброса его на системный цвет по умолчанию.
  • Не удается задать прозрачные цвета. Альфа-канал цвета игнорируется.

Windows предоставляет пользователю возможность применить выбранный цвет акцента к строке заголовка. Если вы задаете любой цвет строки заголовка, рекомендуется явно задать все цвета. Это гарантирует отсутствие непреднамеренных сочетаний цветов из-за пользовательских параметров цвета.

Значок и системное меню

Вы можете скрыть значок системы или заменить его пользовательским значком. Значок системы отображает системное меню при щелчке правой кнопкой мыши или касании один раз. Он закрывает окно при двойном щелчке или нажатии.

Чтобы отобразить или скрыть системный значок и связанные с ним действия, задайте свойство панели заголовка IconShowOptions .

m_TitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu;

Чтобы использовать пользовательский значок окна, вызовите один из методов AppWindow.SetIcon , чтобы задать новый значок.

Полная настройка

При выборе полной настройки строки заголовка клиентская область приложения расширяется, чтобы охватывать все окно, включая область заголовка. Вы несете ответственность за рисование и обработку входных данных для всего окна, кроме кнопок заголовка, которые по-прежнему предоставляются окном.

Чтобы скрыть строку заголовка системы и расширить содержимое в области заголовка, задайте для свойства, которое расширяет содержимое приложения в области trueзаголовков. В приложении XAML это свойство можно задать в методе приложения OnLaunched (App.xaml.cs) или на первой странице приложения.

Совет

Ознакомьтесь с разделом "Полный пример настройки", чтобы просмотреть весь код одновременно.

В этом примере показано, как задать для свойства Window.ExtendsContentIntoTitleBar значение true.

public MainWindow()
{
    this.InitializeComponent();

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

Внимание

ExtendsContentIntoTitleBar отображается в коде XAML IntelliSense для Window, но при настройке в XAML возникает ошибка. Задайте это свойство в коде.

В этом примере показано, как получить AppWindowTitleBar и задать для свойства AppWindowTitleBar.ExtendsContentIntoTitleBar значениеtrue. В этом примере показано, как использовать API взаимодействия для получения AppWindow, который необходим, если приложение не использует WinUI 3 1.3 или более поздней версии.

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

Содержимое строки заголовка и область перетаскивания по умолчанию

Когда приложение распространяется на область заголовков, вы отвечаете за определение пользовательского интерфейса и управление ими для строки заголовка. Обычно это включает в себя, как минимум, указание текста заголовка и области перетаскивания. Область перетаскивания в строке заголовка определяет, где пользователь может щелкнуть и перетащить его, чтобы переместить окно вокруг. Кроме того, пользователь может щелкнуть правой кнопкой мыши, чтобы отобразить системное меню.

Дополнительные сведения о допустимом содержимом строки заголовка и рекомендуемых шаблонах пользовательского интерфейса см. в разделе "Конструктор заголовков".

В этом примере показан XAML для пользовательского пользовательского интерфейса строки заголовка без интерактивного содержимого.

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

Внимание

RightPaddingColumn Они LeftPaddingColumn используются для резервирования места для кнопок заголовка. Значения Width этих столбцов задаются в коде, который отображается позже. См. раздел "Кнопки заголовка системы" для кода и объяснения.

Приложение XAML имеет отображаемое имя, заданное в файле Package.appxmanifest. Это значение можно получить и использовать в пользовательской строке заголовка, как показано ниже.

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

При расширении содержимого в области заголовка строка заголовка скрыта, и создается панель заголовка по умолчанию AppWindowTitleBar , которая предоставляет кнопки заголовка и область перетаскивания по ширине экрана, идентичной строке заголовка системы. Если в строке заголовка не помещается интерактивное содержимое, можно оставить этот регион перетаскивания по умолчанию как есть. Если вы размещаете интерактивное содержимое в строке заголовка, необходимо указать регионы, которые являются интерактивными, которые мы рассмотрим в следующем разделе.

Внимание

При определении настраиваемых областей перетаскивания они не должны находиться в верхней части окна в области заголовка по умолчанию; Вы можете определить любую часть пользовательского интерфейса в виде области перетаскивания. Однако размещение регионов перетаскивания в разных местах может затруднить обнаружение пользователей.

Интерактивное содержимое

Интерактивные элементы управления, такие как кнопки, меню или поле поиска, можно разместить в верхней части приложения, чтобы они отображались в строке заголовка. Однако необходимо указать, какие регионы являются интерактивными, чтобы интерактивные элементы получали входные данные пользователей, позволяя пользователям перемещать окно вокруг.

Приложение Windows с полем поиска в строке заголовка

При добавлении интерактивного содержимого в область заголовка необходимо использовать класс InputNonClientPointerSource , чтобы указать области, в которых входные данные передаются в интерактивный элемент управления, а не обрабатываются строкой заголовков. Чтобы задать интерактивные регионы, вызовите метод InputNonClientPointerSource.SetRegionRects . Этот метод принимает значение, указывающее тип заданного региона (в данном случае Passthrough), а также массив прямоугольников, каждый из которых определяет Passthrough регион. При изменении размера строки заголовка необходимо пересчитывать интерактивные регионы, чтобы соответствовать новому размеру, и вызывать SetRegionRects с новыми значениями.

В этом примере показан пользовательский пользовательский интерфейс строки заголовка с полем поиска и элементом управления учетной записью PersonPicture. В нем показано, как вычислить и задать интерактивные прямоугольники для этих элементов управления, чтобы входные данные передаются в них.

Ниже приведены некоторые важные моменты, которые следует заметить об этом коде:

  • AppTitleBar Задайте для сетки высоту 48, чтобы следовать руководству по проектированию заголовка для интерактивного содержимого.
  • Задайте значение PreferredHeightOptionTall, чтобы кнопки заголовка были той же высотой, что и строка заголовка.
  • Чтобы упростить изменение размера элементов управления и вычисление регионов, используйте Grid несколько именованных столбцов для макета.
  • Используйте размер MinWidth звездочки (*) для столбца, содержащего AutoSuggestBox значение, чтобы он автоматически изменял размер окна.
  • Установите для MinWidth RightDragColumn резервирования небольшую область, которая всегда перетаскивается даже при изменении размера окна.
  • Установите значение ExtendsContentIntoTitleBar true в конструкторе MainWindow. Если задать его в коде, который вызывается позже, сначала может отображаться строка заголовка системы по умолчанию, а затем скрыта.
  • Выполните начальный вызов для вычисления интерактивных регионов после AppTitleBar загрузки элемента. В противном случае не гарантируется, что элементы, используемые для вычисления, будут иметь правильные значения.
  • Обновите интерактивные вычисления прямоугольника только после AppTitleBar изменения размера элемента (AppTitleBar_SizeChanged). Если вы зависите от события окна Changed , будут ситуации (например, максимальное или свернутое окно), где событие происходит до AppTitleBar изменения размера, и вычисления будут использовать неверные значения.
  • Задайте настраиваемые области перетаскивания и интерактивных областей только после проверки ExtendsContentIntoTitleBar того, что используется настраиваемая строка заголовка.
<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>

В этом коде показано, как вычислить и задать интерактивные регионы, соответствующие элементам управления AutoSuggestBox и 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)
        );
    }
}

Предупреждение

AppWindow использует физические пиксели для совместимости с платформами пользовательского интерфейса, которые не используют логические координаты. Если используется WPF или WinUI 3, RightInsetLeftInsetи значения, используемые для вычисления регионов, необходимо настроить, если шкала отображения не составляет 100 %. В этом примере мы получаем scaleAdjustment значение для учета параметра масштабирования отображения.

Кнопки заголовка системы

Система резервирует левый или правый верхний угол окна приложения для кнопок заголовка системы (свернуть, развернуть или восстановить, закрыть). Система сохраняет контроль над областью кнопки заголовка, чтобы гарантировать, что минимальные функциональные возможности предоставляются для перетаскивания, минимизации, максимизации и закрытия окна. Система рисует кнопку "Закрыть" в правом верхнем углу для языков слева направо и в левом верхнем углу для языков справа налево.

Содержимое можно нарисовать под областью управления заголовками, например фон приложения, но не следует помещать пользовательский интерфейс, с которым пользователь сможет взаимодействовать. Он не получает никаких входных данных, так как входные данные для элементов управления заголовками обрабатываются системой.

В этих строках из предыдущего примера показаны столбцы заполнения в XAML, определяющие строку заголовка. Использование столбцов заливки вместо полей гарантирует, что фон закрашивает область под кнопками элемента управления заголовком (для прозрачных кнопок). Использование столбцов с заполнением вправо и влево гарантирует правильность работы строки заголовка в макетах справа налево и слева направо.

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

Размеры и положение области управления заголовками передаются классом AppWindowTitleBar , чтобы вы могли учесть его в макете пользовательского интерфейса строки заголовка. Ширина зарезервированной области на каждой стороне определяется свойствами LeftInset или RightInset , а высота — свойством Height .

Ниже показано, как ширина столбцов заполнения указывается при вычислении и установке областей перетаскивания.

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

Внимание

См. важные сведения в разделе интерактивного содержимого о том, как отображение масштабирования влияет на эти значения.

Поддержка высокой строки заголовка для настраиваемых строк заголовков

При добавлении интерактивного содержимого, например поля поиска или изображения человека в строке заголовка, рекомендуется увеличить высоту строки заголовка, чтобы обеспечить больше места для этих элементов. Более высокая строка заголовка также упрощает обработку касания. Свойство AppWindowTitleBar.PreferredHeightOption позволяет увеличить высоту строки заголовка с стандартной высоты, которая является стандартной высотой до высоты выше. При выборе Tall режима заголовка заголовок кнопки заголовка, которые система рисует как наложение в клиентской области, отображаются выше с их минимальной или максимальной/закрывающей глифами по центру. Если вы не указали область перетаскивания, система нарисует ту, которая расширяет ширину окна и высоту, определяемую PreferredHeightOption заданным значением.

В этом примере показано, как задать PreferredHeightOption свойство.

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

Внимание

Свойство AppWindowTitleBar.ExtendsContentIntoTitleBar должно быть true перед настройкой PreferredHeightOption свойства. Если вы пытаетесь задать PreferredHeightOption время ExtendsContentIntoTitleBar false, создается исключение.

Цвет и прозрачность кнопок заголовка

Когда вы расширяете содержимое приложения в области заголовков, вы можете сделать фон кнопок заголовка прозрачным, чтобы разрешить фоновому просмотру приложения. Обычно фон устанавливается на Colors.Transparent для полной прозрачности. Для частичной прозрачности задайте альфа-канал для цвета , для которого задано свойство.

Эти свойства строки заголовка могут быть прозрачными:

Все остальные свойства цвета будут игнорировать альфа-канал. Если ExtendsContentIntoTitleBar задано значение false, альфа-канал всегда игнорируется для всех AppWindowTitleBar свойств цвета.

Цвет фона кнопки не применяется к наведении указателя мыши на кнопку "Закрыть" и нажатием состояний. Кнопка закрытия всегда использует системный цвет для этих состояний.

Совет

Мика является восхитительным материалом , который помогает отличить окно, которое находится в фокусе. Мы рекомендуем использовать его в качестве фона для долгоживущие окна в Windows 11. Если вы применили Мику в клиентской области окна, вы можете расширить его в области заголовка и сделать кнопки подписи прозрачными для мики, чтобы показать. Дополнительные сведения см . в материале Mica.

Сведите заголовок, если окно неактивно

Вы должны сделать его очевидным, если окно активно или неактивно. Как минимум, необходимо изменить цвет текста, значков и кнопок в строке заголовка.

Для приложений XAML обработайте событие Window.Activated , чтобы определить состояние активации окна и обновить пользовательский интерфейс строки заголовка по мере необходимости.

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

Для других платформ пользовательского интерфейса обработайте событие, чтобы определить состояние активации окна и обновить пользовательский интерфейс строки заголовка по мере необходимости. Определение состояния окна зависит от платформы пользовательского интерфейса, используемой для приложения.

Сброс строки заголовка

Чтобы сбросить или переключиться на строку заголовка системы во время работы приложения, можно вызвать AppWindowTitleBar.ResetToDefault.

m_AppWindow.TitleBar.ResetToDefault();

Для приложений XAML можно также сбросить заголовок следующим образом:

  • Вызовите SetTitleBar , чтобы переключиться на новый элемент строки заголовка во время работы приложения.
  • Вызов SetTitleBar с null параметром для сброса в области перетаскивания по умолчанию AppWindowTitleBar .
  • Вызовите SetTitleBar с null параметром и задайте ExtendsContentIntoTitleBar , чтобы false вернуться к строке заголовка системы по умолчанию.

Отображение и скрытие строки заголовка

Если в приложение добавлена поддержка полноэкранных или компактных режимов наложения , может потребоваться внести изменения в строку заголовка, когда приложение переключается между этими режимами. Окно XAML не предоставляет интерфейсы API для поддержки полноэкранного режима; Для этого можно использовать API AppWindow.

Когда приложение работает в полноэкранном режиме , система скрывает кнопки управления заголовками и заголовками. Вы можете обработать событие AppWindow.Change и проверить свойство event args DidPresenterChange , чтобы определить, следует ли отображать, скрывать или изменять заголовок в ответ на новую презентацию окна.

В этом примере показано, как обрабатывать Changed событие для отображения и скрытия AppTitleBar элемента из предыдущих примеров. Если окно помещается в компактный режим наложения, заголовок сбрасывается на строку заголовка по умолчанию (или можно предоставить настраиваемую строку заголовка, оптимизированную для компактного наложения ).

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

Примечание.

Режимы полноэкранного и компактного наложения можно вводить только в том случае, если оно поддерживается приложением. Дополнительные сведения см. в разделе "Управление окнами приложений", FullScreenPresenter и CompactOverlayPresenter.

Что рекомендуется и что не рекомендуется делать

  • Убедитесь, что окно активно или неактивно. Как минимум, измените цвет текста, значков и кнопок в строке заголовка.
  • Определите область перетаскивания вдоль верхнего края холста приложения. Сопоставление с размещением строк заголовков системы упрощает поиск пользователей.
  • Определите область перетаскивания, соответствующую визуальной строке заголовка (при наличии) на холсте приложения.

Полный пример настройки

В этом примере показан весь код, описанный в разделе полной настройки.

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