Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
AppWindow e suas APIs relacionadas simplificam a criação de aplicativos com várias janelas, permitindo que você mostre o conteúdo do seu aplicativo em janelas secundárias enquanto continua 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 AppWindow para a Loja, mas alguns componentes de plataforma e estrutura são conhecidos por não funcionar 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:
- Desacoplar um controlador da página principal e abri-lo 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 escolha de cores flutuante e janela secundária
APIs importantes: namespace Windows.UI.WindowManagement, classe AppWindow
Visão geral da API
A classe
Aqui estão algumas das APIs importantes que você usa para mostrar o conteúdo em um AppWindow.
Janela do Aplicativo
A classe AppWindow pode ser usada para exibir uma parte de um aplicativo UWP em uma janela secundária. Ele é semelhante em conceito a um ApplicationView, mas não o mesmo no comportamento e no tempo de vida. Um recurso principal do AppWindow é que cada instância compartilha o mesmo thread de processamento de interface do usuário (incluindo o dispatcher de eventos) do qual foram criados, o que simplifica aplicativos de várias janelas.
Você só pode conectar o conteúdo XAML ao AppWindow, não há suporte para conteúdo nativo do DirectX ou holográfico. No entanto, você pode mostrar uma XAML
Ambiente de Janelas
A API WindowingEnvironment permite que você saiba sobre o ambiente em que seu aplicativo está sendo apresentado para que você possa adaptar seu aplicativo conforme necessário. Ele descreve o tipo de janela 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. Ele também fornece um conjunto de objetos DisplayRegion que descrevem as áreas em que 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 visualização pode ser mostrada ao usuário em uma exibição lógica; por exemplo, em um PC desktop, essa é a área de 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 backup. Pode haver várias regiões de exibição no mesmo monitor ou uma DisplayRegion pode ser configurada para abranger vários monitores se esses monitores forem homogêneos em todos os aspectos.
AppWindowPresenter
A API
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 padrão GetForCurrentView dependem de ter um único ApplicationView/CoreWindow com uma única árvore XAML por thread para trabalhar. Esse não é o caso quando você usa um AppWindow, portanto, 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 um AppWindow. Em seguida, você pode usar a propriedade UIElement.XamlRoot para recuperar o XamlRoot.
Para obter mais informações sobre UIContext e XamlRoot, consulte Tornar o código portátil entre diferentes plataformas de janela.
Mostrar uma nova janela
Vamos dar uma olhada nas etapas para mostrar o conteúdo em um novo AppWindow.
Mostrar uma nova janela
Chame o método estático AppWindow.TryCreateAsync para criar uma nova AppWindow .
AppWindow appWindow = await AppWindow.TryCreateAsync();Crie o conteúdo da janela.
Normalmente, você cria um quadro XAML e, em seguida, navega o Quadro até uma página XAML onde definiu o conteúdo do aplicativo. Para obter mais informações sobre quadros e páginas, consulte navegação entre pares entre duas páginas.
Frame appWindowContentFrame = new Frame(); appWindowContentFrame.Navigate(typeof(AppWindowMainPage));No entanto, você pode mostrar qualquer conteúdo XAML no AppWindow, não apenas um Quadro e Uma Página. Por exemplo, você pode mostrar apenas um único controle, como ColorPicker, ou mostrar um SwapChainPanel que hospeda o conteúdo do DirectX.
Chame o método ElementCompositionPreview.SetAppWindowContent para anexar o conteúdo XAML ao AppWindow.
ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowContentFrame);A chamada para esse método cria um objeto
XamlRoot e o define como a propriedadeXamlRoot 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, novas chamadas para SetAppWindowContent para esta instância do 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 lidar com o evento AppWindow.Closed para liberar recursos XAML (o conteúdo appWindow) e referências ao AppWindow.
appWindow.Closed += delegate
{
appWindowContentFrame.Content = null;
appWindow = null;
};
Dica
Você deve manter a quantidade de código em seu manipulador de eventos Closed ao valor mínimo possível para evitar problemas inesperados.
Acompanhar instâncias do AppWindow
Dependendo de como você usa várias janelas em seu aplicativo, você pode ou não precisar acompanhar as instâncias do AppWindow que você cria. O exemplo de HelloAppWindow mostra algumas maneiras diferentes de você normalmente usar um AppWindow . Aqui, veremos por que essas janelas devem ser rastreadas e como fazer isso.
Acompanhamento 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 única instância e é essencialmente uma extensão de MainWindow. Para garantir que apenas uma instância seja criada, usa-se uma variável de nível de página para rastrear a janela do seletor de cores. 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();
}
Acompanhar uma instância do 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 das quais funciona de forma independente.
A funcionalidade da página permite manipular a janela, defini-la como FullScreen ou CompactOverlaye também escuta eventos AppWindow.Changed para mostrar informações sobre a janela. Para chamar essas APIs, AppWindowPage precisa de uma referência à instância do AppWindow que a hospeda.
Se for só isso que você precisa, pode criar uma propriedade em AppWindowPage e atribuir a instância AppWindow a ela ao criá-la.
AppWindowPage.xaml.cs
Em AppWindowPage, crie uma propriedade para manter a referência 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 da página e atribua o AppWindow recém-criado à 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;
// ...
}
Acompanhamento de janelas do aplicativo usando UIContext
Você talvez também queira acessar as instâncias AppWindow a partir de outras partes do seu aplicativo. Por exemplo, MainPage pode ter um botão "fechar tudo" que fecha todas as instâncias controladas do AppWindow.
Nesse caso, você deve usar o
MainPage.xaml.cs
Em MainPage, crie o Dicionário como uma propriedade estática. Em seguida, adicione a página ao Dicionário ao criá-la e remova-a quando a página for fechada. Você pode acessar 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 exemplo HelloAppWindow mostra as duas maneiras de acompanhar a janela em AppWindowPage, mas você normalmente usará uma ou outra, não ambas.
Tamanho e posicionamento da janela de solicitação
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 do método, o sistema pode ou não respeitar as alterações solicitadas, dependendo dos fatores ambientais.
Chame RequestSize para especificar um tamanho de janela desejado, assim.
colorPickerAppWindow.RequestSize(new Size(300, 428));
Os métodos para gerenciar o posicionamento da janela são nomeados RequestMove*: RequestMoveAdjacentToCurrentView, RequestMoveAdjacentToWindow, RequestMoveRelativeToDisplayRegion, RequestMoveToDisplayRegion.
Neste exemplo, esse código move a janela para estar 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. Isso retorna um objeto
Por exemplo, você pode chamar esse código para mover a janela para o canto superior direito da exibição. Esse código deve ser chamado após a exibição da janela; caso contrário, o tamanho da janela retornado pela chamada para GetPlacement será 0,0 e o deslocamento será 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 um AppWindow usando uma configuração predefinida apropriada para o dispositivo em que ele é mostrado. Você pode usar um valor
Este exemplo mostra como fazer o seguinte:
- Use o evento AppWindow.Changed para ser notificado se as apresentações de janela disponíveis forem alteradas.
- Use a propriedade AppWindow.Presenter para obter o AppWindowPresenter atual.
- Chame IsPresentationSupported para verificar se um AppWindowPresentationKind específico é suportado.
- Chame GetConfiguration para verificar que tipo de configuração é usada no momento.
- 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 usando o mesmo thread de UI. No entanto, um elemento XAML só pode ser adicionado a uma árvore XAML uma vez. Se você quiser mover uma parte da interface do usuário de uma janela para outra, precisará gerenciar o posicionamento dela 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 MainPage, o que o coloca na árvore XAML 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 um novo AppWindow, você precisa primeiro removê-lo da árvore XAML 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á-la à nova árvore XAML. Aqui, primeiro você cria um Grid que será o contêiner pai do ColorPicker e adicionará o ColorPicker como elemento filho do Grid. (Isso permite que você remova facilmente o ColorPicker desta árvore XAML mais tarde.) 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 o AppWindow for fechado, você inverte o processo. Primeiro, remova o
// 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 do ApplicationView. Dentro de um AppWindow, quando você usa um ContentDialog, é necessário definir manualmente o XamlRoot na caixa de diálogo para a raiz do host XAML.
Para fazer isso, defina a propriedade XamlRoot do ContentDialog como a mesma XamlRoot que um elemento já no AppWindow. Aqui, esse código está dentro do manipulador de eventos Click de um botão, permitindo que você use o sender (o botão 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 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ó pode haver um ContentDialog aberto por thread de cada vez. A tentativa de abrir dois ContentDialogs gerará uma exceção, mesmo que eles estejam tentando abrir em AppWindows separados.
Para gerenciar isso, você deve, no mínimo, abrir 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 é acompanhar 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, você verifica se há uma caixa de diálogo aberta no momento e, se houver, chame o método Ocultar para fechá-la. Por fim, atribua a nova caixa de diálogo a CurrentDialoge tente exibi-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.
}
}
Se não for desejável ter uma caixa de diálogo fechada programaticamente, não atribua-a como CurrentDialog. Aqui, MainPage mostra uma caixa de diálogo importante que só deve ser descartada quando o usuário clica em Ok. Como isso não está atribuído como CurrentDialog, não se faz nenhuma tentativa de 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));
}
}
}