共用方式為


顯示應用程式的多個視窗

在 WinUI 3 應用程式中,您可以在次要視窗中顯示應用程式內容,同時仍在每個視窗中使用相同的 UI 線程。

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

小提示

使用多個視窗的一個常見原因是允許將 TabView 選項卡拆除到新視窗中。 如需此案例的特定資訊和範例,請參閱索引標籤檢視一文中的索引標籤撕裂

API 概觀

以下是您在多個視窗中用來顯示內容的一些重要 API。

XAML Window 和 AppWindow

WindowAppWindow 類別可用來在次要視窗中顯示應用程式的一部分。 WinUI 視窗的一個重要功能是,每個實例都會共用相同的 UI 處理線程(包括建立的事件發送器),以簡化多視窗應用程式。

如需 的詳細說明,請參閱 Windows App SDK 和 WinUI 的窗口概觀

AppWindowPresenter

AppWindowPresenter API 可讓您輕鬆地將視窗切換為預先定義的設定,例如 FullScreenCompactOverlay。 如需詳細資訊,請參閱 管理應用程式視窗

XamlRoot

XamlRoot 類別會保留 XAML 元素樹狀結構,將它連線到視窗主機物件,並提供大小和可見度等資訊。 您不會直接建立 XamlRoot 物件。 相反地,當您將 XAML 元素附加至某個Window 時,會建立一個。 然後,您可以使用 UIElement.XamlRoot 屬性來擷取 XamlRoot。

WindowId

WindowId 是應用程式視窗的唯一標識符。 它是自動建立的,並能同時識別與其關聯的AppWindow和頂層 Win32 HWND。

您可以從視覺元素存取 UIElement.XamlRoot;然後是 XamlRoot.ContentIslandEnvironment;則 ContentIslandEnvironment.AppWindowId 屬性會包含 UIElement 所在視窗的識別碼。

顯示新視窗

您可以在 XAML 或程式碼建立新的 Window 。 如果您在 XAML 中建立 Window ,實際上就是要建立 類別的 Window 子類別。 例如,請參閱由 Visual Studio 應用程式範本所建立的MainWindow.xaml

讓我們看看在新視窗中顯示內容的步驟。

使用 XAML 建立新視窗

  1. 方案總管 窗格中,以滑鼠右鍵按下專案名稱,然後選取 新增 > 項目...
  2. 在 [ 新增專案 ] 對話框中,選取視窗左側範本清單中的 WinUI
  3. 選取 空白 Window 範本。
  4. 將檔案命名為 。
  5. [新增]

顯示新視窗

  1. 建立Window的新實例,或如果您以Window檔案創建了Window子類,則實例化.xaml子類。

    Window newWindow = new Window();
    
  2. 建立窗口內容。

    如果您使用檔案建立 Window 子類別 .xaml ,您可以直接在 XAML 中新增視窗內容。 否則,您會在程式代碼中新增內容,如下所示。

    建立 XAML Frame 是很常見的操作,然後導覽 Frame 到您在 XAML [Page](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page) 中定義的應用程式內容頁面。 如需框架和頁面的詳細資訊,請參閱 兩個頁面之間的點對點流覽

    Frame contentFrame = new Frame();
    contentFrame.Navigate(typeof(SecondaryPage));
    

    不過,您可以在AppWindow內顯示任何 XAML 內容,而不僅限於Frame和Page。 例如,您可以只顯示單一控制項,例如 ColorPicker,如稍後所示。

  3. 將 XAML 內容設定為 的 Content 屬性。Window

    newWindow.Content = contentFrame;
    
  4. 呼叫 Window.Activate 方法以顯示新視窗。

    newWindow.Activate();
    

追蹤 Window 的實例

您可能想要從應用程式的其他部分存取 Window 實例,但在您建立的實例 Window之後,除非保留對它的參考,否則無法從其他程式碼存取它。 例如,您可能想要在 Window 中處理 事件,以便在調整視窗大小時重排 UI 元素,或者您可以設置一個「全部關閉」按鈕來關閉 MainPage 的所有追蹤實例。

在此情況下,您應使用 WindowId 唯一標識符來追蹤 Dictionary 中的視窗實例,將 WindowId 作為 Key,並將 Window 實例視為 Value。 (TabView 分離 API 也用於 WindowId 追蹤 Windows)

在您的 App 類別中,將建立 Dictionary 為靜態屬性。 然後,在建立頁面時,將每個頁面新增至 Dictionary ,並在頁面關閉時將其移除。

// App.xaml.cs
public partial class App : Application
{
    private Window? _window;
    public static Dictionary<WindowId, Window> ActiveWindows { get; set; } = new Dictionary<WindowId, Window>();

    // ...

    protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
    {
        _window = new MainWindow();
        _window.Activate();
        // Track the new window in the dictionary.
        ActiveWindows.Add(_window.AppWindow.Id, _window);
    }
}

下列程式代碼會在 中 MainPage按下按鈕時,建立新的視窗。 此方法將新視窗新增至 TrackWindowActiveWindows,並處理 Dictionary 事件,就會在視窗關閉時從 Window 將其移除。

// MainPage.xaml.cs
private Window CreateWindow()
{
    Window newWindow = new Window();

    // Configure the window.
    newWindow.AppWindow.Resize(new SizeInt32(1200, 800));
    newWindow.Title = "Window " + newWindow.AppWindow.Id.Value.ToString();
    newWindow.SystemBackdrop = new MicaBackdrop();

    TrackWindow(newWindow);
    return newWindow;
}

private void TrackWindow(Window window)
{
    window.Closed += (sender, args) => {
        App.ActiveWindows.Remove(window.AppWindow.Id, out window);
    };
    App.ActiveWindows.Add(window.AppWindow.Id, window);
}

從您的應用程式代碼中取得被追蹤的視窗

若要從應用程式程式碼存取Window實例,您必須取得WindowId以擷取目前視窗中類別Dictionary的靜態App。 您應該在頁面的 Loaded 事件處理常式中執行此動作,而不是在建構函式中執行此動作,讓 XamlRoot 不是 null

public sealed partial class SecondaryPage : Page
{
    Window window;

    public SecondaryPage()
    {
        InitializeComponent();
        Loaded += AppWindowPage_Loaded;
    }

    private void AppWindowPage_Loaded(object sender, RoutedEventArgs e)
    {
        // Get the reference to this Window that was stored when it was created.
        // Do this in the Page Loaded handler rather than the constructor to
        // ensure that the XamlRoot is created and attached to the Window.
        WindowId windowId = this.XamlRoot.ContentIslandEnvironment.AppWindowId;

        if (App.ActiveWindows.ContainsKey(windowId))
        {
            window = App.ActiveWindows[windowId];
        }
    }
}