Поделиться через


Управление окнами приложений

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

Замечание

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

Приложение Галерея WinUI 3 включает интерактивные примеры большинства элементов управления, особенностей и возможностей WinUI 3. Получение приложения из Microsoft Store или получение исходного кода на GitHub

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

Обычно вы используете API AppWindow для:

  • Управление размером и положением окна приложения.

  • Управление цветом заголовка окна, значка и заголовка; или создайте полностью настраиваемую строку заголовка с помощью API AppWindowTitleBar .

    Дополнительные сведения и примеры см. в разделе "Настройка строки заголовка ".

  • Управление внешним видом и поведением окна с помощью интерфейсов API, производных от AppWindowPresenter.

Реагируйте на изменения AppWindow

Вы реагируете на изменения AppWindow , обрабатывая одно событие Change , а затем проверяете значения событий (AppWindowChangedEventArgs), чтобы определить, какой вид изменений произошел. Если произошло изменение, которое вас интересует, вы можете ответить на него. Возможные изменения включают положение, размер, презентер, видимость и z-порядок.

Вот пример обработчика события для AppWindow.Changed.

private void AppWindow_Changed(AppWindow sender, AppWindowChangedEventArgs args)
{
    // ConfigText and SizeText are TextBox controls defined in XAML for the page.
    if (args.DidPresenterChange == true)
    {
        ConfigText.Text = sender.Presenter.Kind.ToString();
    }

    if (args.DidSizeChange == true)
    {
        SizeText.Text = sender.Size.Width.ToString() + ", " + sender.Size.Height.ToString();
    }
}

Window размер и размещение

Класс AppWindow имеет несколько свойств и методов, которые можно использовать для управления размером и размещением окна.

Категория Свойства
Свойства только для чтения Положение, Размер, Размер клиента
Events Изменено (DidPositionChange, DidSizeChange)
Методы размера и положения Move, Resize, ResizeClient, MoveAndResize
Методы Z-order ПереместитьПоПорядкуВниз, ПереместитьПоПорядкуВверх, ПереместитьПоПорядкуНиже

Вызовите изменение размера, чтобы указать новый размер окна.

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

public MainWindow()
{
    InitializeComponent();
    AppWindow.Resize(new Windows.Graphics.SizeInt32(1200, 800));
}

Вызовите метод Move , чтобы изменить положение окна.

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

Это происходит в файле кода для класса Page, поэтому у вас нет автоматического доступа к объектам Window или AppWindow. У вас есть несколько опций для получения AppWindow.

private void MoveWindowButton_Click(object sender, RoutedEventArgs e)
{
    AppWindow appWindow = AppWindow.GetFromWindowId(XamlRoot.ContentIslandEnvironment.AppWindowId);
    RectInt32? area = DisplayArea.GetFromWindowId(appWindow.Id, DisplayAreaFallback.Nearest)?.WorkArea;
    if (area == null) return;
    appWindow.Move(new PointInt32((area.Value.Width - appWindow.Size.Width) / 2, (area.Value.Height - appWindow.Size.Height) / 2));
}

Класс AppWindowPresenter и подклассы

К нему AppWindow применяется AppWindowPresenter (выступающий). Презентатор создается системой и применяется к AppWindow во время создания. Каждый подкласс AppWindowPresenter предоставляет предварительно определенную конфигурацию, соответствующую цели окна. Эти презентеры, производные от AppWindowPresenter, предоставляются и доступны на всех поддерживаемых версиях ОС.

  • CompactOverlayPresenter

    Настраивает окно всегда поверх других окон фиксированного размера с соотношением сторон 16:9, чтобы создать эффект картинка в картинке. По умолчанию InitialSizeCompactOverlaySize.Small, но вы можете изменить его на Medium или Large. Вы также можете вызвать AppWindow.Resize, чтобы переопределить пропорции 16:9 и сделать окно любым нужным размером.

  • FullScreenPresenter

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

  • ПерекрытиеPresenter

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

Замечание

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

Выступающий по умолчанию

По умолчанию применяется презентер, когда создается AppWindow, представляющий экземпляр OverlappedPresenter с настройками свойств по умолчанию. Нет необходимости хранить ссылку на него, чтобы вернуться к стандартному представителю для окна после применения другого представителя. Это связано с тем, что система сохраняет тот же экземпляр этого презентера на протяжении всего времени существования AppWindow, для которого он был создан; и вы можете повторно установить его, вызвав метод AppWindow.SetPresenter с AppWindowPresenterKind.Default в качестве параметра.

Это важно

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

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

appWindow.SetPresenter(AppWindowPresenterKind.Default);
OverlappedPresenter defaultPresenter = (OverlappedPresenter)appWindow.Presenter;
defaultPresenter.IsMaximizable = false;
defaultPresenter.IsMinimizable = false;

Изменение перекрывающегося презентера

OverlappedPresenter — это гибкий компонент, который можно настроить множеством способов.

Методы Create* позволяют создать перекрывающуюся презентацию с настройками свойств по умолчанию или с параметрами, подготовленными для конкретного использования.

В этой таблице показано, как задаются свойства конфигурации при создании объекта OverlappedPresenter из каждого метода.

Недвижимость Create CreateForContextMenu CreateForDialog CreateForToolWindow
HasBorder true true true true
HasTitleBar true false true true
IsAlwaysOnTop false false false false
IsMaximizable true false false true
IsMinimizable true false false true
IsModal false false false false
IsResizable true false false true

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

Свойства HasBorder и HasTitleBar доступны только для чтения. Эти значения можно задать, вызвав метод SetBorderAndTitleBar (SetBorderAndTitleBar(bool hasBorder, bool hasTitleBar)). Перекрывающийся Presenter не может иметь строку заголовка без границы. То есть, если hasTitleBar параметр имеет значение true, hasBorder то этот параметр также должен быть true. В противном случае создается исключение с этим сообщением:

The parameter is incorrect.
Invalid combination: Border=false, TitleBar=true.

Установите IsMaximizable в false, чтобы скрыть кнопку "Развернуть" на панели инструментов. Рекомендуем сделать это, если вы установите свойства PreferredMaximumHeight или PreferredMaximumWidth, поскольку эти свойства ограничивают размер окна даже в развернутом состоянии. Это не влияет на вызовы метода Развернуть.

Установите IsMinimizable в false для скрытия кнопки минимизации на панели инструментов. Это не влияет на вызовы метода Minimize.

Установите значение IsResizable на false, чтобы скрыть элементы управления изменением размера и запретить пользователю изменять размер окна. Это не влияет на вызовы метода AppWindow.Resize.

Установите IsAlwaysOnTop, чтобы true это окно оставалось поверх других окон. При вызове любого из AppWindow.MoveInZOrder* методов они всё равно вступают в силу и изменяют порядок слоёв окна, даже если это свойство true.

Задайте значение PreferredMaximumHeight и PreferredMaximumWidth , чтобы ограничить максимальный размер, к которому пользователь может растянуть окно. Рекомендуется задать IsMaximizablefalse значение, если заданы максимальные свойства размера, так как эти свойства ограничивают размер окна даже в максимальном состоянии. Эти свойства также влияют на вызовы AppWindow.Resize; окно не изменится до размера, превышающего указанную максимальную высоту и ширину.

Задайте PreferredMinimumHeight и PreferredMinimumWidth, чтобы установить минимальный размер окна, до которого пользователь может его уменьшить. Эти свойства также влияют на вызовы AppWindow.Resize; размер окна не будет уменьшен меньше указанной минимальной высоты и ширины.

Вы можете задать IsModal для true создания модального окна. Модальное окно — это отдельное окно, которое блокирует взаимодействие с родительским окном, пока не будет закрыто. Однако для создания модального окна необходимо также задать окно владельца; В противном случае исключение создается с этим сообщением:

The parameter is incorrect.

The window should have an owner when IsModal=true.

Чтобы задать окно владельца в приложении WinUI, требуется взаимодействие Win32. Дополнительные сведения и пример кода см. на AppWindow странице примера приложения Галереи WinUI.

Назначить докладчика

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

При применении нового презентера (свойство .Presenter изменяется), ваше приложение уведомляется событием .Changed на соответствующем , при этом свойству AppWindowChangedEventArgs.DidPresenterChange задано значение .

Подсказка

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

В этом примере показано, как выполнить следующие действия:

Здесь презентер создается, изменяется и применяется в конструкторе окна.

OverlappedPresenter presenter = OverlappedPresenter.Create();
presenter.PreferredMinimumWidth = 420;
presenter.PreferredMinimumHeight = 550;
AppWindow.SetPresenter(presenter);

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

AppWindow appWindow;
OverlappedPresenter modifiedPresenter;

private void AppWindowPage_Loaded(object sender, RoutedEventArgs e)
{
    appWindow = AppWindow.GetFromWindowId(XamlRoot.ContentIslandEnvironment.AppWindowId);
    modifiedPresenter = (OverlappedPresenter)appWindow.Presenter;

    appWindow.Changed += AppWindow_Changed;
}

private void AppWindow_Changed(AppWindow sender, AppWindowChangedEventArgs args)
{
    if (args.DidPresenterChange)
    {
        // ConfigText is a TextBox control defined in XAML for the page.
        ConfigText.Text = appWindow.Presenter.Kind.ToString();
    }
}

private void CompactOverlayButton_Click(object sender, RoutedEventArgs e)
{
    if (appWindow.Presenter.Kind != AppWindowPresenterKind.CompactOverlay)
    {
        appWindow.SetPresenter(CompactOverlayPresenter.Create());
        fullScreenButton.IsChecked = false;
    }
    else
    {
        appWindow.SetPresenter(modifiedPresenter);
    }
}

private void FullScreenButton_Click(object sender, RoutedEventArgs e)
{
    if (appWindow.Presenter.Kind != AppWindowPresenterKind.FullScreen)
    {
        appWindow.SetPresenter(FullScreenPresenter.Create());
        compactOverlayButton.IsChecked = false;
    }
    else
    {
        appWindow.SetPresenter(modifiedPresenter);
    }
}

Платформа пользовательского интерфейса и интероперабельность HWND

Класс AppWindow доступен для любого HWND верхнего уровня в приложении. Это означает, что при работе с платформой пользовательского интерфейса рабочего стола (включая WinUI 3), вы можете продолжать использовать точку входа этой платформы для создания окна и присоединения его содержимого. После создания окна с этой платформой пользовательского интерфейса можно использовать функции взаимодействия с окнами (см. ниже), предоставленные в пакете SDK для приложений Windows, для доступа к соответствующим AppWindow методам, свойствам и событиям.

Ниже приведены некоторые преимущества использования AppWindow (даже при работе с платформой пользовательского интерфейса):

  • Простая настройка строки заголовка; по умолчанию поддерживает интерфейс Windows 11 (округлённые углы, всплывающее окно групп привязки).
  • Возможности полноэкранного и компактного наложения (картинка в картинке) предоставляются системой.
  • Область API среды выполнения Windows (WinRT) для некоторых основных концепций окна Win32.

Получите AppWindow для версий Windows App SDK до 1.3 (или других платформ для классических приложений)

Свойство Window.AppWindow доступно в пакете SDK для приложений Windows версии 1.3 и более поздних версий. Для более ранних версий можно использовать функционально эквивалентный пример кода в этом разделе.

C#. Оболочки .NET для функций взаимодействия окна реализуются как методы класса Microsoft.UI.Win32Interop . Также см. API взаимодействия из приложения на платформе .NET.

C++. Функции взаимодействия определяются в файле заголовка winrt/Microsoft.ui.interop.h.

В приведенном ниже примере кода показан фактический исходный код; но вот рецепт получения объекта, заданного AppWindow существующим окном:

  1. Получите HWND для существующего объекта окна (для платформы пользовательского интерфейса), если у вас его еще нет.
  2. Передайте этот HWND в функцию интероперабельности GetWindowIdFromWindow, чтобы получить WindowId.
  3. Передайте этот WindowId в статический метод AppWindow.GetFromWindowId, чтобы получить AppWindow.
// MainWindow.xaml.cs
private void myButton_Click(object sender, RoutedEventArgs e)
{
    // Retrieve the window handle (HWND) of the current (XAML) WinUI 3 window.
    var hWnd =
        WinRT.Interop.WindowNative.GetWindowHandle(this);

    // Retrieve the WindowId that corresponds to hWnd.
    Microsoft.UI.WindowId windowId =
        Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd);

    // Lastly, retrieve the AppWindow for the current (XAML) WinUI 3 window.
    Microsoft.UI.Windowing.AppWindow appWindow =
        Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);

    if (appWindow != null)
    {
        // You now have an AppWindow object, and you can call its methods to manipulate the window.
        // As an example, let's change the title text of the window.
        appWindow.Title = "Title text updated via AppWindow!";
    }
}
// pch.h
#include "microsoft.ui.xaml.window.h" // For the IWindowNative interface.
#include <winrt/Microsoft.UI.Interop.h> // For the WindowId struct and the GetWindowIdFromWindow function.
#include <winrt/Microsoft.UI.Windowing.h> // For the AppWindow class.

// mainwindow.xaml.cpp
void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&)
{
    // Retrieve the window handle (HWND) of the current (XAML) WinUI 3 window.
    auto windowNative{ this->m_inner.as<::IWindowNative>() };
    HWND hWnd{ 0 };
    windowNative->get_WindowHandle(&hWnd);

    // Retrieve the WindowId that corresponds to hWnd.
    Microsoft::UI::WindowId windowId = 
        Microsoft::UI::GetWindowIdFromWindow(hWnd);

    // Lastly, retrieve the AppWindow for the current (XAML) WinUI 3 window.
    Microsoft::UI::Windowing::AppWindow appWindow = 
        Microsoft::UI::Windowing::AppWindow::GetFromWindowId(windowId);

    if (appWindow)
    {
        // You now have an AppWindow object, and you can call its methods to manipulate the window.
        // As an example, let's change the title text of the window.
        appWindow.Title(L"Title text updated via AppWindow!");
    }
}

Дополнительные примеры работы с AppWindow см. в примере галереи Windowing.

Ограничения

Пакет SDK для приложений Windows в настоящее время не предоставляет методы для присоединения содержимого платформы пользовательского интерфейса к объекту AppWindow.