語言
Windows 應用程式 SDK提供 Microsoft.UI.Windowing.AppWindow 類別,代表 HWND 的高階抽象。 你的應用程式中的AppWindow 與最上層 HWND 之間有 1:1 對應。 AppWindow 及其相關類別提供 API,可讓您管理應用程式最上層視窗的許多層面,而不需要直接存取 HWND。
備註
本文示範如何在應用程式中使用 AppWindow API。 作為必要條件,我們建議您閱讀並理解 AppWindow WinUI 3 和 Windows 應用程式 SDK 的 Windowing 概覽 中的信息,無論您使用 WinUI 或其他 UI 框架,皆適用此信息。
- 重要 API: AppWindow 類別、 OverlappedPresenter 類別
![]()
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。
- 如果您根據Window或中的描述保留對Window的參考,您可以先取得,然後從 Window中取得AppWindow。
- 或者,您可以呼叫靜態 AppWindow.GetFromWindowId 方法來獲取 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 衍生的呈現器已提供,而且可在所有支援的作業系統版本上使用。
-
設定固定大小、置頂的視窗,並以 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。
此範例展示了如何執行以下步驟:
- AppWindow使用 Presenter 屬性來取得目前的呈現器。
- 使用 AppWindowPresenter.Kind 屬性來檢查目前套用的組態種類。
- 呼叫 AppWindow.SetPresenter 以變更目前的組態。
在這裡,呈現器會在視窗的建構函式中被建立、修改和套用。
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 物件的配方:
- 如果您還沒有它,請擷取現有窗口物件的HWND(適用於 UI 架構)。
- 將 HWND 傳遞至 GetWindowIdFromWindow Interop 函式以擷取 WindowId。
- 將 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 的方法。