Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
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
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
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
Chame o estático AppWindow.TryCreateAsync método para criar um novo AppWindow.
AppWindow appWindow = await AppWindow.TryCreateAsync();
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.
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á.
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
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
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 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:
- Use o evento AppWindow.Changed para ser notificado se as apresentações de janela disponíveis mudarem.
- Use a propriedade AppWindow.Presenter para obter o atual AppWindowPresenter.
- Chame IsPresentationSupported para ver se um AppWindowPresentationKind específico é suportado.
- Chame GetConfiguration para verificar que tipo de configuração está a ser usada atualmente.
- Chame 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
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="" />
</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
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 CurrentDialog
e 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="" />
</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));
}
}
}