次の方法で共有


AppWindow で複数のビューを表示する

AppWindow とそれに関連する API を使用すると、各ウィンドウで同じ UI スレッドで作業しながら、アプリのコンテンツをセカンダリ ウィンドウに表示できるため、マルチウィンドウ アプリの作成が簡略化されます。

AppWindow は現在プレビュー段階です。 つまり、AppWindow を使用するアプリをストアに送信できますが、一部のプラットフォームおよびフレームワーク コンポーネントは AppWindow で動作しないことがわかっています ( 制限事項を参照)。

ここでは、 HelloAppWindowというサンプル アプリを使用した複数のウィンドウのシナリオをいくつか示します。 サンプル アプリは、次の機能を示しています。

  • メイン ページからコントロールのドッキングを解除し、新しいウィンドウで開きます。
  • ページの新しいインスタンスを新しいウィンドウで開きます。
  • プログラムによって新しいウィンドウのサイズを設定し、アプリに配置します。
  • ContentDialog をアプリの適切なウィンドウに関連付けます。

1 つのウィンドウ を使用したサンプル アプリの

1つのウィンドウを持つサンプルアプリ

ドッキングされていないカラー ピッカーとセカンダリ ウィンドウを含むサンプル アプリ

ドッキングされていないカラー ピッカーとセカンダリ ウィンドウを含むサンプル アプリ

重要な API: Windows.UI.WindowManagement 名前空間AppWindow クラス

API の概要

Windows 10 バージョン 1903 (SDK 18362) 以降では、WindowManagement 名前空間の AppWindow クラスとその他の API を使用できます。 アプリが以前のバージョンの Windows 10 を対象とする場合は、 ApplicationView を使用してセカンダリ ウィンドウを作成する必要があります。 WindowManagement API はまだ開発中であり、API リファレンス ドキュメントで説明されているように 制限 があります。

AppWindow でコンテンツを表示するために使用する重要な API の一部を次に示します。

アプリウィンドウ

AppWindow クラスを使用すると、UWP アプリの一部をセカンダリ ウィンドウに表示できます。 これは ApplicationView の概念に似ていますが、動作と有効期間では同じではありません。 AppWindow の主な機能は、各インスタンスが作成元の同じ UI 処理スレッド (イベント ディスパッチャーを含む) を共有することで、マルチウィンドウ アプリを簡略化することです。

XAML コンテンツは AppWindow にのみ接続できます。ネイティブ DirectX または Holographic コンテンツはサポートされません。 ただし、DirectX コンテンツをホストする XAML SwapChainPanel を表示できます。

ウィンドウ環境

WindowingEnvironment API を使用すると、アプリが表示されている環境を把握できるため、必要に応じてアプリを調整できます。 環境がサポートするウィンドウの種類について説明します。たとえば、アプリが PC で実行されている場合は Overlapped 、アプリが Xbox で実行されている場合は Tiled 。 また、アプリが論理ディスプレイに表示される領域を記述する DisplayRegion オブジェクトのセットも提供します。

表示領域

DisplayRegion API では、論理ディスプレイ上のユーザーにビューを表示できるリージョンについて説明します。たとえば、デスクトップ PC では、これはフル ディスプレイからタスク バーの領域を引いた値です。 バッキング・モニターの物理表示域との 1 対 1 のマッピングであるとは限りません。 同じモニター内に複数のディスプレイ領域が存在する場合もあります。また、これらのモニターがすべての側面で同種である場合は、複数のモニターにまたがるよう DisplayRegion を構成できます。

AppWindowPresenter (アプリウィンドウプレゼンター)

AppWindowPresenter API を使用すると、ウィンドウをFullScreenCompactOverlayなどの定義済みの構成に簡単に切り替えることができます。 これらの構成により、構成をサポートするすべてのデバイスで一貫したエクスペリエンスがユーザーに提供されます。

UIコンテキスト

UIContext は、アプリ ウィンドウまたはビューの一意識別子です。 これは自動的に作成され、 UIElement.UIContext プロパティを使用して UIContext を取得できます。 XAML ツリー内のすべての UIElement には、同じ UIContext があります。

UIContext は重要です 。Window.CurrentGetForCurrentView パターンなどの API は、スレッドごとに 1 つの 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 フレームを作成し、アプリのコンテンツを定義した XAML ページ にフレームを移動します。 フレームとページの詳細については、「2 つのページ間のピア ツー ピア ナビゲーション を参照してください。

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

    ただし、フレームとページだけでなく、AppWindow に任意の XAML コンテンツを表示できます。 たとえば、 ColorPicker などのコントロールを 1 つだけ表示したり、DirectX コンテンツをホストする SwapChainPanel を表示したりできます。

  3. ElementCompositionPreview.SetAppWindowContent メソッドを呼び出して、XAML コンテンツを AppWindow にアタッチします。

    ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowContentFrame);
    

    このメソッドを呼び出すと、 XamlRoot オブジェクトが作成され、指定した UIElement の XamlRoot プロパティとして設定されます。

    このメソッドは、AppWindow インスタンスごとに 1 回だけ呼び出せます。 コンテンツが設定されると、この AppWindow インスタンスに対する SetAppWindowContent の呼び出しがさらに失敗します。 また、null UIElement オブジェクトを渡して AppWindow コンテンツを切断しようとすると、呼び出しは失敗します。

  4. AppWindow.TryShowAsync メソッドを呼び出して、新しいウィンドウを表示します。

    await appWindow.TryShowAsync();
    

ウィンドウが閉じられたときにリソースを解放する

XAML リソース ( AppWindow コンテンツ) と AppWindow への参照を解放するには、常に AppWindow.Closed イベントを処理する必要があります。

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

ヒント

予期しない問題を回避するには、 Closed イベント ハンドラー内のコードの量を最小限に抑える必要があります。

AppWindow のインスタンスを追跡する

アプリで複数のウィンドウを使用する方法によっては、作成した AppWindow のインスタンスを追跡する必要がある場合とそうでない場合があります。 HelloAppWindowの例は、AppWindow を通常使用するさまざまな方法を示しています。 ここでは、これらのウィンドウを追跡する必要がある理由と、その方法について説明します。

単純な追跡

カラー ピッカー ウィンドウは 1 つの XAML コントロールをホストし、カラー ピッカーを操作するためのコードはすべて MainPage.xaml.cs ファイルに存在します。 カラー ピッカー ウィンドウでは、1 つのインスタンスのみが許可され、基本的に MainWindowの拡張機能です。 1 つのインスタンスのみが作成されるように、カラー ピッカー ウィンドウはページ レベル変数で追跡されます。 新しいカラー ピッカー ウィンドウを作成する前に、インスタンスが存在するかどうかを確認します。存在する場合は、新しいウィンドウを作成する手順をスキップし、既存のウィンドウで 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に存在します。 これにより、複数のインスタンスが許可され、それぞれのインスタンスが個別に機能します。

ページの機能を使用すると、ウィンドウを操作し、ウィンドウを または に設定したり、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で、ディクショナリを静的プロパティとして作成します。 次に、ページを作成するときに辞書にページを追加し、ページが閉じられたときに削除します。 ElementCompositionPreview.SetAppWindowContentを呼び出した後では、コンテンツ フレーム () から 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 でないように、コンストラクターではなく、ページの Loaded イベント ハンドラーで行う必要があります。 UIContext は、ページ: this.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));

ウィンドウの配置を管理するメソッドの名前は、RequestMoveAdjacentToCurrentView、RequestMoveAdjacentToWindowRequestMoveRelativeToDisplayRegionRequestMoveToDisplayRegionRequestMoveAdjacentToCurrentViewという名前です。

この例では、ウィンドウが生成されるメイン ビューの横にウィンドウを移動します。

colorPickerAppWindow.RequestMoveAdjacentToCurrentView();

ウィンドウの現在のサイズと配置に関する情報を取得するには、 GetPlacement を呼び出します。 これは、ウィンドウの現在の DisplayRegionOffset、および Size を提供する AppWindowPlacement オブジェクトを返します。

たとえば、このコードを呼び出して、ウィンドウをディスプレイの右上隅に移動できます。 このコードは、ウィンドウが表示された後に呼び出す必要があります。それ以外の場合、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 ツリーに追加できるのは 1 回だけです。 あるウィンドウから別のウィンドウに UI の一部を移動する場合は、XAML ツリー内での UI の配置を管理する必要があります。

この例では、 ColorPicker コントロールをメイン ウィンドウとセカンダリ ウィンドウの間で移動しながら再利用する方法を示します。

カラー ピッカーは、 MainPageの XAML で宣言され、 MainPage XAML ツリーに配置されます。

<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 ツリーに追加できます。 ここでは、まず ColorPicker の親コンテナーとなる Grid を作成し、ColorPicker を Grid の子として追加します。 (これにより、後でこの XAML ツリーから ColorPicker を簡単に削除できます)。次に、新しいウィンドウの XAML ツリーのルートとして Grid を設定します。

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) に加えて 1 つ以上の AppWindows を開いている場合、モーダル ダイアログでは、それがルート化されているウィンドウのみがブロックされるため、各ウィンドウでダイアログの開き方を試みることができます。 ただし、スレッドごとに一度に開くことができる ContentDialog は 1 つだけです。 2 つの ContentDialog を開こうとすると、各 ContentDialog が別々の AppWindow で開かれようとしている場合でも、例外がスローされます。

これを管理するには、少なくとも別のダイアログが既に開いている場合に例外をキャッチするために、 try/catch ブロックでダイアログを開く必要があります。

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

ダイアログを管理するもう 1 つの方法は、現在開いているダイアログを追跡し、新しいダイアログを開く前に閉じる方法です。 ここでは、この目的のために MainPageCurrentDialog という名前の静的プロパティを作成してください。

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));
        }
    }
}