Compartir a través de


Mostrar varias vistas con AppWindow

AppWindow y sus API relacionadas simplifican la creación de aplicaciones de varias ventanas al permitirle mostrar el contenido de la aplicación en ventanas secundarias mientras sigue trabajando en el mismo subproceso de interfaz de usuario en cada ventana.

Nota:

AppWindow está actualmente en versión preliminar. Esto significa que puedes enviar aplicaciones que usan AppWindow a la Tienda, pero se sabe que algunos componentes de plataforma y marco no funcionan con AppWindow (consulta Limitaciones).

Aquí se muestran algunos escenarios para varias ventanas con una aplicación de ejemplo denominada HelloAppWindow. La aplicación de ejemplo muestra la siguiente funcionalidad:

  • Desacopla un control de la página principal y ábralo en una nueva ventana.
  • Abra nuevas instancias de una página en nuevas ventanas.
  • Ajustar el tamaño y colocar nuevas ventanas mediante programación en la aplicación.
  • Asocie un ContentDialog con la ventana adecuada de la aplicación.

Aplicación de ejemplo con una sola ventana

Aplicación de ejemplo con una sola ventana

aplicación de ejemplo con selector de colores desacoplado y ventana secundaria

Aplicación de ejemplo con selector de colores desacoplado y ventana secundaria

APIs importantes: espacio de nombres Windows.UI.WindowManagement, clase AppWindow

Introducción a la API

La clase AppWindow y otras API del espacio de nombres WindowManagement están disponibles a partir de Windows 10, versión 1903 (SDK 18362). Si la aplicación tiene como destino versiones anteriores de Windows 10, debes usar ApplicationView para crear ventanas secundarias. Las API de WindowManagement siguen en desarrollo y tienen limitaciones tal como se describe en los documentos de referencia de api.

Estas son algunas de las API importantes que se utilizan para mostrar contenido en un AppWindow.

Ventana de aplicación

La clase AppWindow se puede usar para mostrar una parte de una aplicación para UWP en una ventana secundaria. Es similar en concepto a applicationView, pero no al mismo en comportamiento y duración. Una característica principal de AppWindow es que cada instancia comparte el mismo subproceso de procesamiento de la interfaz de usuario (incluido el distribuidor de eventos) desde el que se crearon, lo que simplifica las aplicaciones de varias ventanas.

Solo puedes conectar contenido XAML a AppWindow, no hay compatibilidad con contenido nativo de DirectX o Holographic. Sin embargo, puedes mostrar un SwapChainPanel XAML que hospeda contenido de DirectX.

WindowingEnvironment

WindowingEnvironment API le permite conocer el entorno en el que se presenta la aplicación para que pueda adaptar la aplicación según sea necesario. Describe el tipo de ventana que admite el entorno; Por ejemplo, Overlapped si la aplicación se ejecuta en un equipo o Tiled si la aplicación se ejecuta en una Xbox. También proporciona un conjunto de objetos DisplayRegion que describen las áreas en las que se puede mostrar una aplicación en una pantalla lógica.

DisplayRegion

La API DisplayRegion describe la región en la que se puede mostrar una vista a un usuario en una pantalla lógica; por ejemplo, en un equipo de escritorio, se trata de la pantalla completa menos el área de la barra de tareas. No es necesariamente una correspondencia 1:1 con el área de visualización física del monitor secundario. Puede haber varias regiones de visualización dentro del mismo monitor o se puede configurar displayRegion para abarcar varios monitores si esos monitores son homogéneos en todos los aspectos.

PresentadorDeVentanaDeAplicación

La API de AppWindowPresenter permite cambiar fácilmente las ventanas a configuraciones predefinidas como FullScreen o CompactOverlay. Estas configuraciones proporcionan al usuario una experiencia coherente en cualquier dispositivo que admita la configuración.

UIContext

UIContext es un identificador único para una ventana o vista de la aplicación. Se crea automáticamente y puede usar la propiedad UIElement.UIContext para recuperar UIContext. Cada UIElement del árbol XAML tiene el mismo UIContext.

UIContext es importante porque API como Window.Current y el patrón GetForCurrentView dependen de tener un único ApplicationView/CoreWindow con un único árbol XAML por subproceso para funcionar correctamente. Este no es el caso cuando se usa una instancia de AppWindow, por lo que se usa UIContext para identificar una ventana determinada en su lugar.

XamlRoot

La clase XamlRoot contiene un árbol de elementos XAML, lo conecta al objeto host de ventana (por ejemplo, AppWindow o ApplicationView) y proporciona información como el tamaño y la visibilidad. No creas un objeto XamlRoot directamente. En su lugar, se crea uno cuando se adjunta un elemento XAML a appWindow. A continuación, puedes usar la propiedad UIElement.XamlRoot para recuperar XamlRoot.

Para obtener más información sobre UIContext y XamlRoot, consulta Haz que el código sea portátil entre hosts de ventanas.

Mostrar una nueva ventana

Echemos un vistazo a los pasos para mostrar contenido en un nuevo AppWindow.

Para mostrar una nueva ventana

  1. Llame al método estático AppWindow.TryCreateAsync para crear una nueva AppWindow.

    AppWindow appWindow = await AppWindow.TryCreateAsync();
    
  2. Cree el contenido de la ventana.

    Normalmente, creas un Frame XAMLy luego navegas ese Frame a una página XAML donde has definido el contenido de tu aplicación. Para obtener más información sobre marcos y páginas, consulta navegación entre pares entre dos páginas.

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

    Sin embargo, puedes mostrar cualquier contenido XAML en AppWindow, no solo un marco y una página. Por ejemplo, puede mostrar solo un solo control, como ColorPicker, o puede mostrar un SwapChainPanel que hospeda contenido de DirectX.

  3. Llame al método ElementCompositionPreview.SetAppWindowContent para adjuntar el contenido XAML a AppWindow.

    ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowContentFrame);
    

    La llamada a este método crea un objeto XamlRoot y lo establece como la propiedad XamlRoot para el UIElement especificado.

    Solo puede llamar a este método una vez por instancia de AppWindow. Una vez establecido el contenido, se producirá un error en las llamadas adicionales a SetAppWindowContent para esta instancia de AppWindow. Además, si intenta desconectar el contenido de AppWindow pasando un objeto UIElement nulo, se producirá un error en la llamada.

  4. Llame al método AppWindow.TryShowAsync para mostrar la nueva ventana.

    await appWindow.TryShowAsync();
    

Liberar recursos cuando se cierra una ventana

Siempre debes controlar el evento AppWindow.Closed para liberar recursos XAML (el contenido de AppWindow) y referencias a AppWindow.

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

Sugerencia

Debe mantener la cantidad de código en el controlador de eventos Closed al mínimo para evitar problemas inesperados.

Seguimiento de instancias de AppWindow

Dependiendo de cómo use varias ventanas en su aplicación, puede que necesite o no realizar un seguimiento de las instancias de AppWindow que cree. En el ejemplo de HelloAppWindow se muestran algunas maneras diferentes de usar normalmente una AppWindow. Aquí veremos por qué se debe realizar un seguimiento de estas ventanas y cómo hacerlo.

Seguimiento simple

La ventana del selector de colores hospeda un único control XAML y el código para interactuar con el selector de colores reside en el MainPage.xaml.cs archivo. La ventana del selector de colores solo permite una sola instancia y es básicamente una extensión de MainWindow. Para asegurarse de que solo se crea una instancia, se realiza un seguimiento de la ventana del selector de colores con una variable de nivel de página. Antes de crear una nueva ventana del selector de colores, compruebe si existe una instancia y, si es así, omita los pasos para crear una nueva ventana y simplemente llame a TryShowAsync en la ventana existente.

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

Seguimiento de una instancia de AppWindow en su contenido hospedado

La AppWindowPage ventana hospeda una página XAML completa y el código para interactuar con la página reside en AppWindowPage.xaml.cs. Permite varias instancias, cada una de las cuales funciona de forma independiente.

La funcionalidad de la página te permite manipular la ventana, estableciéndola en FullScreen o CompactOverlay, y también monitoriza los eventos AppWindow.Changed para mostrar información sobre la ventana. Para llamar a estas API, AppWindowPage necesita una referencia a la instancia de AppWindow que la hospeda.

Si es todo lo que necesita, puede crear una propiedad en AppWindowPage y asignarle la instancia de AppWindow al crearla.

AppWindowPage.xaml.cs

En AppWindowPage, cree una propiedad que mantenga la referencia de AppWindow.

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

    // ...
}

MainPage.xaml.cs

En MainPage, obtenga una referencia a la instancia de página y asigne la instancia de AppWindow recién creada a la propiedad de 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;

    // ...
}

Seguimiento de ventanas de aplicaciones mediante UIContext

También podrías querer tener acceso a las instancias de AppWindow desde otras partes de tu aplicación. Por ejemplo, MainPage podría tener un botón "Cerrar todo" que cierre todas las instancias con seguimiento de AppWindow.

En este caso, debe usar el UIContext identificador único para rastrear las instancias de ventana en un Dictionary.

MainPage.xaml.cs

En MainPage, cree Diccionario como una propiedad estática. A continuación, agregue la página al Diccionario al crearla y quítela cuando se cierre la página. Puede obtener el UIContext del contenido Frame (appWindowContentFrame.UIContext) después de llamar a ElementCompositionPreview.SetAppWindowContent.

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

Para usar la instancia de AppWindow en su código , use el UIContext de la página para recuperarla del diccionario estático en . Debe hacerlo en el controlador de eventos Loaded de la página en lugar de en el constructor para que UIContext no sea nulo. Puede obtener UIContext desde la página: 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;
    }
    // ...
}

Nota:

En el ejemplo HelloAppWindow muestra ambas maneras de seguir la ventana en AppWindowPage, pero normalmente usarás una o la otra, no ambas.

Tamaño y ubicación de la ventana de solicitud

La clase AppWindow tiene varios métodos que puede usar para controlar el tamaño y la ubicación de la ventana. Según lo implícito en los nombres de método, el sistema puede o no respetar los cambios solicitados en función de los factores ambientales.

Llame a RequestSize para especificar un tamaño de ventana deseado, como este.

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

Los métodos para administrar la selección de ubicación de ventana se denominan RequestMove*: RequestMoveAdjacentToCurrentView, RequestMoveAdjacentToWindow, RequestMoveRelativeToDisplayRegion, RequestMoveToDisplayRegion.

En este ejemplo, este código mueve la ventana para que esté junto a la vista principal desde la que se genera la ventana.

colorPickerAppWindow.RequestMoveAdjacentToCurrentView();

Para obtener información sobre el tamaño actual y la ubicación de la ventana, llame a GetPlacement. Esto devuelve un objeto AppWindowPlacement que proporciona el actual DisplayRegion , Offsety Size de la ventana.

Por ejemplo, podría llamar a este código para mover la ventana a la esquina superior derecha de la pantalla. Este código debe llamarse después de que se haya mostrado la ventana; De lo contrario, el tamaño de la ventana devuelto por la llamada a GetPlacement será 0,0 y el desplazamiento será incorrecto.

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

Solicitud de una configuración de presentación

La clase AppWindowPresenter le permite mostrar una AppWindow mediante una configuración predefinida adecuada para el dispositivo donde se presenta. Puede usar un valor AppWindowPresentationConfiguration para colocar la ventana en modo FullScreen o CompactOverlay.

En este ejemplo se muestra cómo hacer lo siguiente:

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

Reutilización de elementos XAML

Una instancia de AppWindow te permite tener varios árboles XAML con el mismo subproceso de interfaz de usuario. Sin embargo, un elemento XAML solo se puede agregar a un árbol XAML una vez. Si quieres mover una parte de la interfaz de usuario de una ventana a otra, tienes que administrarla en el árbol XAML.

En este ejemplo se muestra cómo reutilizar un control ColorPicker mientras se mueve entre la ventana principal y una ventana secundaria.

El seleccionador de color se declara en el XAML para MainPage, lo que lo coloca en el árbol XAML de 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>

Cuando el selector de colores se separa para ubicarlo en un nuevo AppWindow, primero tienes que quitarlo del árbol XAML de MainPage quitándolo de su contenedor primario. Aunque no es necesario, en este ejemplo también se oculta el contenedor primario.

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

A continuación, puedes agregarlo al nuevo árbol XAML. En este caso, primero creará un Grid que será el contenedor primario para ColorPicker y agregará ColorPicker como elemento secundario de la cuadrícula. (Esto te permite quitar fácilmente el ColorPicker de este árbol XAML más adelante). A continuación, estableces la cuadrícula como la raíz del árbol XAML en la nueva ventana.

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

Cuando se cierra el AppWindow, se invierte el proceso. En primer lugar, quite el ColorPicker del Gridy, a continuación, agréguelo como hijo del StackPanel en 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();
}

Mostrar un cuadro de diálogo

De forma predeterminada, los cuadros de diálogo de contenido se muestran de forma modáctica con respecto a applicationView raíz. Cuando usas un ContentDialog dentro de una AppWindow, debes establecer manualmente el XamlRoot del cuadro de diálogo en la raíz del host XAML.

Para ello, establezca la propiedad XamlRoot de ContentDialog en el mismo XamlRoot que un elemento ya presente en AppWindow. Aquí, este código está dentro del manejador de eventos Click de un botón, por lo que puedes usar el remitente (el botón en el que se hace clic) para obtener el XamlRoot.

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

Si tiene una o más AppWindows abiertas además de la ventana principal (ApplicationView), cada ventana puede intentar abrir un cuadro de diálogo, ya que el cuadro de diálogo modal bloqueará solo la ventana en la que está arraigado. Sin embargo, solo puede haber un ContentDialog abierto por subproceso a la vez. Si intenta abrir dos ContentDialogs, se producirá una excepción, incluso si intentan abrirse en AppWindows independientes.

Para gestionarlo, debe al menos abrir el cuadro de diálogo en un bloque try/catch para detectar la excepción en caso de que otro cuadro de diálogo ya esté abierto.

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

Otra manera de administrar diálogos consiste en realizar un seguimiento del cuadro de diálogo abierto actualmente y cerrarlo antes de intentar abrir un diálogo nuevo. Aquí, creará una propiedad estática en MainPage denominada CurrentDialog para este propósito.

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;

   // ...
}

A continuación, compruebe si hay un cuadro de diálogo abierto actualmente y, si existe, llame al método Hide para cerrarlo. Por último, asigne el cuadro de diálogo nuevo a CurrentDialoge intente mostrarlo.

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.
    }
}

Si no es conveniente cerrar un cuadro de diálogo mediante programación, no asígnelo como CurrentDialog. Aquí, MainPage muestra un cuadro de diálogo importante que solo debe descartarse cuando el usuario hace clic en Ok. Dado que no se asigna como CurrentDialog, no se intenta cerrarlo mediante programación.

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.
        }
    }
    // ...
}

Código completo

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