在 WinUI 3 应用中,可以在辅助窗口中显示应用内容,同时仍在每个窗口中使用相同的 UI 线程。
- 重要 API: Microsoft.UI.Windowing 命名空间、 Window 类、 AppWindow 类
 
WinUI 3 示例集应用程序包括大多数 WinUI 3 控件、特性和功能的交互式示例。 从 Microsoft 应用商店获取应用或在 GitHub 上获取源代码
API 概述
下面是用于在多个窗口中显示内容的一些重要 API。
XAML Window 和 AppWindow
这些 Window 和 AppWindow 类可用于在辅助窗口中显示应用的一部分。 WinUI 窗口的一个重要功能是,每个实例共享相同的 UI 处理线程(包括创建它们的事件调度程序),这简化了多窗口应用。
有关 和 Window 的更详细说明,请参阅 AppWindow。
AppWindowPresenter
              AppWindowPresenter API 使你可以轻松地将窗口切换到预定义的配置,例如FullScreen或 CompactOverlay。 有关详细信息,请参阅 “管理应用”窗口。
XamlRoot
XamlRoot 类保存 XAML 元素树,将其连接到窗口宿主对象,并提供大小和可见性等信息。 不要直接创建 XamlRoot 对象。 而是在将 XAML 元素附加到 Window 时创建一个对象。 然后,可以使用 UIElement.XamlRoot 属性检索 XamlRoot。
WindowId
WindowId 是应用窗口的唯一标识符。 它自动创建,并标识 AppWindow 及其关联的顶级 Win32 HWND。
在视觉元素中,可以访问 UIElement.XamlRoot;然后访问 XamlRoot.ContentIslandEnvironment;最后,ContentIslandEnvironment.AppWindowId 属性包含 UIElement 所在的窗口 ID。
显示新窗口
可以在 XAML 或代码中创建新 Window 项。 如果在 XAML 中创建一个 Window ,实际上就是要创建类的 Window 子类。 例如,请参阅由 Visual Studio 应用模板创建的 MainWindow.xaml。
让我们看看在新窗口中显示内容的步骤。
使用 XAML 创建新窗口
- 在 “解决方案资源管理器” 窗格中,右键单击项目名称,然后选择“ 添加新 > 项...”
 - 在“ 添加新项 ”对话框中,选择窗口左侧模板列表中的 WinUI 。
 - 选择“空白 Window”模板。
 - 为文件命名。
 - 按 Add。
 
打开新窗口
实例化 Window 的新实例,或者如果你使用 Window 文件创建了 Window 子类,则实例化
.xaml子类。Window newWindow = new Window();创建窗口内容。
如果通过 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,如稍后所示。
- 
newWindow.Content = contentFrame; 调用 Window.Activate 方法以显示新窗口。
newWindow.Activate();
跟踪 Window 的实例
你可能想要从应用的其他部分访问 Window 实例,但在创建 Window实例后,除非你保留对它的引用,否则无法从其他代码访问它。 例如,你可能想要在Window.SizeChanged事件中重新排列窗口大小调整时的 UI 元素,或者可以有一个“关闭所有”按钮来关闭所有跟踪的Window实例。
在这种情况下,你应该使用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时,以下代码将创建新窗口。 该TrackWindow方法将新窗口添加到ActiveWindowsDictionary对象,并处理Window.Closed事件,当窗口关闭时将其从ActiveWindows中删除。
// 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检索它。 应在页面的 加载 事件处理程序而不是构造函数中执行此作,以便 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];
        }
    }
}