Partilhar via


Mostrar várias visualizações com AppWindow

AppWindow e suas APIs relacionadas simplificam a criação de aplicativos de várias janelas, permitindo que você mostre o conteúdo do aplicativo em janelas secundárias enquanto ainda trabalha no mesmo thread da interface do usuário em cada janela.

Observação

AppWindow está atualmente em fase de testes. Isso significa que você pode enviar aplicativos que usam AppWindow para a Loja, mas alguns componentes de plataforma e estrutura são conhecidos por não funcionarem com AppWindow (consulte Limitações).

Aqui, mostramos alguns cenários para várias janelas com um aplicativo de exemplo chamado HelloAppWindow. O aplicativo de exemplo demonstra a seguinte funcionalidade:

  • Desencaixe um controle da página principal e abra-o em uma nova janela.
  • Abra novas instâncias de uma Página em novas janelas.
  • Dimensionar e posicionar novas janelas programaticamente no aplicativo.
  • Associe um ContentDialog à janela apropriada no aplicativo.

Aplicativo de exemplo com uma única janela

Aplicativo de exemplo com uma única janela

Aplicação de exemplo com seletor de cores flutuante e janela secundária

App de exemplo com paleta de cores desacoplada e janela secundária

APIs importantes: namespace Windows.UI.WindowManagement, classe AppWindow

Visão geral da API

A classe AppWindow e outras APIs no namespace WindowManagement estão disponíveis a partir do Windows 10, versão 1903 (SDK 18362). Se o seu aplicativo tiver como destino versões anteriores do Windows 10, você deverá usar ApplicationView para criar janelas secundárias. As APIs do WindowManagement ainda estão em desenvolvimento e têm limitações conforme descrito nos documentos de referência da API.

Aqui estão algumas das APIs importantes que você usa para mostrar conteúdo em uma AppWindow.

Janela da Aplicação

A classe AppWindow pode ser usada para exibir uma parte de um aplicativo UWP em uma janela secundária. É semelhante em conceito a um ApplicationView, mas não o mesmo em comportamento e tempo de vida. Um recurso principal do AppWindow é que cada instância compartilha o mesmo thread de processamento da interface do usuário (incluindo o dispatcher de eventos) a partir do qual foram criadas, o que simplifica os aplicativos de várias janelas.

Você só pode conectar conteúdo XAML à sua AppWindow, não há suporte para conteúdo nativo DirectX ou Holográfico. No entanto, pode exibir um SwapChainPanel XAML que hospeda conteúdo DirectX.

Ambiente de janelas

A API WindowingEnvironment permite que você saiba sobre o ambiente onde seu aplicativo está sendo apresentado para que você possa adaptá-lo conforme necessário. Descreve o tipo de janela que o ambiente suporta; por exemplo, Overlapped se a aplicação estiver a ser executada num PC ou Tiled se a aplicação estiver a ser executada numa Xbox. Ele também fornece um conjunto de objetos DisplayRegion que descrevem as áreas nas quais um aplicativo pode ser mostrado em uma exibição lógica.

Região de Exibição

A API DisplayRegion descreve a região na qual uma vista pode ser mostrada a um utilizador num ecrã lógico; por exemplo, num computador de secretária, este é o ecrã completo menos a área da barra de tarefas. Não é necessariamente um mapeamento 1:1 com a área de exibição física do monitor de suporte. Pode haver várias regiões de exibição dentro do mesmo monitor ou uma DisplayRegion pode ser configurada para abranger vários monitores se esses monitores forem homogêneos em todos os aspetos.

Apresentador de Janela de Aplicação

A API AppWindowPresenter permite alternar facilmente janelas para configurações predefinidas, como FullScreen ou CompactOverlay. Essas configurações oferecem ao usuário uma experiência consistente em qualquer dispositivo que suporte a configuração.

UIContext

UIContext é um identificador exclusivo para uma janela ou exibição de aplicativo. Ele é criado automaticamente e você pode usar a propriedade UIElement.UIContext para recuperar o UIContext. Cada UIElement na árvore XAML tem o mesmo UIContext.

UIContext é importante porque APIs como Window.Current e o GetForCurrentView padrão dependem de ter um único ApplicationView/CoreWindow com uma única árvore XAML por thread para trabalhar. Este não é o caso quando você usa uma AppWindow, então você usa UIContext para identificar uma janela específica.

XamlRoot

A classe XamlRoot contém uma árvore de elementos XAML, conecta-a ao objeto host da janela (por exemplo, AppWindow ou ApplicationView) e fornece informações como tamanho e visibilidade. Você não cria um objeto XamlRoot diretamente. Em vez disso, um é criado quando você anexa um elemento XAML a uma AppWindow. Em seguida, você pode usar a propriedade UIElement.XamlRoot para recuperar a XamlRoot.

Para saber mais sobre UIContext e XamlRoot, consulte Tornar o código portátil em diferentes ambientes de janela.

Mostrar uma nova janela

Vamos dar uma olhada nas etapas para mostrar conteúdo em uma nova AppWindow.

Para mostrar uma nova janela

  1. Chame o estático AppWindow.TryCreateAsync método para criar um novo AppWindow.

    AppWindow appWindow = await AppWindow.TryCreateAsync();
    
  2. Crie o conteúdo da janela.

    Normalmente, você cria umde Quadro XAML e, em seguida, navega pelo Quadro até um Página de XAML onde você definiu o conteúdo do aplicativo. Para mais informações sobre quadros e páginas, veja Navegação par-a-par entre duas páginas.

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

    No entanto, pode mostrar qualquer conteúdo XAML na AppWindow, não apenas um Frame e uma Page. Por exemplo, você pode mostrar apenas um único controle, como ColorPicker, ou pode mostrar um SwapChainPanel que hospeda conteúdo DirectX.

  3. Chame o método ElementCompositionPreview.SetAppWindowContent para anexar o conteúdo XAML à AppWindow.

    ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowContentFrame);
    

    A chamada para esse método cria um objeto XamlRoot e o define como a propriedade XamlRoot para o UIElement especificado.

    Você só pode chamar esse método uma vez por instância do AppWindow. Depois que o conteúdo tiver sido definido, outras chamadas para SetAppWindowContent para essa instância de AppWindow falharão. Além disso, se você tentar desconectar o conteúdo do AppWindow passando um objeto UIElement nulo, a chamada falhará.

  4. Chame o método AppWindow.TryShowAsync para mostrar a nova janela.

    await appWindow.TryShowAsync();
    

Liberar recursos quando uma janela é fechada

Você sempre deve manipular o evento AppWindow.Closed para liberar recursos XAML (o conteúdo AppWindow) e referências à AppWindow.

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

Sugestão

Você deve manter a quantidade de código em seu Closed manipulador de eventos ao mínimo possível para evitar problemas inesperados.

Rastrear instâncias de AppWindow

Dependendo de como você usa várias janelas em seu aplicativo, talvez seja necessário ou não acompanhar as instâncias do AppWindow criadas. O exemplo HelloAppWindow mostra algumas maneiras diferentes de usar normalmente um AppWindow. Aqui, veremos por que essas janelas devem ser rastreadas e como fazê-lo.

Rastreamento simples

A janela do seletor de cores hospeda um único controle XAML e o código para interagir com o seletor de cores reside no MainPage.xaml.cs arquivo. A janela do seletor de cores permite apenas uma única instância e é essencialmente uma extensão do MainWindow. Para garantir que apenas uma instância seja criada, a janela do seletor de cores é monitorizada através de uma variável ao nível da página. Antes de criar uma nova janela de seletor de cores, verifique se uma instância existe e, se existir, ignore as etapas para criar uma nova janela e chame apenas TryShowAsync na janela 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();
}

Rastrear uma instância do AppWindow em seu conteúdo hospedado

A AppWindowPage janela hospeda uma página XAML completa e o código para interagir com a página reside no AppWindowPage.xaml.cs. Permite várias instâncias, cada uma das quais funciona de forma independente.

A funcionalidade da página permite manipular a janela, configurando-a para FullScreen ou CompactOverlay, e também escuta eventos AppWindow.Changed de e para mostrar informações sobre a janela. Para chamar essas APIs, AppWindowPage precisa de uma referência à instância do AppWindow que está hospedando-o.

Se for tudo de que precisas, podes criar uma propriedade em e atribuir a instância AppWindow do a ela quando a criares.

AppWindowPage.xaml.cs

No AppWindowPage, crie uma propriedade para guardar a referência AppWindow.

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

    // ...
}

MainPage.xaml.cs

No MainPage, obtenha uma referência à instância de página e atribua ao AppWindow recém-criado a propriedade em 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;

    // ...
}

Rastreando janelas de aplicativos usando UIContext

Você também pode querer ter acesso às instâncias de AppWindow de outras partes do seu aplicativo. Por exemplo, MainPage pode ter um botão 'fechar tudo' que fecha todas as instâncias rastreadas do AppWindow.

Nesse caso, você deve usar o UIContext identificador exclusivo para controlar as instâncias de janela em umDicionário.

MainPage.xaml.cs

No MainPage, crie o dicionário como uma propriedade estática. Em seguida, adicione a página ao dicionário quando a criar e remova-a quando a página for fechada. Você pode obter o UIContext do conteúdo Frame (appWindowContentFrame.UIContext) depois de chamar 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 a instância AppWindow em seu código , use o UIContext página para recuperá-lo do dicionário estático no . Você deve fazer isso no manipulador de eventos Loaded da página em vez de no construtor para que UIContext não seja null. Você pode obter o UIContext na 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;
    }
    // ...
}

Observação

O HelloAppWindow exemplo mostra as duas maneiras de rastrear a janela no AppWindowPage, mas você normalmente usará uma ou outra, não ambas.

Solicitar tamanho e posicionamento da janela

A classe AppWindow tem vários métodos que você pode usar para controlar o tamanho e o posicionamento da janela. Conforme implícito pelos nomes dos métodos, o sistema pode ou não honrar as alterações solicitadas dependendo de fatores ambientais.

Chame RequestSize para especificar um tamanho de janela desejado, como este.

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

Os métodos para gerenciar o posicionamento da janela são chamados RequestMove*: RequestMoveAdjacentToCurrentView, RequestMoveAdjacentToWindow, RequestMoveRelativeToDisplayRegion, RequestMoveToDisplayRegion.

Neste exemplo, esse código move a janela para estar ao lado da exibição principal a partir da qual a janela é gerada.

colorPickerAppWindow.RequestMoveAdjacentToCurrentView();

Para obter informações sobre o tamanho atual e o posicionamento da janela, chame GetPlacement. Isso retorna um objeto AppWindowPlacement que fornece a DisplayRegionatual, o Offsete o Size da janela.

Por exemplo, você pode chamar esse código para mover a janela para o canto superior direito da tela. Este código tem de ser chamado depois de a janela ter sido apresentada; caso contrário, o Tamanho da janela retornado pela chamada para GetPlacement será 0,0 e o deslocamento estará incorreto.

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

Solicitar uma configuração de apresentação

A classe AppWindowPresenter permite mostrar uma AppWindow usando uma configuração predefinida apropriada para o dispositivo em que ela é mostrada. Você pode usar um valor de AppWindowPresentationConfiguration para colocar a janela no modo FullScreen ou CompactOverlay.

Este exemplo mostra como fazer o seguinte:

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

Reutilizar elementos XAML

Um AppWindow permite que você tenha várias árvores XAML com o mesmo thread de interface do usuário. No entanto, um elemento XAML só pode ser adicionado a uma árvore XAML uma vez. Se quiser mover uma parte da interface do usuário de uma janela para outra, você precisa gerenciar seu posicionamento na árvore XAML.

Este exemplo mostra como reutilizar um controle ColorPicker ao movê-lo entre a janela principal e uma janela secundária.

O seletor de cores é declarado no XAML para o MainPage, o que o coloca na árvore XAML do 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>

Quando o seletor de cores é desanexado para ser colocado em uma nova AppWindow, primeiro você precisa removê-lo da árvore XAML MainPage removendo-o de seu contêiner pai. Embora não seja necessário, este exemplo também oculta o contêiner pai.

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

Em seguida, você pode adicioná-lo à nova árvore XAML. Aqui, você primeiro cria uma Grelha que será o contenedor pai para o ColorPicker e adiciona o ColorPicker como filho da Grelha. (Isso permite que você remova facilmente o ColorPicker dessa árvore XAML mais tarde.) Em seguida, defina a Grid como a raiz da árvore XAML na nova janela.

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

Quando o AppWindow é fechado, você inverte o processo. Primeiro, remova o ColorPicker do Grid , e depois adicione-o como filho do StackPanel em 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 uma caixa de diálogo

Por padrão, as caixas de diálogo de conteúdo são exibidas de forma modal em relação à raiz ApplicationView. Ao usar um ContentDialog dentro de um AppWindow, é necessário definir manualmente a XamlRoot na caixa de diálogo para a raiz do host XAML.

Para fazer isso, defina a propriedade XamlRoot do ContentDialog para o mesmo XamlRoot de um elemento já presente na AppWindow. Aqui, esse código está dentro do manipulador de eventos Click de um botão, para que você possa usar o de remetente (o Button clicado) para obter o XamlRoot.

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

Se você tiver um ou mais AppWindows abertos, além da janela principal (ApplicationView), cada janela pode tentar abrir uma caixa de diálogo, porque a caixa de diálogo modal bloqueará apenas a janela na qual está enraizada. No entanto, só pode haver um ContentDialog aberto por thread de cada vez. A tentativa de abrir dois ContentDialogs lançará uma exceção, mesmo que eles estejam tentando abrir em AppWindows separados.

Para gerir isto, deve-se, pelo menos, abrir a caixa de diálogo num bloco de try/catch para captar a exceção caso outra caixa de diálogo já esteja aberta.

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

Outra maneira de gerenciar caixas de diálogo é rastrear a caixa de diálogo aberta no momento e fechá-la antes de tentar abrir uma nova caixa de diálogo. Aqui, você cria uma propriedade estática em MainPage chamada CurrentDialog para essa finalidade.

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;

   // ...
}

Em seguida, verifique se há uma caixa de diálogo aberta no momento e, se houver, chame o método Hide para fechá-la. Por fim, atribua o novo diálogo a CurrentDialoge tente mostrá-lo.

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

Se não for desejável ter uma caixa de diálogo fechada programaticamente, não a atribua como .CurrentDialog Aqui, MainPage mostra uma caixa de diálogo importante que só deve ser fechada quando o utilizador clica em Ok. Como ele não é atribuído como o CurrentDialog, nenhuma tentativa é feita para fechá-lo programaticamente.

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