Mostrar várias exibições com AppWindow
A AppWindow e suas APIs relacionadas simplificam a criação de aplicativos com várias janelas, permitindo que você mostre o conteúdo do aplicativo em janelas secundárias enquanto ainda está trabalhando no mesmo thread de interface do usuário em cada janela.
Observação
AppWindow está atualmente em versão prévia. Isso significa que você pode enviar aplicativos que usam o AppWindow à Store, mas alguns componentes de plataforma e estrutura são conhecidos por não funcionar com o AppWindow (confira Limitações).
Aqui, mostramos alguns cenários para várias janelas com o aplicativo de exemplo HelloAppWindow
. O aplicativo de exemplo demonstra as seguintes funcionalidades:
- Desencaixar um controle da página principal e abre-o em uma nova janela.
- Abrir novas instâncias de Page em novas janelas.
- Dimensionar e posicionar programaticamente novas janelas no aplicativo.
- Associar um ContentDialog à janela apropriada no aplicativo.
Aplicativo de exemplo com uma única janela
Aplicativo de exemplo com seletor de cores desencaixado 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). Caso seu aplicativo seja destinado a versões anteriores do Windows 10, use 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 de API.
Aqui estão algumas das APIs importantes usadas para mostrar o conteúdo em uma AppWindow.
AppWindow
A classe AppWindow pode ser usada para exibir uma parte do aplicativo UWP em uma janela secundária. É semelhante em conceito a uma ApplicationView, mas não tem o mesmo comportamento e tempo de vida. O principal recurso de AppWindow é que cada instância compartilha o mesmo thread de processamento da interface do usuário (incluindo o dispatcher de eventos) 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 do DirectX ou do Holographic. No entanto, você pode mostrar um SwapChainPanel do XAML que hospeda conteúdo do DirectX.
WindowingEnvironment
A API WindowingEnvironment possibilita que você conheça o ambiente em que seu aplicativo está sendo apresentado, de modo que você possa adaptar o aplicativo de acordo com a necessidade. Ela descreve o tipo de janela a que o ambiente dá suporte; por exemplo, Overlapped
se o aplicativo estiver em execução em um computador ou Tiled
se o aplicativo estiver em execução em um Xbox. Também fornece um conjunto de objetos DisplayRegion que descreve as áreas em que um aplicativo pode ser mostrado em uma exibição lógica.
DisplayRegion
A API DisplayRegion descreve a região em que uma exibição pode ser mostrada a um usuário em uma exibição lógica; por exemplo, em um computador desktop, é a exibição completa 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 é possível configurar uma DisplayRegion para abranger vários monitores, caso esses monitores sejam homogêneos em todos os aspectos.
AppWindowPresenter
A API AppWindowPresenter permite alternar facilmente o Windows para configurações predefinidas, como FullScreen
ou CompactOverlay
. Essas configurações fornecem ao usuário uma experiência consistente em qualquer dispositivo que dê suporte à configuração.
UIContext
UIContext é um identificador exclusivo para uma janela ou exibição de aplicativo. É criado automaticamente, e você pode usar a propriedade UIElement.UIContext para recuperar o UIContext. Todo UIElement na árvore XAML tem o mesmo UIContext.
O UIContext é importante porque APIs como Window.Current e o padrão GetForCurrentView
precisam ter uma única ApplicationView/CoreWindow com uma única árvore XAML por thread com as quais possam trabalhar. Esse não é o caso quando você usa uma AppWindow, portanto, use UIContext para identificar uma janela específica.
XamlRoot
A classe XamlRoot mantém uma árvore de elementos XAML, conecta-a ao objeto de host da janela (por exemplo, a AppWindow ou ApplicationView) e fornece informações como tamanho e visibilidade. Você não cria um objeto XamlRoot diretamente. Em vez disso, ele é criado quando você anexa um elemento XAML a uma AppWindow. Em seguida, você pode usar a propriedade UIElement.XamlRoot para recuperar o XamlRoot.
Para obter mais informações sobre UIContext e XamlRoot, confira Viabilizar a portabilidade de código em hosts de janelas.
Mostrar uma nova janela
Vamos dar uma olhada nas etapas para mostrar o conteúdo em uma nova AppWindow.
Para mostrar uma nova janela
Chame o método estático AppWindow.TryCreateAsync para criar uma AppWindow.
AppWindow appWindow = await AppWindow.TryCreateAsync();
Crie o conteúdo da janela.
Normalmente, você adiciona um Frame XAML e passa o Frame para uma Page XAML em que definiu o conteúdo do aplicativo. Para obter mais informações sobre quadros e páginas, confira Navegação ponto a ponto entre duas páginas.
Frame appWindowContentFrame = new Frame(); appWindowContentFrame.Navigate(typeof(AppWindowMainPage));
No entanto, você pode mostrar qualquer conteúdo XAML na AppWindow, não apenas um quadro e uma página. Por exemplo, você pode mostrar apenas um controle, como ColorPicker, ou pode mostrar um SwapChainPanel que hospeda conteúdo do DirectX.
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 de AppWindow. Depois que o conteúdo for definido, outras chamadas para SetAppWindowContent nessa instância de AppWindow falharão. Além disso, se você tentar desconectar o conteúdo da AppWindow passando um objeto UIElement nulo, a chamada falhará.
Chame o método AppWindow.TryShowAsync para mostrar a nova janela.
await appWindow.TryShowAsync();
Liberar recursos quando uma janela for fechada
Você sempre deve manipular com o evento AppWindow.Closed para liberar recursos XAML (o conteúdo da AppWindow) e fazer referências a AppWindow.
appWindow.Closed += delegate
{
appWindowContentFrame.Content = null;
appWindow = null;
};
Dica
Use o mínimo de código possível no manipulador de eventos Closed
para evitar problemas inesperados.
Rastrear instâncias de AppWindow
Dependendo de como usa várias janelas em seu aplicativo, você pode ou não precisar manter o controle das instâncias de AppWindow que criar. O exemplo HelloAppWindow
mostra algumas maneiras diferentes pelas quais você normalmente pode usar uma AppWindow. Aqui, veremos por que essas janelas devem ser rastreadas e como fazer isso.
Rastreamento simples
A janela Seletor de cores hospeda um único controle XAML, e o código para interagir com o seletor de cores reside no arquivo MainPage.xaml.cs
. A janela do seletor de cores só permite uma instância e é essencialmente uma extensão de MainWindow
. Para garantir que apenas uma instância seja criada, a janela do seletor de cores é rastreada com uma variável de nível de página. Antes de criar uma janela do seletor de cores, verifique se existe uma instância e, caso haja, ignore as etapas para criar uma janela e apenas chame 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 de AppWindow em seu conteúdo hospedado
A janela AppWindowPage
hospeda uma página XAML completa, e o código para interagir com a página reside em AppWindowPage.xaml.cs
. Ele permite várias instâncias, cada uma funcionando de forma independente.
A funcionalidade da página permite manipular a janela, definindo-a como FullScreen
ou CompactOverlay
, e também escuta os eventos de AppWindow.Changed para mostrar informações sobre a janela. Para chamar essas APIs, AppWindowPage
precisa de uma referência à instância AppWindow que a hospeda.
Se isso for tudo o que você precisa, você poderá criar uma propriedade em AppWindowPage
e atribuir a instância da AppWindow a ela durante a criação.
AppWindowPage.xaml.cs
Em AppWindowPage
, crie uma propriedade para manter a referência a AppWindow.
public sealed partial class AppWindowPage : Page
{
public AppWindow MyAppWindow { get; set; }
// ...
}
MainPage.xaml.cs
Em MainPage
, obtenha uma referência para a instância de page e atribua a AppWindow recém-criada à 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;
// ...
}
Rastrear janelas do aplicativo usando UIContext
Talvez você também queira ter acesso às instâncias de AppWindow em outras partes do seu aplicativo. Por exemplo, MainPage
pode ter um botão "fechar tudo" para fechar todas as instâncias rastreadas de AppWindow.
Nesse caso, você deve usar o identificador exclusivo de UIContext para rastrear as instâncias de janela em um Dictionary.
MainPage.xaml.cs
Em MainPage
, crie Dictionary como uma propriedade estática. Em seguida, adicione a página a Dictionary ao criá-la 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 de AppWindow no seu código AppWindowPage
, use o UIContext da página para recuperá-la do Dictionary estático em MainPage
. Você deve fazer isso no manipulador de eventos Loaded da página, e não no construtor, para que o UIContext não seja nulo. 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 exemplo HelloAppWindow
mostra as duas maneiras de rastrear a janela em AppWindowPage
, mas normalmente se usa uma ou outra, e 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. Como os nomes dos métodos deixam implícito, o sistema pode ou não honrar as alterações solicitadas, dependendo dos fatores ambientais.
Chame RequestSize para especificar o tamanho desejado da janela, como este.
colorPickerAppWindow.RequestSize(new Size(300, 428));
Os métodos para gerenciar o posicionamento de janelas são chamados de RequestMove* : RequestMoveAdjacentToCurrentView, RequestMoveAdjacentToWindow, RequestMoveRelativeToDisplayRegion, RequestMoveToDisplayRegion.
Neste exemplo, o código move a janela para que fique ao lado da exibição principal da qual a janela é gerada.
colorPickerAppWindow.RequestMoveAdjacentToCurrentView();
Para obter informações sobre o tamanho e o posicionamento atuais da janela, chame GetPlacement. Ele retorna um objeto AppWindowPlacement que fornece as informações atuais de DisplayRegion, Offset e Size da janela.
Por exemplo, você poderia chamar esse código para mover a janela para o canto superior direito da exibição. Este código deverá ser chamado depois que a janela for exibida; 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 que você mostre uma AppWindow usando uma configuração predefinida apropriada para o dispositivo no qual ela é mostrada. É possível usar o valor AppWindowPresentationConfiguration para colocar a janela no modo FullScreen
ou CompactOverlay
.
Este exemplo mostra como fazer o seguinte:
- Usar o evento AppWindow.Changed para ser notificado se as apresentações de janela disponíveis forem alteradas.
- Usar a propriedade AppWindow.Presenter para obter a AppWindowPresenter atual.
- Chamar IsPresentationSupported para ver se há suporte para um AppWindowPresentationKind específico.
- Chamar GetConfiguration para verificar que tipo de configuração está em uso no momento.
- Chamar RequestPresentation para alterar a configuração atual.
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
Uma 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 uma vez a uma árvore XAML. Caso queira mover uma parte da interface do usuário de uma janela para outra, você precisará gerenciá-la 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 cor é declarado no XAML para MainPage
, que o coloca na árvore XAML de MainPage
.
<StackPanel x:Name="colorPickerContainer" Grid.Column="1" Background="WhiteSmoke">
<Button Click="DetachColorPickerButton_Click" HorizontalAlignment="Right">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="" />
</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 de MainPage
retirando-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ê cria primeiro uma Grid que será o contêiner pai do ColorPicker e adiciona o ColorPicker como um filho de Grid. (Isso permite que você remova facilmente o ColorPicker desta árvore XAML posteriormente.) Em seguida, defina a grade 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 a AppWindow é fechada, você reverte o processo. Primeiro, remova ColorPicker de Grid e, em seguida, adicione-o como um filho de 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 modalmente em relação à ApplicationView raiz. Quando você usa ContentDialog dentro de uma AppWindow, é preciso definir manualmente XamlRoot na caixa de diálogo para a raiz do host XAML.
Para fazer isso, defina a propriedade XamlRoot de ContentDialog para o mesmo XamlRoot que um elemento já presente na AppWindow. Aqui, o código está dentro do manipulador de eventos Click de um botão, de modo que você pode usar sender (o botão clicado) para obter o XamlRoot.
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
{
simpleDialog.XamlRoot = ((Button)sender).XamlRoot;
}
Caso você tenha uma ou mais AppWindows abertas além da janela principal (ApplicationView), cada janela poderá tentar abrir uma caixa de diálogo, pois a caixa de diálogo modal bloqueará apenas a janela na qual ela está enraizada. No entanto, só é possível haver uma ContentDialog aberta por thread de cada vez. A tentativa de abrir duas ContentDialogs lançará uma exceção, mesmo que estejam tentando abrir em AppWindows separadas.
Para gerenciar isso, você deve abrir pelo menos a caixa de diálogo em um bloco try/catch
para capturar 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 atualmente aberta e fechá-la antes de tentar abrir uma nova caixa. 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, você verifica se há uma caixa de diálogo aberta no momento e, se houver, chama o método Hide para fechá-la. Por fim, atribua a nova caixa de diálogo para CurrentDialog
e tente mostrá-la.
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.
}
}
Caso não queira fechar programaticamente uma caixa de diálogo, não a atribua como CurrentDialog
. Aqui, MainPage
mostra uma caixa de diálogo importante que só deverá ser descartada quando o usuário clicar em Ok
. Como ela não está atribuída como a CurrentDialog
, nenhuma tentativa é feita para fechá-la 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="" />
</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));
}
}
}
Tópicos relacionados
Windows developer