共用方式為


管理應用程式視窗

Windows App SDK 提供 Microsoft.UI.Windowing.AppWindow 類別,代表 HWND 的高階抽象概念。 你的應用程式中的AppWindow 與最上層 HWND 之間有 1:1 對應。 AppWindow 及其相關類別提供 API,可讓您管理應用程式最上層視窗的許多層面,而不需要直接存取 HWND。

備註

本文示範如何在應用程式中使用 AppWindow API。 作為必要條件,我們建議您閱讀並瞭解 AppWindowWinUI 和 Windows App SDK 的 Windowing 概觀中的資訊,無論您使用 WinUI 或其他 UI 架構,都適用。

WinUI 3 Gallery 應用程式包含大部分 WinUI 3 控制項、特性和功能的互動式範例。 從 Microsoft Store 取得應用程式,或在 GitHub 上取得原始程式碼

您可以搭配 Windows App SDK 支援的任何 UI 架構使用 AppWindow API - WinUI 3、WPF、WinForms 或 Win32。 AppWindow API 會與架構特定的視窗化 API 搭配運作:

您通常會使用 AppWindow API 來:

  • 管理應用程式視窗的大小和位置。

  • 管理視窗標題、圖示和標題列色彩;或使用 AppWindowTitleBar API建立完全自定義標題列。

    如需詳細資訊和範例,請參閱 標題欄自定義

  • 使用 AppWindowPresenter 衍生的 API 來管理視窗的外觀和行為。

回應AppWindow的變更

您會透過處理單一 AppWindow 事件來回應的變更,然後檢查事件參數(AppWindowChangedEventArgs)以判斷發生的變更類型。 如果您關注的變更已發生,您可以對其作出回應。 潛在的變更包括位置、大小、呈現者、可見性和迭置順序。

以下是 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 有數個屬性和方法,可用來管理視窗的大小和位置。

類別 屬性
唯讀屬性 PositionSizeClientSize
活動 已變更DidPositionChangeDidSizeChange
大小和位置方法 MoveResize、ResizeClientMoveAndResize
Z 順序方法 MoveInZOrderAtBottomMoveInZOrderAtTopMoveInZOrderBelow

呼叫 Resize 以指定新的視窗大小。

在此範例中,程式代碼位於 中 MainWindow.xaml.cs,因此您可以使用 Window.AppWindow 屬性來取得 AppWindow 實例。

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

呼叫 Move 方法以變更視窗的位置。

本範例會在使用者按鍵時,將視窗置中於畫面上。

這發生在 Page 類別的程式代碼檔案中,因此您不會自動存取 WindowAppWindow 物件。 您有幾個選項可用來取得 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,但您可以將它變更為 MediumLarge。 您也可以呼叫 AppWindow。Resize 來覆寫 16:9 長寬比,讓視窗調整為任何所需的大小。

  • 全螢幕簡報者

    設定視窗以提供適合觀看影片的全螢幕體驗。 視窗沒有框線或標題列,並隱藏系統任務列。

  • 重疊的簡報者

    標準視窗組態預設會提供具有重設大小控點的框線,以及具有最小化/最大化/還原按鈕的標題列。

備註

作為 Win32 應用程式模型的新概念,presenter 類似於視窗狀態和 樣式的組合,但並不相同。 有些演示者也有定義的行為,無法從傳統視窗狀態和樣式屬性進行檢查(例如自動隱藏標題列)。

默認演示者

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

OverlappedPresenter 是彈性演示者,您可以透過各種方式進行設定。

Create* 方法可讓您建立具有預設屬性設定的重疊演示者,或建立一個屬性設定已預先配置以用於特定用途的重疊演示者。

下表顯示當您從每個方法建立重疊Presenter 物件時,如何設定組態屬性。

房產 Create CreateForContextMenu CreateForDialog CreateForTool視窗
HasBorder true true true true
HasTitleBar true false true true
是永遠在頂部 false false false false
可最大化 true false false true
可最小化 true false false true
是模態 false false false false
可調整大小 true false false true

套用的演示者是實時物件。 對AppWindow.Presenter 物件的任何屬性進行變更會立即生效。 沒有任何事件可通知您這些變更,但您可以隨時檢查目前值的屬性。

HasBorderHasTitleBar 屬性是唯讀的。 您可以呼叫 SetBorderAndTitleBar 方法 (SetBorderAndTitleBar(bool hasBorder, bool hasTitleBar)) 來設定這些值。 重疊Presenter 不能有沒有框線的標題欄。 也就是說,如果 hasTitleBar 參數是 true,則 hasBorder 參數也必須是 true。 否則,將擲出例外狀況並顯示此訊息:

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

IsMaximizable 設定為 false ,以隱藏工具列中的最大化按鈕。 如果您設定 PreferredMaximumHeightPreferredMaximumWidth 屬性,建議您這樣做,因為這些屬性會限制視窗大小,即使處於最大化狀態也一樣。 這不會影響 對 Maximize 方法的呼叫。

IsMinimizable 設定為 false ,以隱藏工具列中的最小化按鈕。 這不會影響對 Minimize 方法的呼叫。

IsResizable 設定為 false 以隱藏重設大小控制件,並防止使用者調整視窗大小。 這不會影響對 AppWindow.Resize 方法的呼叫。

IsAlwaysOnTop 設定為 , true 讓此視窗保持在其他視窗之上。 如果您呼叫任何 AppWindow.MoveInZOrder* 方法,它們仍會生效,以變更視窗的迭置順序,即使此屬性為 true

PreferredMaximumHeightPreferredMaximumWidth 設定為限制使用者可以延展視窗的大小上限。 如果您設定大小上限屬性,建議您將 設定 IsMaximizablefalse ,因為這些屬性會限制視窗大小,即使處於最大化狀態也一樣。 這些屬性也會影響 對的 AppWindow呼叫。重設大小;視窗的大小不會大於指定的最大高度和寬度。

PreferredMinimumHeightPreferredMinimumWidth 設定為使用者可以壓縮視窗的大小下限。 這些屬性也會影響 對的 AppWindow呼叫。重設大小;視窗的大小不會小於指定的最小高度和寬度。

您可以將 IsModal 設定為 true 以建立 模態視窗。 模態視窗是獨立的視窗,會封鎖與其擁有者視窗的互動,直到關閉為止。 不過,若要建立模態視窗,您也必須設定擁有者視窗。否則,系統會拋出例外並顯示此訊息:

The parameter is incorrect.

The window should have an owner when IsModal=true.

若要在 WinUI 應用程式中設定擁有者視窗,需要 Win32 Interop。 如需詳細資訊和範例程式代碼,請參閱 AppWindow WinUI 資源庫範例應用程式中的頁面。

套用簡報模式

一個簡報者只能同時應用於一個視窗。 嘗試將相同的呈現器套用到第二個視窗時會拋出例外狀況。 這表示如果您有多個視窗,而且您想要將每個視窗切換成特定的簡報模式,則需要建立相同類型的多個演示者,然後將每個演示者套用至自己的視窗。

套用新的簡報者時(AppWindow.簡報者屬性改變),您的應用程式會透過受影響的AppWindow上的事件收到通知,並且將AppWindow屬性設為

小提示

如果您套用了經過修改的顯示器,並允許在顯示器之間進行切換,請務必保留已修改顯示器的參照,以便將其重新套用至 AppWindow

此範例示範如何執行下列動作:

在這裡,呈現器會在視窗的建構函式中被建立、修改和套用。

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

在視窗內容的 Page 中,您可以取得 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);
    }
}

UI 框架和 HWND Interop

類別 AppWindow 適用於您應用程式內任意頂層 HWND。 這表示當您使用桌面 UI 架構(包括 WinUI 3)時,您可以繼續使用該架構的進入點來建立視窗,並附加其內容。 一旦您使用該 UI 架構建立窗口之後,就可以使用 Windows App SDK 中提供的視窗化 Interop 函式,來存取對應的 AppWindow 及其方法、屬性和事件。

有些使用AppWindow(即使在使用 UI 架構時)的好處是:

  • 簡單的標題列自訂;預設會維持 Windows 11 的使用者介面風格(包含圓角與貼齊群組彈出視窗功能)。
  • 系統提供的全螢幕與精簡畫中畫體驗。
  • Windows 執行階段 (WinRT) API 介面,適用於部分核心 Win32 視窗化概念。

AppWindow取得 1.3 之前的 Windows App SDK 版本(或其他傳統型應用程式架構)

.WindowAppWindow屬性適用於 Windows App SDK 1.3 版和更新版本。 對於舊版,您可以使用在本節中功能等同的程式碼範例。

C#. .NET 包裝函式針對視窗化互操作功能實作為 Microsoft.UI.Win32Interop 類別的方法。 另請參閱從 .NET 應用程式呼叫 Interop API

C++ Interop 函式定義於 winrt/Microsoft.ui.interop.h 標頭檔案中。

下列程式代碼範例區段顯示實際的原始程式碼;但以下是針對現有視窗擷取 AppWindow 物件的配方:

  1. 如果您還沒有它,請擷取現有窗口物件的HWND(適用於 UI 架構)。
  2. 將 HWND 傳遞至 GetWindowIdFromWindow Interop 函式以擷取 WindowId
  3. 將 WindowId 傳遞至靜態 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 資源庫範例

局限性

Windows App SDK 目前不提供將 UI 架構內容附加至 AppWindow的方法。