Windows App SDK 提供 Microsoft.UI.Windowing.AppWindow 類別,代表 HWND 的高階抽象概念。 你的應用程式中的AppWindow 與最上層 HWND 之間有 1:1 對應。 AppWindow 及其相關類別提供 API,可讓您管理應用程式最上層視窗的許多層面,而不需要直接存取 HWND。
備註
本文示範如何在應用程式中使用 AppWindow API。 作為必要條件,我們建議您閱讀並瞭解 AppWindowWinUI 和 Windows App SDK 的 Windowing 概觀中的資訊,無論您使用 WinUI 或其他 UI 架構,都適用。
- 重要 API: AppWindow 類別、 OverlappedPresenter 類別
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 有數個屬性和方法,可用來管理視窗的大小和位置。
| 類別 | 屬性 |
|---|---|
| 唯讀屬性 | 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));
}
AppWindowPresenter 類別和子類別
每個 AppWindow 都套用了 AppWindowPresenter。 呈現器由系統建立,並在創建時套用至 AppWindow 。 AppWindowPresenter 的每個子類別都提供適合視窗用途的預先定義組態。 這些 AppWindowPresenter 衍生的呈現器已提供,而且可在所有支援的作業系統版本上使用。
-
設定固定大小、置頂的視窗,並以 16:9 的比例,以實現 畫中畫 的體驗。 根據預設, InitialSize 是 CompactOverlaySize.Small,但您可以將它變更為
Medium或Large。 您也可以呼叫 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 物件的任何屬性進行變更會立即生效。 沒有任何事件可通知您這些變更,但您可以隨時檢查目前值的屬性。
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 資源庫範例應用程式中的頁面。
套用簡報模式
一個簡報者只能同時應用於一個視窗。 嘗試將相同的呈現器套用到第二個視窗時會拋出例外狀況。 這表示如果您有多個視窗,而且您想要將每個視窗切換成特定的簡報模式,則需要建立相同類型的多個演示者,然後將每個演示者套用至自己的視窗。
套用新的簡報者時(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 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 物件的配方:
- 如果您還沒有它,請擷取現有窗口物件的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 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的方法。