共用方式為


使用 AppWindow 顯示多個檢視

AppWindow 及其相關的 API 可讓您在次要視窗中顯示應用程式內容,同時在每個視窗上仍使用相同的 UI 線程,來簡化多視窗應用程式的建立。

備註

AppWindow 目前為預覽狀態。 這表示您可以將使用AppWindow的應用程式提交至市集,但已知某些平臺和架構元件無法與AppWindow搭配運作(請參閱 限制)。

在這裡,我們會示範多個視窗的一些案例,其中範例應用程式稱為 HelloAppWindow。 範例應用程式示範下列功能:

  • 從主頁面移出控件,並在新視窗中開啟。
  • 在新視窗中開啟頁面的新實例。
  • 以程式設計方式在應用程式中調整新視窗的大小和位置。
  • 將 ContentDialog 與應用程式中的適當視窗產生關聯。

範例應用程式使用單一視窗

單一視窗的範例應用程式

具有分離色彩選擇器和次要視窗的範例應用程式

具有未停駐色彩選擇器和次要視窗的範例應用程式

重要 APIWindows.UI.WindowManagement 命名空間AppWindow 類別

API 概觀

從 Windows 10 版本 1903 (SDK 18362) 開始,即可使用 WindowManagement 命名空間中的 AppWindow 類別和其他 API。 如果您的應用程式以舊版 Windows 10 為目標,您必須 使用 ApplicationView 來建立次要視窗。 WindowManagement APIs 仍在開發中,並有 限制,如 API 參考檔所述。

以下是您在AppWindow中用來顯示內容的一些重要 API。

應用程式視窗

AppWindow 類別可用來在次要視窗中顯示 UWP 應用程式的一部分。 其概念與 ApplicationView 類似,但在行為和存留期中則不同。 AppWindow 的主要特點是,每個實例共用相同的 UI 處理緒(包括事件分派器),從中建立,可簡化多視窗應用程式。

您只能將 XAML 內容連線到 AppWindow,不支援原生 DirectX 或全像攝影內容。 不過,您可以顯示承載 DirectX 內容的 XAML SwapChainPanel

視窗環境

WindowingEnvironment API 可讓您瞭解應用程式呈現所在的環境,以便視需要調整您的應用程式。 它描述了環境支援的窗口類型;例如,Overlapped 表示應用程式正在電腦上執行,而 Tiled 表示應用程式在 Xbox 上執行。 它也提供一組 DisplayRegion 物件,描述應用程式可能會在邏輯顯示器上顯示的區域。

顯示區域

DisplayRegion API 描述可在邏輯顯示器上向使用者顯示檢視的區域,例如,在桌面電腦上,這是整個顯示器減去任務欄的部分。 它與背後顯示器的實體顯示範圍不一定是 1:1 的對應。 相同監視器內可以有多個顯示區域,或者,如果這些監視器在所有方面都是同質的,則可以將 DisplayRegion 設定為跨越多個監視器。

應用程式視窗演示者

AppWindowPresenter API 可讓您輕鬆地將視窗切換至預先定義的組態,例如 FullScreenCompactOverlay。 這些設定可讓使用者在任何支援設定的裝置上一致體驗。

視覺介面情境

UIContext 是應用程式視窗或檢視的唯一標識碼。 它會自動建立,您可以使用 UIElement.UIContext 屬性來獲取 UIContext。 XAML 樹狀結構中的每個 UIElement 都有相同的 UIContext。

UIContext 很重要,因為像 Window.CurrentGetForCurrentView 模式這些 API,需要每個線程具備一個具有單一 XAML 樹狀結構的 ApplicationView/CoreWindow。 當您使用AppWindow時,情況並非如此,因此您會改用UIContext來識別特定視窗。

XamlRoot

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

如需UIContext和 XamlRoot 的詳細資訊,請參閱 讓程式代碼跨視窗主機進行可移植

顯示新視窗

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

顯示新視窗

  1. 呼叫靜態 AppWindow.TryCreateAsync 方法來建立新的 AppWindow

    AppWindow appWindow = await AppWindow.TryCreateAsync();
    
  2. 建立窗口內容。

    一般而言,您會建立 XAML Frame,然後將 Frame 瀏覽至您已定義應用程式內容的 XAML Page。 如需框架和頁面的詳細資訊,請參閱 兩個頁面之間的點對點流覽

    Frame appWindowContentFrame = new Frame();
    appWindowContentFrame.Navigate(typeof(AppWindowMainPage));
    

    不過,您可以在 AppWindow 中顯示任何 XAML 內容,而不只是 Frame 和 Page。 例如,您可以只顯示單一控件,例如 ColorPicker,也可以顯示裝載 DirectX 內容的 SwapChainPanel

  3. 呼叫 ElementCompositionPreview.SetAppWindowContent 方法,將 XAML 內容附加至 AppWindow。

    ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowContentFrame);
    

    呼叫此方法會建立 XamlRoot 物件,並將其設定為指定 UIElement 的 XamlRoot 屬性。

    每個 AppWindow 實例只能呼叫這個方法一次。 設定內容之後,此 AppWindow 實例對 SetAppWindowContent 的進一步呼叫將會失敗。 此外,如果您嘗試透過傳入 Null UIElement 對象來中斷 AppWindow 內容的連線,呼叫將會失敗。

  4. 呼叫 AppWindow.TryShowAsync 方法來顯示新的視窗。

    await appWindow.TryShowAsync();
    

關閉視窗時釋放資源

您應該始終監控 AppWindow.Closed 事件,以釋放 XAML 資源(即 AppWindow 內容)和對 AppWindow 的參考。

appWindow.Closed += delegate
{
    appWindowContentFrame.Content = null;
    appWindow = null;
};

小提示

您應該將事件處理程式中的 Closed 程式代碼數量保持在可能的最低數量,以避免發生非預期的問題。

追蹤AppWindow的實例

視您在應用程式中使用多個視窗的方式而定,您可能或可能不需要追蹤您建立的 AppWindow 實例。 HelloAppWindow 範例顯示一些您一般會使用 AppWindow的不同方式。 在這裡,我們將探討為何應該追蹤這些視窗,以及如何加以追蹤。

簡單追蹤

色彩選擇器視窗會裝載單一 XAML 控制件,以及與色彩選擇器互動的程式代碼全都位於檔案中 MainPage.xaml.cs 。 色彩選擇器視窗只允許單一實例,而且基本上是的 MainWindow延伸模組。 為了確保只建立一個實例,色彩選擇器視窗會使用頁面層級變數來追蹤。 在建立新的色彩選擇器視窗之前,檢查是否存在實例,如果確實存在,略過建立新視窗的步驟,直接在現有視窗上呼叫 TryShowAsync

AppWindow colorPickerAppWindow;

// ...

private async void DetachColorPickerButton_Click(object sender, RoutedEventArgs e)
{
    // Create the color picker window.
    if (colorPickerAppWindow == null)
    {
        // ...
        // Create a new window
        colorPickerAppWindow = await AppWindow.TryCreateAsync();
        // ...
    }
    // Show the window.
    await colorPickerAppWindow.TryShowAsync();
}

在裝載的內容中追蹤AppWindow實例

視窗會 AppWindowPage 裝載完整的 XAML 頁面,且與頁面互動的程式代碼位於 AppWindowPage.xaml.cs中。 它允許多個實例,每個實例各自獨立運作。

頁面的功能可讓您控制視窗,設置視窗為 FullScreenCompactOverlay,並接聽 AppWindow.Changed 事件以顯示視窗的資訊。 為了呼叫這些 API,AppWindowPage 需要一個承載它的 AppWindow 實例的參考。

如果您只需要這一切,您可以在 中 AppWindowPage 建立屬性,並在建立它時將 AppWindow 實例指派給它。

AppWindowPage.xaml.cs

AppWindowPage中,建立屬性來儲存 AppWindow 引用。

public sealed partial class AppWindowPage : Page
{
    public AppWindow MyAppWindow { get; set; }

    // ...
}

MainPage.xaml.cs

MainPage中,取得頁面實例的參考,並將新建立的 AppWindow 指派給 AppWindowPage中的屬性。

private async void ShowNewWindowButton_Click(object sender, RoutedEventArgs e)
{
    // Create a new window.
    AppWindow appWindow = await AppWindow.TryCreateAsync();

    // Create a Frame and navigate to the Page you want to show in the new window.
    Frame appWindowContentFrame = new Frame();
    appWindowContentFrame.Navigate(typeof(AppWindowPage));

    // Get a reference to the page instance and assign the
    // newly created AppWindow to the MyAppWindow property.
    AppWindowPage page = (AppWindowPage)appWindowContentFrame.Content;
    page.MyAppWindow = appWindow;

    // ...
}

使用 UIContext 追蹤應用程式視窗

您可能也想要從應用程式的其他部分存取 AppWindow 實例。 例如, MainPage 可以有一個 [關閉全部] 按鈕,以關閉AppWindow的所有追蹤實例。

在此情況下,您應該使用 UIContext 唯一標識符來追蹤 Dictionary 中的視窗實例。

MainPage.xaml.cs

MainPage中,將 Dictionary 建立為靜態屬性。 然後,當您建立頁面時,將頁面新增至字典,並在頁面關閉時將其移除。 呼叫 ElementCompositionPreview.SetAppWindowContent之後,您可以從內容 Frame Frame)取得 UIContext。

public sealed partial class MainPage : Page
{
    // Track open app windows in a Dictionary.
    public static Dictionary<UIContext, AppWindow> AppWindows { get; set; }
        = new Dictionary<UIContext, AppWindow>();

    // ...

    private async void ShowNewWindowButton_Click(object sender, RoutedEventArgs e)
    {
        // Create a new window.
        AppWindow appWindow = await AppWindow.TryCreateAsync();

        // Create a Frame and navigate to the Page you want to show in the new window.
        Frame appWindowContentFrame = new Frame();
        appWindowContentFrame.Navigate(typeof(AppWindowPage));

        // Attach the XAML content to the window.
        ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowContentFrame);

        // Add the new page to the Dictionary using the UIContext as the Key.
        AppWindows.Add(appWindowContentFrame.UIContext, appWindow);
        appWindow.Title = "App Window " + AppWindows.Count.ToString();

        // When the window is closed, be sure to release
        // XAML resources and the reference to the window.
        appWindow.Closed += delegate
        {
            MainPage.AppWindows.Remove(appWindowContentFrame.UIContext);
            appWindowContentFrame.Content = null;
            appWindow = null;
        };

        // Show the window.
        await appWindow.TryShowAsync();
    }

    private async void CloseAllButton_Click(object sender, RoutedEventArgs e)
    {
        while (AppWindows.Count > 0)
        {
            await AppWindows.Values.First().CloseAsync();
        }
    }
    // ...
}

AppWindowPage.xaml.cs

若要在您的程式代碼中使用 AppWindowPage 實例,請使用頁面的 UIContext 從 中的MainPage靜態字典擷取它。 您應該在頁面的 載入 事件處理程式中執行此動作,而不是在建構函式中執行,以確保 UIContext 不為 null。 您可以從 Page:this.UIContext取得 UIContext。

public sealed partial class AppWindowPage : Page
{
    AppWindow window;

    // ...
    public AppWindowPage()
    {
        this.InitializeComponent();

        Loaded += AppWindowPage_Loaded;
    }

    private void AppWindowPage_Loaded(object sender, RoutedEventArgs e)
    {
        // Get the reference to this AppWindow that was stored when it was created.
        window = MainPage.AppWindows[this.UIContext];

        // Set up event handlers for the window.
        window.Changed += Window_Changed;
    }
    // ...
}

備註

HelloAppWindow 範例示範在 中 AppWindowPage追蹤視窗的兩種方式,但您通常會使用其中一個或另一個,而不是兩者。

要求視窗大小和位置

AppWindow 類別有數種方法,可用來控制視窗的大小和位置。 根據方法名稱所隱含,系統可能會或可能不接受所要求的變更,視環境因素而定。

呼叫 RequestSize 以指定所需的視窗大小,如下所示。

colorPickerAppWindow.RequestSize(new Size(300, 428));

管理視窗放置的方法命名為 RequestMove*RequestMoveAdjacentToCurrentViewRequestMoveAdjacentToWindowRequestMoveRelativeToDisplayRegionRequestMoveToDisplayRegion

在此範例中,這段程式碼會將視窗移動到生成視窗的主畫面旁邊。

colorPickerAppWindow.RequestMoveAdjacentToCurrentView();

若要取得視窗目前大小和位置的相關信息,請呼叫 GetPlacement。 這會傳回 AppWindowPlacement 物件,該物件提供視窗目前的 DisplayRegionOffsetSize

例如,您可以呼叫此程式碼,將視窗移至顯示器右上角。 在窗口顯示之後,必須呼叫此程序代碼;否則,呼叫 GetPlacement 所傳回的視窗大小會是 0,0,而位移將會不正確。

DisplayRegion displayRegion = window.GetPlacement().DisplayRegion;
double displayRegionWidth = displayRegion.WorkAreaSize.Width;
double windowWidth = window.GetPlacement().Size.Width;
int horizontalOffset = (int)(displayRegionWidth - windowWidth);
window.RequestMoveRelativeToDisplayRegion(displayRegion, new Point(horizontalOffset, 0));

要求簡報配置

AppWindowPresenter 類別可讓您使用適用於其顯示裝置的預先定義組態來顯示 AppWindow。 您可以使用 AppWindowPresentationConfiguration 值,將視窗 FullScreen 置於或 CompactOverlay 模式中。

此範例示範如何執行下列動作:

private void Window_Changed(AppWindow sender, AppWindowChangedEventArgs args)
{
    if (args.DidAvailableWindowPresentationsChange)
    {
        EnablePresentationButtons(sender);
    }

    if (args.DidWindowPresentationChange)
    {
        ConfigText.Text = window.Presenter.GetConfiguration().Kind.ToString();
    }

    if (args.DidSizeChange)
    {
        SizeText.Text = window.GetPlacement().Size.ToString();
    }
}

private void EnablePresentationButtons(AppWindow window)
{
    // Check whether the current AppWindowPresenter supports CompactOverlay.
    if (window.Presenter.IsPresentationSupported(AppWindowPresentationKind.CompactOverlay))
    {
        // Show the CompactOverlay button...
        compactOverlayButton.Visibility = Visibility.Visible;
    }
    else
    {
        // Hide the CompactOverlay button...
        compactOverlayButton.Visibility = Visibility.Collapsed;
    }

    // Check whether the current AppWindowPresenter supports FullScreen?
    if (window.Presenter.IsPresentationSupported(AppWindowPresentationKind.FullScreen))
    {
        // Show the FullScreen button...
        fullScreenButton.Visibility = Visibility.Visible;
    }
    else
    {
        // Hide the FullScreen button...
        fullScreenButton.Visibility = Visibility.Collapsed;
    }
}

private void CompactOverlayButton_Click(object sender, RoutedEventArgs e)
{
    if (window.Presenter.GetConfiguration().Kind != AppWindowPresentationKind.CompactOverlay)
    {
        window.Presenter.RequestPresentation(AppWindowPresentationKind.CompactOverlay);
        fullScreenButton.IsChecked = false;
    }
    else
    {
        window.Presenter.RequestPresentation(AppWindowPresentationKind.Default);
    }
}

private void FullScreenButton_Click(object sender, RoutedEventArgs e)
{
    if (window.Presenter.GetConfiguration().Kind != AppWindowPresentationKind.FullScreen)
    {
        window.Presenter.RequestPresentation(AppWindowPresentationKind.FullScreen);
        compactOverlayButton.IsChecked = false;
    }
    else
    {
        window.Presenter.RequestPresentation(AppWindowPresentationKind.Default);
    }
}

重複使用 XAML 元素

AppWindow 可讓您有多個具有相同 UI 線程的 XAML 樹狀結構。 不過,XAML 元素只能新增至 XAML 樹狀結構一次。 如果您想要將UI的一部分從某個視窗移至另一個視窗,則必須管理它位於 XAML 樹狀結構中的位置。

這個範例示範如何在主視窗與次要窗口之間移動 ColorPicker 控件時重複使用它。

色彩選擇器在 XAML 的MainPage中宣告,這將它放在 XAML 樹狀結構的MainPage中。

<StackPanel x:Name="colorPickerContainer" Grid.Column="1" Background="WhiteSmoke">
    <Button Click="DetachColorPickerButton_Click" HorizontalAlignment="Right">
        <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE2B4;" />
    </Button>
    <ColorPicker x:Name="colorPicker" Margin="12" Width="288"
                 IsColorChannelTextInputVisible="False"
                 ColorChanged="ColorPicker_ColorChanged"/>
</StackPanel>

將色彩選擇器卸離以放在新的 AppWindow 中時,您必須先從 MainPage XAML 樹狀結構中移除它,方法是從其父容器中移除它。 雖然並非必要,但此範例也會隱藏父容器。

colorPickerContainer.Children.Remove(colorPicker);
colorPickerContainer.Visibility = Visibility.Collapsed;

然後,您可以將它新增至新的 XAML 樹狀結構。 在這裡,您會先建立 Grid,成為 ColorPicker 的父容器,並將 ColorPicker 新增為 Grid 的子系。 (這可讓您稍後輕鬆地從這個 XAML 樹狀結構中移除 ColorPicker。接著,您會在新視窗中將 Grid 設定為 XAML 樹狀結構的根目錄。

Grid appWindowRootGrid = new Grid();
appWindowRootGrid.Children.Add(colorPicker);

// Create a new window
colorPickerAppWindow = await AppWindow.TryCreateAsync();

// Attach the XAML content to our window
ElementCompositionPreview.SetAppWindowContent(colorPickerAppWindow, appWindowRootGrid);

AppWindow 關閉時,您會逆轉這個過程。 首先,從 Grid 移除 ColorPicker,然後在 中將它新增為 MainPage 的子系。

// When the window is closed, be sure to release XAML resources
// and the reference to the window.
colorPickerAppWindow.Closed += delegate
{
    appWindowRootGrid.Children.Remove(colorPicker);
    appWindowRootGrid = null;
    colorPickerAppWindow = null;

    colorPickerContainer.Children.Add(colorPicker);
    colorPickerContainer.Visibility = Visibility.Visible;
};
private async void DetachColorPickerButton_Click(object sender, RoutedEventArgs e)
{
    ColorPickerContainer.Visibility = Visibility.Collapsed;

    // Create the color picker window.
    if (colorPickerAppWindow == null)
    {
        ColorPickerContainer.Children.Remove(colorPicker);

        Grid appWindowRootGrid = new Grid();
        appWindowRootGrid.Children.Add(colorPicker);

        // Create a new window
        colorPickerAppWindow = await AppWindow.TryCreateAsync();
        colorPickerAppWindow.RequestMoveAdjacentToCurrentView();
        colorPickerAppWindow.RequestSize(new Size(300, 428));
        colorPickerAppWindow.Title = "Color picker";

        // Attach the XAML content to our window
        ElementCompositionPreview.SetAppWindowContent(colorPickerAppWindow, appWindowRootGrid);

        // When the window is closed, be sure to release XAML resources
        // and the reference to the window.
        colorPickerAppWindow.Closed += delegate
        {
            appWindowRootGrid.Children.Remove(colorPicker);
            appWindowRootGrid = null;
            colorPickerAppWindow = null;

            ColorPickerContainer.Children.Add(colorPicker);
            ColorPickerContainer.Visibility = Visibility.Visible;
        };
    }
    // Show the window.
    await colorPickerAppWindow.TryShowAsync();
}

顯示對話框

根據預設,內容對話框以模態方式顯示,相對於根目錄 ApplicationView。 當您在 AppWindow 內使用 ContentDialog 時,您必須手動將對話方塊上的 XamlRoot 設定為 XAML 主機的根目錄。

若要這樣做,請將 ContentDialog 的 XamlRoot 屬性設定為與 AppWindow 中已經有元素相同的 XamlRoot 。 在這裡,此程式碼位於按鈕 Click 事件處理器內,因此您可以使用 發送者 (被點擊的按鈕)來獲得 XamlRoot。

if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
{
    simpleDialog.XamlRoot = ((Button)sender).XamlRoot;
}

如果您在主視窗(ApplicationView)之外還開啟了一個或多個 AppWindows,那麼每個視窗都可以嘗試開啟對話框,因為模態對話框只會封鎖它所屬的視窗。 不過,在每個執行緒中,一次只能有一個 ContentDialog 被開啟。 嘗試開啟兩個 ContentDialogs 將會拋出例外狀況,即使它們嘗試在不同的 AppWindows 中開啟也一樣。

若要管理這項作業,您應該至少在區塊中 try/catch 開啟對話框,以攔截例外狀況,以防另一個對話框已經開啟。

try
{
    ContentDialogResult result = await simpleDialog.ShowAsync();
}
catch (Exception)
{
    // The dialog didn't open, probably because another dialog is already open.
}

管理對話的另一種方式是追蹤目前開啟的對話方塊,並在嘗試開啟新對話方塊之前將其關閉。 在這裡,您會在 MainPage 中建立名為 CurrentDialog 的靜態屬性,用於此目的。

public sealed partial class MainPage : Page
{
    // Track the last opened dialog so you can close it if another dialog tries to open.
    public static ContentDialog CurrentDialog { get; set; } = null;

   // ...
}

然後,您會檢查是否有目前開啟的對話方塊,如果有的話,請呼叫 Hide 方法來關閉它。 最後,將新的對話框指派給 CurrentDialog,然後嘗試顯示它。

private async void DialogButton_Click(object sender, RoutedEventArgs e)
{
    ContentDialog simpleDialog = new ContentDialog
    {
        Title = "Content dialog",
        Content = "Dialog box for " + window.Title,
        CloseButtonText = "Ok"
    };

    if (MainPage.CurrentDialog != null)
    {
        MainPage.CurrentDialog.Hide();
    }
    MainPage.CurrentDialog = simpleDialog;

    // Use this code to associate the dialog to the appropriate AppWindow by setting
    // the dialog's XamlRoot to the same XamlRoot as an element that is already
    // present in the AppWindow.
    if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
    {
        simpleDialog.XamlRoot = ((Button)sender).XamlRoot;
    }

    try
    {
        ContentDialogResult result = await simpleDialog.ShowAsync();
    }
    catch (Exception)
    {
        // The dialog didn't open, probably because another dialog is already open.
    }
}

如果不想要以程式設計方式關閉對話框,請勿將它指派為 CurrentDialog。 在這裡,MainPage 顯示了一個重要的對話框,只有當使用者點擊 Ok時才應該關閉。 因為它未指派為 CurrentDialog,因此不會嘗試以程式設計方式關閉它。

public sealed partial class MainPage : Page
{
    // Track the last opened dialog so you can close it if another dialog tries to open.
    public static ContentDialog CurrentDialog { get; set; } = null;

    // ...
    private async void DialogButton_Click(object sender, RoutedEventArgs e)
    {
        ContentDialog importantDialog = new ContentDialog
        {
            Title = "Important dialog",
            Content = "This dialog can only be dismissed by clicking Ok.",
            CloseButtonText = "Ok"
        };

        if (MainPage.CurrentDialog != null)
        {
            MainPage.CurrentDialog.Hide();
        }
        // Do not track this dialog as the MainPage.CurrentDialog.
        // It should only be closed by clicking the Ok button.
        MainPage.CurrentDialog = null;

        try
        {
            ContentDialogResult result = await importantDialog.ShowAsync();
        }
        catch (Exception)
        {
            // The dialog didn't open, probably because another dialog is already open.
        }
    }
    // ...
}

完整程式碼

MainPage.xaml

<Page
    x:Class="HelloAppWindow.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HelloAppWindow"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <Button x:Name="NewWindowButton" Content="Open new window" 
                    Click="ShowNewWindowButton_Click" Margin="0,12"/>
            <Button Content="Open dialog" Click="DialogButton_Click" 
                    HorizontalAlignment="Stretch"/>
            <Button Content="Close all" Click="CloseAllButton_Click" 
                    Margin="0,12" HorizontalAlignment="Stretch"/>
        </StackPanel>

<StackPanel x:Name="colorPickerContainer" Grid.Column="1" Background="WhiteSmoke">
    <Button Click="DetachColorPickerButton_Click" HorizontalAlignment="Right">
        <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE2B4;" />
    </Button>
            <ColorPicker x:Name="colorPicker" Margin="12" Width="288"
                 IsColorChannelTextInputVisible="False"
                 ColorChanged="ColorPicker_ColorChanged"/>
        </StackPanel>
    </Grid>
</Page>

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.WindowManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Hosting;
using Windows.UI.Xaml.Media;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace HelloAppWindow
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        AppWindow colorPickerAppWindow;

        // Track open app windows in a Dictionary.
        public static Dictionary<UIContext, AppWindow> AppWindows { get; set; }
            = new Dictionary<UIContext, AppWindow>();

        // Track the last opened dialog so you can close it if another dialog tries to open.
        public static ContentDialog CurrentDialog { get; set; } = null;

        public MainPage()
        {
            this.InitializeComponent();
        }

        private async void ShowNewWindowButton_Click(object sender, RoutedEventArgs e)
        {
            // Create a new window.
            AppWindow appWindow = await AppWindow.TryCreateAsync();

            // Create a Frame and navigate to the Page you want to show in the new window.
            Frame appWindowContentFrame = new Frame();
            appWindowContentFrame.Navigate(typeof(AppWindowPage));

            // Get a reference to the page instance and assign the
            // newly created AppWindow to the MyAppWindow property.
            AppWindowPage page = (AppWindowPage)appWindowContentFrame.Content;
            page.MyAppWindow = appWindow;
            page.TextColorBrush = new SolidColorBrush(colorPicker.Color);

            // Attach the XAML content to the window.
            ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowContentFrame);

            // Add the new page to the Dictionary using the UIContext as the Key.
            AppWindows.Add(appWindowContentFrame.UIContext, appWindow);
            appWindow.Title = "App Window " + AppWindows.Count.ToString();

            // When the window is closed, be sure to release XAML resources
            // and the reference to the window.
            appWindow.Closed += delegate
            {
                MainPage.AppWindows.Remove(appWindowContentFrame.UIContext);
                appWindowContentFrame.Content = null;
                appWindow = null;
            };

            // Show the window.
            await appWindow.TryShowAsync();
        }

        private async void DialogButton_Click(object sender, RoutedEventArgs e)
        {
            ContentDialog importantDialog = new ContentDialog
            {
                Title = "Important dialog",
                Content = "This dialog can only be dismissed by clicking Ok.",
                CloseButtonText = "Ok"
            };

            if (MainPage.CurrentDialog != null)
            {
                MainPage.CurrentDialog.Hide();
            }
            // Do not track this dialog as the MainPage.CurrentDialog.
            // It should only be closed by clicking the Ok button.
            MainPage.CurrentDialog = null;

            try
            {
                ContentDialogResult result = await importantDialog.ShowAsync();
            }
            catch (Exception)
            {
                // The dialog didn't open, probably because another dialog is already open.
            }
        }

        private async void DetachColorPickerButton_Click(object sender, RoutedEventArgs e)
        {
            // Create the color picker window.
            if (colorPickerAppWindow == null)
            {
                colorPickerContainer.Children.Remove(colorPicker);
                colorPickerContainer.Visibility = Visibility.Collapsed;

                Grid appWindowRootGrid = new Grid();
                appWindowRootGrid.Children.Add(colorPicker);

                // Create a new window
                colorPickerAppWindow = await AppWindow.TryCreateAsync();
                colorPickerAppWindow.RequestMoveAdjacentToCurrentView();
                colorPickerAppWindow.RequestSize(new Size(300, 428));
                colorPickerAppWindow.Title = "Color picker";

                // Attach the XAML content to our window
                ElementCompositionPreview.SetAppWindowContent(colorPickerAppWindow, appWindowRootGrid);

                // Make sure to release the reference to this window, 
                // and release XAML resources, when it's closed
                colorPickerAppWindow.Closed += delegate
                {
                    appWindowRootGrid.Children.Remove(colorPicker);
                    appWindowRootGrid = null;
                    colorPickerAppWindow = null;

                    colorPickerContainer.Children.Add(colorPicker);
                    colorPickerContainer.Visibility = Visibility.Visible;
                };
            }
            // Show the window.
            await colorPickerAppWindow.TryShowAsync();
        }

        private void ColorPicker_ColorChanged(ColorPicker sender, ColorChangedEventArgs args)
        {
            NewWindowButton.Background = new SolidColorBrush(args.NewColor);
        }

        private async void CloseAllButton_Click(object sender, RoutedEventArgs e)
        {
            while (AppWindows.Count > 0)
            {
                await AppWindows.Values.First().CloseAsync();
            }
        }
    }
}

AppWindowPage.xaml

<Page
    x:Class="HelloAppWindow.AppWindowPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HelloAppWindow"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <TextBlock x:Name="TitleTextBlock" Text="Hello AppWindow!" FontSize="24" HorizontalAlignment="Center" Margin="24"/>

        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <Button Content="Open dialog" Click="DialogButton_Click"
                    Width="200" Margin="0,4"/>
            <Button Content="Move window" Click="MoveWindowButton_Click"
                    Width="200" Margin="0,4"/>
            <ToggleButton Content="Compact Overlay" x:Name="compactOverlayButton" Click="CompactOverlayButton_Click"
                          Width="200" Margin="0,4"/>
            <ToggleButton Content="Full Screen" x:Name="fullScreenButton" Click="FullScreenButton_Click"
                          Width="200" Margin="0,4"/>
            <Grid>
                <TextBlock Text="Size:"/>
                <TextBlock x:Name="SizeText" HorizontalAlignment="Right"/>
            </Grid>
            <Grid>
                <TextBlock Text="Presentation:"/>
                <TextBlock x:Name="ConfigText" HorizontalAlignment="Right"/>
            </Grid>
        </StackPanel>
    </Grid>
</Page>

AppWindowPage.xaml.cs

using System;
using Windows.Foundation;
using Windows.Foundation.Metadata;
using Windows.UI;
using Windows.UI.WindowManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238

namespace HelloAppWindow
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class AppWindowPage : Page
    {
        AppWindow window;

        public AppWindow MyAppWindow { get; set; }

        public SolidColorBrush TextColorBrush { get; set; } = new SolidColorBrush(Colors.Black);

        public AppWindowPage()
        {
            this.InitializeComponent();

            Loaded += AppWindowPage_Loaded;
        }

        private void AppWindowPage_Loaded(object sender, RoutedEventArgs e)
        {
            // Get the reference to this AppWindow that was stored when it was created.
            window = MainPage.AppWindows[this.UIContext];

            // Set up event handlers for the window.
            window.Changed += Window_Changed;

            TitleTextBlock.Foreground = TextColorBrush;
        }

        private async void DialogButton_Click(object sender, RoutedEventArgs e)
        {
            ContentDialog simpleDialog = new ContentDialog
            {
                Title = "Content dialog",
                Content = "Dialog box for " + window.Title,
                CloseButtonText = "Ok"
            };

            if (MainPage.CurrentDialog != null)
            {
                MainPage.CurrentDialog.Hide();
            }
            MainPage.CurrentDialog = simpleDialog;

            // Use this code to associate the dialog to the appropriate AppWindow by setting
            // the dialog's XamlRoot to the same XamlRoot as an element that is already 
            // present in the AppWindow.
            if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
            {
                simpleDialog.XamlRoot = ((Button)sender).XamlRoot;
            }

            try
            {
                ContentDialogResult result = await simpleDialog.ShowAsync();
            }
            catch (Exception)
            {
                // The dialog didn't open, probably because another dialog is already open.
            }
        }

        private void Window_Changed(AppWindow sender, AppWindowChangedEventArgs args)
        {
            if (args.DidAvailableWindowPresentationsChange)
            {
                EnablePresentationButtons(sender);
            }

            if (args.DidWindowPresentationChange)
            {
                ConfigText.Text = window.Presenter.GetConfiguration().Kind.ToString();
            }

            if (args.DidSizeChange)
            {
                SizeText.Text = window.GetPlacement().Size.ToString();
            }
        }

        private void EnablePresentationButtons(AppWindow window)
        {
            // Check whether the current AppWindowPresenter supports CompactOverlay.
            if (window.Presenter.IsPresentationSupported(AppWindowPresentationKind.CompactOverlay))
            {
                // Show the CompactOverlay button...
                compactOverlayButton.Visibility = Visibility.Visible;
            }
            else
            {
                // Hide the CompactOverlay button...
                compactOverlayButton.Visibility = Visibility.Collapsed;
            }

            // Check whether the current AppWindowPresenter supports FullScreen?
            if (window.Presenter.IsPresentationSupported(AppWindowPresentationKind.FullScreen))
            {
                // Show the FullScreen button...
                fullScreenButton.Visibility = Visibility.Visible;
            }
            else
            {
                // Hide the FullScreen button...
                fullScreenButton.Visibility = Visibility.Collapsed;
            }
        }

        private void CompactOverlayButton_Click(object sender, RoutedEventArgs e)
        {
            if (window.Presenter.GetConfiguration().Kind != AppWindowPresentationKind.CompactOverlay)
            {
                window.Presenter.RequestPresentation(AppWindowPresentationKind.CompactOverlay);
                fullScreenButton.IsChecked = false;
            }
            else
            {
                window.Presenter.RequestPresentation(AppWindowPresentationKind.Default);
            }
        }

        private void FullScreenButton_Click(object sender, RoutedEventArgs e)
        {
            if (window.Presenter.GetConfiguration().Kind != AppWindowPresentationKind.FullScreen)
            {
                window.Presenter.RequestPresentation(AppWindowPresentationKind.FullScreen);
                compactOverlayButton.IsChecked = false;
            }
            else
            {
                window.Presenter.RequestPresentation(AppWindowPresentationKind.Default);
            }
        }

        private void MoveWindowButton_Click(object sender, RoutedEventArgs e)
        {
            DisplayRegion displayRegion = window.GetPlacement().DisplayRegion;
            double displayRegionWidth = displayRegion.WorkAreaSize.Width;
            double windowWidth = window.GetPlacement().Size.Width;
            int horizontalOffset = (int)(displayRegionWidth - windowWidth);
            window.RequestMoveRelativeToDisplayRegion(displayRegion, new Point(horizontalOffset, 0));
        }
    }
}