Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
AppWindow und die zugehörigen APIs vereinfachen die Erstellung von Mehrfenster-Apps, indem Sie Ihren App-Inhalt in sekundären Fenstern anzeigen können, während Sie weiterhin an demselben UI-Thread in jedem Fenster arbeiten.
Hinweis
AppWindow befindet sich derzeit in der Vorschauphase. Dies bedeutet, dass Sie Apps, die AppWindow verwenden, in den Store übermitteln können. Es ist jedoch bekannt, dass einige Plattform- und Framework-Komponenten nicht mit AppWindow funktionieren (siehe Einschränkungen).
Hier zeigen wir einige Szenarien für mehrere Fenster mit einer Beispiel-App namens HelloAppWindow. Die Beispiel-App veranschaulicht die folgenden Funktionen:
- Lösen Sie ein Steuerelement von der Hauptseite und öffnen Sie es in einem neuen Fenster.
- Öffnen Sie neue Instanzen einer Seite in neuen Fenstern.
- Programmgesteuerte Größe und Position neuer Fenster in der App.
- Ordnen Sie ein ContentDialog-Fenster dem entsprechenden Fenster in der App zu.
Beispiel-App mit einem einzelnen Fenster
Beispiel-App mit nicht angedocktem Farbwahler und sekundärem Fenster
Wichtige APIs: Windows.UI.WindowManagement-Namespace, AppWindow-Klasse
API-Übersicht
Die AppWindow-Klasse und andere APIs im WindowManagement-Namespace sind ab Windows 10, Version 1903 (SDK 18362) verfügbar. Wenn Ihre App auf frühere Versionen von Windows 10 ausgerichtet ist, müssen Sie ApplicationView verwenden, um sekundäre Fenster zu erstellen. WindowManagement-APIs befinden sich noch in der Entwicklung und weisen Einschränkungen auf, wie in den API-Referenzdokumenten beschrieben.
Hier sind einige der wichtigen APIs, die Sie zum Anzeigen von Inhalten in einer AppWindow verwenden.
App-Fenster
Die AppWindow-Klasse kann verwendet werden, um einen Teil einer UWP-App in einem sekundären Fenster anzuzeigen. Es ist ähnlich im Konzept einem ApplicationView, unterscheidet sich jedoch im Verhalten und in der Lebensdauer. Ein Hauptmerkmal von AppWindow ist, dass jede Instanz denselben UI-Verarbeitungsthread (einschließlich des Ereignisverteilers) verwendet, aus dem sie erstellt wurde, was die Entwicklung von Apps mit mehreren Fenstern vereinfacht.
Sie können nur XAML-Inhalte mit Ihrer AppWindow verbinden, es gibt keine Unterstützung für systemeigene DirectX- oder Holographic-Inhalte. Sie können jedoch ein XAML-SwapChainPanel anzeigen, das DirectX-Inhalte hostet.
Fensterumgebung
Die WindowingEnvironment-API informiert Sie über die Umgebung, in der Ihre App präsentiert wird, damit Sie Ihre App nach Bedarf anpassen können. Es beschreibt die Art des Fensters, das die Umgebung unterstützt; Beispiel: Overlapped Wenn die App auf einem PC ausgeführt wird oder Tiled die App auf einer Xbox ausgeführt wird. Außerdem wird eine Reihe von DisplayRegion-Objekten bereitgestellt, die die Bereiche beschreiben, in denen eine App auf einer logischen Anzeige angezeigt werden kann.
AnzeigeRegion
Die DisplayRegion-API beschreibt den Bereich, in dem einem Benutzer auf einer logischen Anzeige eine Ansicht angezeigt werden kann; Auf einem Desktop-PC ist dies z. B. die vollständige Anzeige minus der Bereich der Taskleiste. Es handelt sich nicht unbedingt um eine 1:1-Zuordnung mit dem physischen Anzeigebereich des hinteren Monitors. Es können mehrere Anzeigebereiche innerhalb desselben Monitors vorhanden sein, oder eine DisplayRegion kann so konfiguriert werden, dass sie sich über mehrere Monitore erstreckt, wenn diese Monitore in allen Aspekten homogen sind.
AppWindowPresenter
Mit der AppWindowPresenter--API können Sie Fenster einfach in vordefinierte Konfigurationen wie FullScreen oder CompactOverlayumschalten. Diese Konfigurationen bieten dem Benutzer eine konsistente Benutzererfahrung auf allen Geräten, die die Konfiguration unterstützen.
UIKontext
UIContext ist der eindeutige Bezeichner für ein Anwendungsfenster oder eine Ansicht. Es wird automatisch erstellt, und Sie können die Eigenschaft UIElement.UIContext verwenden, um den UIContext abzurufen. Jedes UIElement in der XAML-Struktur weist denselben UIContext auf.
UIContext ist wichtig, da APIs wie Window.Current und das GetForCurrentView Muster darauf angewiesen sind, eine einzelne ApplicationView/CoreWindow mit einem einzelnen XAML-Baum pro Thread zu verwenden. Dies ist nicht der Fall, wenn Sie eine AppWindow verwenden, daher verwenden Sie UIContext, um stattdessen ein bestimmtes Fenster zu identifizieren.
XamlRoot
Die XamlRoot-Klasse enthält eine XAML-Elementstruktur, verbindet sie mit dem Fensterhostobjekt (z. B. appWindow oder ApplicationView) und stellt Informationen wie Größe und Sichtbarkeit bereit. Sie erstellen kein XamlRoot-Objekt direkt. Stattdessen wird eine erstellt, wenn Sie ein XAML-Element an eine AppWindow anfügen. Anschließend können Sie die UIElement.XamlRoot--Eigenschaft verwenden, um XamlRoot abzurufen.
Weitere Informationen zu UIContext und XamlRoot finden Sie unter Machen Sie Code portabel über verschiedene Fenster-Hosts.
Ein neues Fenster öffnen
Sehen wir uns die Schritte zum Anzeigen von Inhalten in einem neuen AppWindow an.
Ein neues Fenster öffnen
Rufen Sie die statische Methode AppWindow.TryCreateAsync auf, um ein neues AppWindowzu erstellen.
AppWindow appWindow = await AppWindow.TryCreateAsync();Erstellen Sie den Fensterinhalt.
In der Regel erstellen Sie einen XAML-Frame-und navigieren dann zu einer XAML-Seite, in der Sie den App-Inhalt definiert haben. Weitere Informationen zu Frames und Seiten finden Sie unter Peer-to-peer-Navigation zwischen zwei Seiten.
Frame appWindowContentFrame = new Frame(); appWindowContentFrame.Navigate(typeof(AppWindowMainPage));Sie können jedoch alle XAML-Inhalte in AppWindow anzeigen, nicht nur einen Frame und eine Seite. Sie können beispielsweise nur ein einzelnes Steuerelement anzeigen, wie ColorPicker, oder Sie können ein SwapChainPanel anzeigen, das DirectX-Inhalte hostet.
Rufen Sie die ElementCompositionPreview.SetAppWindowContent-Methode auf, um den XAML-Inhalt an die AppWindow anzufügen.
ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowContentFrame);Der Aufruf dieser Methode erstellt ein XamlRoot-Objekt und legt es als XamlRoot-Eigenschaft für das angegebene UIElement fest.
Sie dürfen diese Methode nur einmal pro AppWindow-Instanz aufrufen. Nachdem der Inhalt festgelegt wurde, schlagen weitere Aufrufe von SetAppWindowContent für diese AppWindow-Instanz fehl. Wenn Sie auch versuchen, den AppWindow-Inhalt zu trennen, indem Sie ein NULL-UIElement-Objekt übergeben, schlägt der Aufruf fehl.
Rufen Sie die AppWindow.TryShowAsync-Methode auf, um das neue Fenster anzuzeigen.
await appWindow.TryShowAsync();
Freigeben von Ressourcen, wenn ein Fenster geschlossen wird
Sie sollten immer das AppWindow.Closed-Ereignis behandeln, um XAML-Ressourcen (den Inhalt von AppWindow) und Verweise auf AppWindow freizugeben.
appWindow.Closed += delegate
{
appWindowContentFrame.Content = null;
appWindow = null;
};
Tipp
Sie sollten die Menge des Codes im Closed Ereignishandler auf den mindest möglichen Betrag beschränken, um unerwartete Probleme zu vermeiden.
Nachverfolgen von Instanzen von AppWindow
Je nachdem, wie Sie mehrere Fenster in Ihrer App verwenden, kann es notwendig sein, die Instanzen von AppWindow nachzuverfolgen, die Sie erstellen. Das HelloAppWindow Beispiel zeigt verschiedene Möglichkeiten, wie Sie in der Regel ein AppWindow-verwenden können. Hier werden wir uns ansehen, warum diese Fenster verfolgt werden sollten und wie man das machen kann.
Einfaches Nachverfolgen
Das Farbauswahlfenster enthält ein einziges XAML-Steuerelement, und der Code für die Interaktion mit der Farbauswahl befindet sich in der MainPage.xaml.cs-Datei. Das Farbauswahlfenster lässt nur eine einzelne Instanz zu und ist im Wesentlichen eine Erweiterung von MainWindow. Um sicherzustellen, dass nur eine Instanz erstellt wird, wird das Farbauswahlfenster mit einer Variablen auf Seitenebene nachverfolgt. Bevor Sie ein neues Farbauswahlfenster erstellen, überprüfen Sie, ob eine Instanz vorhanden ist. Wenn dies der Fall ist, überspringen Sie die Schritte zum Erstellen eines neuen Fensters, und rufen Sie einfach TryShowAsync im vorhandenen Fenster auf.
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();
}
Nachverfolgen einer AppWindow-Instanz in den gehosteten Inhalten
Das AppWindowPage Fenster hostet eine vollständige XAML-Seite, und der Code für die Interaktion mit der Seite befindet sich in AppWindowPage.xaml.cs. Sie ermöglicht mehrere Instanzen, von denen jede unabhängig funktioniert.
Mit der Funktionalität der Seite können Sie das Fenster bearbeiten, es auf FullScreen oder CompactOverlayfestlegen und auch auf AppWindow.Changed Ereignisse lauschen, um Informationen zum Fenster anzuzeigen. Um diese APIs aufzurufen, benötigt AppWindowPage einen Verweis auf die AppWindow-Instanz, die die APIs hostet.
Wenn das alles ist, was Sie benötigen, können Sie eine Eigenschaft in
AppWindowPage.xaml.cs
Erstellen Sie in AppWindowPageeine Eigenschaft, die den AppWindow-Verweis enthalten soll.
public sealed partial class AppWindowPage : Page
{
public AppWindow MyAppWindow { get; set; }
// ...
}
MainPage.xaml.cs
Rufen Sie in MainPageeinen Verweis auf eine Seiteninstanz ab und weisen Sie die neu erstellte AppWindow-Instanz der Eigenschaft in AppWindowPagezu.
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;
// ...
}
Nachverfolgen von App-Fenstern mit UIContext
Möglicherweise möchten Sie auch von anderen Teilen Ihrer App auf AppWindow-Instanzen zugreifen. Beispielsweise könnte MainPage eine 'Alle schließen'-Schaltfläche haben, welche alle nachverfolgten Instanzen von AppWindow schließt.
In diesem Fall sollten Sie den eindeutigen Bezeichner des UIContext verwenden, um die Fensterinstanzen in einem Dictionarynachzuverfolgen.
MainPage.xaml.cs
Erstellen Sie in MainPagedas Wörterbuch als statische Eigenschaft. Fügen Sie dann die Seite beim Erstellen zum Wörterbuch hinzu, und entfernen Sie sie, wenn die Seite geschlossen wird. Sie können den UIContext aus dem Inhalt Frame (appWindowContentFrame.UIContext) abrufen, nachdem Sie ElementCompositionPreview.SetAppWindowContentaufgerufen haben.
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
Um die AppWindow-Instanz in Ihrem AppWindowPage Code zu verwenden, nutzen Sie den UIContext- der Seite, um sie aus dem statischen Wörterbuch in MainPageabzurufen. Sie sollten dies im Ereignishandler der geladenen Seite ausführen, statt im Konstruktor, damit UIContext nicht null ist. Sie können den UIContext aus der Seite abrufen: 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;
}
// ...
}
Hinweis
Das Beispiel HelloAppWindow zeigt beide Möglichkeiten zum Nachverfolgen des Fensters in AppWindowPage, doch üblicherweise verwendet man eine der beiden, nicht beide gleichzeitig.
Fenstergröße und -platzierung anfordern
Die AppWindow-Klasse verfügt über mehrere Methoden, mit deren Hilfe Sie die Größe und Platzierung des Fensters steuern können. Wie durch die Methodennamen impliziert, kann das System die angeforderten Änderungen je nach Umweltfaktoren berücksichtigen oder nicht berücksichtigen.
Rufen Sie RequestSize auf, um eine gewünschte Fenstergröße anzugeben, beispielsweise so.
colorPickerAppWindow.RequestSize(new Size(300, 428));
Die Methoden zum Verwalten der Fensterplatzierung lauten RequestMove*: RequestMoveAdjacentToCurrentView, RequestMoveAdjacentToWindow, RequestMoveRelativeToDisplayRegion, RequestMoveToDisplayRegion.
In diesem Beispiel verschiebt dieser Code das Fenster neben die Hauptansicht, von der das Fenster erzeugt wird.
colorPickerAppWindow.RequestMoveAdjacentToCurrentView();
Rufen Sie GetPlacement auf, um Informationen zur aktuellen Größe und Platzierung des Fensters abzurufen. Dadurch wird ein AppWindowPlacement--Objekt zurückgegeben, das die aktuelle DisplayRegion-, den Offset-und die Größe des Fensters bereitstellt.
Sie können diesen Code beispielsweise aufrufen, um das Fenster in die obere rechte Ecke der Anzeige zu verschieben. Dieser Code muss aufgerufen werden, nachdem das Fenster angezeigt wurde. andernfalls ist die vom Aufruf von GetPlacement zurückgegebene Fenstergröße 0,0, und der Offset ist falsch.
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));
Präsentationskonfiguration anfordern
Mit der AppWindowPresenter Klasse können Sie eine AppWindow mit einer vordefinierten Konfiguration anzeigen, die für das Gerät geeignet ist, auf dem sie angezeigt wird. Sie können einen AppWindowPresentationConfiguration--Wert verwenden, um das Fenster im FullScreen- oder CompactOverlay-Modus zu platzieren.
In diesem Beispiel wird gezeigt, wie Sie die folgenden Aktionen ausführen:
- Verwenden Sie das AppWindow.Changed-Ereignis, um eine Benachrichtigung zu erhalten, wenn sich die verfügbaren Fensterpräsentationen ändern.
- Verwenden Sie die AppWindow.Presenter-Eigenschaft, um den aktuellen AppWindowPresenterabzurufen.
- Rufen Sie IsPresentationSupported- auf, um festzustellen, ob eine bestimmte AppWindowPresentationKind- unterstützt wird.
- Rufen Sie GetConfiguration auf, um zu überprüfen, welche Art von Konfiguration derzeit verwendet wird.
- Führen Sie RequestPresentation aus, um die aktuelle Konfiguration zu ändern.
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);
}
}
Wiederverwenden von XAML-Elementen
Mit einem AppWindow- können Sie mehrere XAML-Bäume mit demselben UI-Thread verwenden. Ein XAML-Element kann jedoch nur einmal einer XAML-Struktur hinzugefügt werden. Wenn Sie einen Teil der Benutzeroberfläche von einem Fenster in ein anderes verschieben möchten, müssen Sie die Platzierung in der XAML-Struktur verwalten.
In diesem Beispiel wird gezeigt, wie Sie ein ColorPicker Steuerelement wiederverwenden, während es zwischen dem Hauptfenster und einem sekundären Fenster verschoben wird.
Die Farbauswahl wird im XAML-Code für MainPagedeklariert, was sie im MainPage XAML-Baum platziert.
<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>
Wenn der Farbwähler getrennt wird, um in einem neuen AppWindow platziert zu werden, müssen Sie ihn zuerst aus der XAML-Struktur MainPage entfernen, indem Sie ihn aus seinem übergeordneten Container herausnehmen. Obwohl es nicht notwendig ist, blendet dieses Beispiel auch den übergeordneten Container aus.
colorPickerContainer.Children.Remove(colorPicker);
colorPickerContainer.Visibility = Visibility.Collapsed;
Anschließend können Sie ihn dem neuen XAML-Baum hinzufügen. Hier erstellen Sie zunächst eine Grid-, die der übergeordnete Container für das ColorPicker-Element ist, und fügen Sie den ColorPicker als untergeordnetes Element des Rasters hinzu. (Auf diese Weise können Sie das „ColorPicker“-Element später aus diesem XAML-Baum entfernen.) Anschließend legen Sie das Raster als Wurzel des XAML-Baums im neuen Fenster fest.
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);
Wenn das AppWindow geschlossen ist, kehren Sie den Prozess um. Entfernen Sie zuerst den ColorPicker aus dem Gridund fügen Sie ihn dann als untergeordnetes Element des StackPanel in MainPagehinzu.
// 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();
}
Ein Dialogfeld anzeigen
Standardmäßig werden Inhaltsdialoge modal relativ zum Stamm-ApplicationView-angezeigt. Wenn Sie ein ContentDialog- in einem AppWindow-verwenden, müssen Sie das XamlRoot-Element im Dialogfeld manuell auf den Stamm des XAML-Hosts festlegen.
Legen Sie dazu die XamlRoot-Eigenschaft des ContentDialog- auf denselben XamlRoot- wie ein Element fest, das bereits im AppWindow enthalten ist. Hier befindet sich dieser Code innerhalb des Click-Ereignishandlers einer Schaltfläche, sodass Sie den Sender (die angeklickte Schaltfläche) verwenden können, um XamlRoot zu erhalten.
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
{
simpleDialog.XamlRoot = ((Button)sender).XamlRoot;
}
Wenn zusätzlich zum Hauptfenster (ApplicationView) mindestens eine AppWindows geöffnet ist, kann jedes Fenster versuchen, ein Dialogfeld zu öffnen, da das modale Dialogfeld nur das Fenster blockiert, in dem es verwurzelt ist. Es kann jedoch pro Thread immer nur ein ContentDialog geöffnet sein. Beim Versuch, zwei Content-Dialogs zu öffnen, wird eine Ausnahme ausgelöst, selbst wenn sie in separaten App-Fenstern geöffnet werden sollen.
Um dies zu verwalten, sollten Sie zumindest das Dialogfeld in einem try/catch-Block öffnen, um die Ausnahme abzufangen, falls bereits ein anderes Dialogfeld geöffnet ist.
try
{
ContentDialogResult result = await simpleDialog.ShowAsync();
}
catch (Exception)
{
// The dialog didn't open, probably because another dialog is already open.
}
Eine weitere Möglichkeit zum Verwalten von Dialogfeldern besteht darin, das aktuell geöffnete Dialogfeld nachzuverfolgen und zu schließen, bevor Sie versuchen, ein neues Dialogfeld zu öffnen. Hier erstellen Sie eine statische Eigenschaft in MainPage, die den Namen CurrentDialog trägt, für diesen Zweck.
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;
// ...
}
Anschließend überprüfen Sie, ob ein aktuell geöffnetes Dialogfeld vorhanden ist. Wenn vorhanden, rufen Sie die Hide-Methode auf, um sie zu schließen. Weisen Sie schließlich das neue Dialogfeld CurrentDialogzu, und versuchen Sie, es anzuzeigen.
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.
}
}
Wenn ein Dialogfeld nicht programmgesteuert geschlossen werden soll, weisen Sie es nicht als CurrentDialogzu. Hier zeigt MainPage einen wichtigen Dialog, der nur geschlossen werden sollte, wenn der Benutzer auf Okklickt. Da es nicht als CurrentDialog zugewiesen ist, wird nicht versucht, es programmgesteuert zu schließen.
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.
}
}
// ...
}
Vollständiger Code
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));
}
}
}