語言

管理應用程式視窗

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

備註

本文示範如何在應用程式中使用 AppWindow API。 作為必要條件,我們建議您閱讀並理解 AppWindow WinUI 3 和 Windows 應用程式 SDK 的 Windowing 概覽 中的信息,無論您使用 WinUI 或其他 UI 框架,皆適用此信息。

WinUI 3 圖庫圖示 WinUI 3 圖庫應用程式包含互動式的 WinUI 控制項與功能範例。 你可以從 Microsoft Store下載 App,或在 GitHub 瀏覽原始碼。

你可以在 Windows 應用程式 SDK 支援的任何 UI 框架中使用 AppWindow API——WinUI、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 有數個屬性和方法,可用來管理視窗的大小和位置。

類別 屬性
唯讀屬性 Position、 Size、 ClientSize
活動 已變更 (DidPositionChange, DidSizeChange)
大小和位置方法 Move、Resize、ResizeClient、MoveAndResize
Z 順序方法 MoveInZOrderAtBottom、 MoveInZOrderAtTop、 MoveInZOrderBelow

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

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

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

以邏輯像素為單位設定視窗大小(實驗性)

這很重要

本節的Window尺寸屬性是 Windows 應用程式 SDK 2.3 Experimental A 中引入的實驗性 API。這些 API 標示為實驗性,未來版本可能會變更或移除。 不要在生產應用程式中使用它們。 下載連結請參閱 最新 Windows 應用程式 SDK 下載項目。

AppWindow.Resize 與 AppWindow。ResizeClient 會以實體像素來計算尺寸。 要在不同比例因子的顯示器上達到相同大小,你必須自己轉換這些數值。 在實驗性版本中,Microsoft.UI.Xaml.Window類別擁有屬性,能取得並設定視窗用戶端區域的邏輯像素大小,也稱為裝置無關像素(DIP)。 視窗會針對目前的顯示縮放比例轉換這些值,因此,Width 為 640 的客戶區域在 100% 縮放下寬度為 640 個實體像素,在 150% 縮放下寬度為 960 個實體像素。 你可以在 XAML 或程式碼中設定這些屬性,而不必經過 Window.AppWindow 屬性。

房產 Description
寬度, 高度 視窗恢復狀態時客戶端區域的大小。
最小寬度, 最小高度 使用者可以調整視窗大小的最小用戶端區域。 預設值是 0。
最大寬度, 最大高度 使用者可以調整視窗大小的最大用戶端區域。 預設值是正無限大,也就是說沒有最大值。

此範例設定了視窗的初始大小與大小限制。

<Window
    x:Class="MyApp.SettingsWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640"
    Height="480"
    MinWidth="320"
    MinHeight="240"
    MaxWidth="960"
    MaxHeight="720">
    <TextBlock Margin="24" Text="Resize this window." />
</Window>

這個範例在 C# 中為其在程式碼中建立的視窗設定相同的值。

Window window = new Window
{
    Width = 640,
    Height = 480,
    MinWidth = 320,
    MinHeight = 240,
    MaxWidth = 960,
    MaxHeight = 720,
    Content = new TextBlock { Margin = new Thickness(24), Text = "Resize this window." }
};

// A size that you set before the first call to Activate is applied when the window is shown.
window.Activate();

此表顯示 Window 屬性與 AppWindow 尺寸調整 API 的關聯。 例如,AppWindow.Resize(new SizeInt32(1200, 800)) 會將整個視窗(包括其邊框和標題列)設為 1200 x 800 的實體像素。 將 Height 設為 1200,並將 Width 設為 800 時,客戶端區域的邏輯像素大小為 1200 x 800,在 150% 縮放比例的顯示器上相當於 1800 x 1200 的實體像素。

API 它會調整哪些大小 單位
Window.寬度, Window.高度(實驗性) 已還原視窗的用戶端區域。 你可以取得並設定數值。 邏輯像素
Window.Bounds 目前的客戶區。 唯讀。 邏輯像素
AppWindow.調整尺寸 整個視窗,包括邊框和標題欄。 實體像素
AppWindow.ResizeClient 客戶區。 實體像素
AppWindow.大小, AppWindow.客戶端大小 目前的視窗和客戶區域。 唯讀。 物理像素

使用 Window 尺寸屬性時請記住以下行為:

  • 已還原大小。 當視窗被最大化或最小化時,Width 和 Height 會回傳視窗恢復時所回到的客戶端大小。 如果你把它們設在那個狀態,還原的大小會改變,視窗會保持最大化或最小化。 如果視窗使用 FullScreenPresenter 或 CompactOverlayPresenter,當視窗切回 OverlappedPresenter 時,會套用你設定的大小。
  • 大小限制。MinWidth、MinHeight、MaxWidth和MaxHeight會在視窗使用預設呈現器 OverlappedPresenter 時生效。 視窗會幫你設定展示者的 PreferredMinimumWidth、 PreferredMinimumHeight、 PreferredMaximumWidth和 PreferredMaximumHeight 屬性,當視窗切換到不同比例的顯示器時,這些屬性會被更新。 不要自己為透過 Window 屬性限制的維度設定那些 presenter 屬性。 欲了解更多關於呈現者的屬性,請參見 「修改重疊呈現者」。
  • 最大化大小。 像是呈現者的 PreferredMaximumWidth 和 PreferredMaximumHeight 屬性,MaxWidth 和 MaxHeight 屬性即使在視窗最大化時,也會限制視窗大小。 例如,從前面例子中最大化視窗時,其客戶端區域邏輯像素不大於 960 x 720 像素,即使在較大的顯示器上也是如此。
  • 有效值。 將 Height 和 Width 設定為介於最小與最大限制之間的數值。 Width、Height、MinWidth 和 MinHeight 都必須為有限值,且大於或等於 0。 MaxWidth 且 MaxHeight 必須為 0 或更大;若要表示沒有最大值,則可設為正無限大。 其他值會讓設定器拋出一個例外,在 C# 中為 ArgumentException。

AppWindowPresenter 類別和子類別

每個 AppWindow 都套用了 AppWindowPresenter。 呈現器由系統建立,並在創建時套用至 AppWindow 。 AppWindowPresenter 的每個子類別都提供適合視窗用途的預先定義組態。 這些 AppWindowPresenter 衍生的呈現器已提供,而且可在所有支援的作業系統版本上使用。

  • CompactOverlayPresenter

    設定固定大小、置頂的視窗,並以 16:9 的比例,以實現 畫中畫 的體驗。 根據預設, InitialSize 是 CompactOverlaySize.Small,但您可以將它變更為 Medium 或 Large。 您也可以呼叫 AppWindow。Resize 來覆寫 16:9 長寬比,讓視窗調整為任何所需的大小。

  • 全螢幕簡報者

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

  • 重疊的簡報者

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

備註

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

默認演示者

建立AppWindow時所套用的預設演示者是具有預設屬性設定的OverlappedPresenter實例。 在套用其他 presenter 之後,無需保留對視窗的引用,就可以回到預設的 presenter。 這是因為系統會在為 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 物件的任何屬性進行變更會立即生效。 沒有任何事件可通知您這些變更,但您可以隨時檢查目前值的屬性。

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 屬性,建議您這樣做,因為這些屬性會限制視窗大小,即使處於最大化狀態也一樣。 這不會影響 對 Maximize 方法的呼叫。

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

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

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

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

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

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

The parameter is incorrect.

The window should have an owner when IsModal=true.

若要在 WinUI 應用程式中設定擁有者視窗,需要 Win32 Interop。 更多資訊與範例程式碼,請參閱 AppWindow WinUI 3 圖庫範例應用程式中的頁面。

套用簡報模式

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

套用新的簡報者時(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)時,可以繼續使用該框架的入口來建立視窗並附加內容。 當你用該 UI 框架建立視窗後,你可以利用Windows 應用程式 SDK中提供的視窗互操作函數(見下方)存取對應的 AppWindow 及其方法、屬性和事件。

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

  • 標題列自訂簡單;預設情況下,它會維持 Windows 11 的使用者介面(圓角、快閃群組跳出)。
  • 系統提供的全螢幕與精簡畫中畫體驗。
  • Windows 執行階段(WinRT)API 表面,用於部分 Win32 核心視窗概念。

下載 AppWindow,適用於 1.3 之前的 Windows 應用程式 SDK 版本(或其他桌面應用框架)。

Window.AppWindow 屬性可在 1.3 版本及更新版本中Windows 應用程式 SDK提供。 對於舊版,您可以使用在本節中功能等同的程式碼範例。

C#. 視窗互操作函式的.NET包裝器以 Microsoft.UI.Win32Interop 類別的方法實作。 另請參閱 從 .NET 應用程式呼叫互操作 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 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 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 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 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 gallery 範例。

局限性

目前Windows 應用程式 SDK沒有提供將 UI 框架內容附加到 AppWindow 的方法。