#include "pch.h"
#include "LayoutAwarePage.h"
#include "SuspensionManager.h"
using namespace $safeprojectname$::Common;
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::System;
using namespace Windows::UI::Core;
using namespace Windows::UI::ViewManagement;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Navigation;
///
/// Initialisiert eine neue Instanz der -Klasse.
///
LayoutAwarePage::LayoutAwarePage()
{
if (Windows::ApplicationModel::DesignMode::DesignModeEnabled)
{
return;
}
// Ein leeres Standardanzeigemodell erstellen
DefaultViewModel = ref new Map(std::less());
// Zwei Änderungen vornehmen, wenn diese Seite Teil der visuellen Struktur ist:
// 1) Den Ansichtszustand der Anwendung dem visuellen Zustand für die Seite zuordnen
// 2) Tastatur- und Mausnavigationsanforderungen bearbeiten
Loaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnLoaded);
// Dieselben Änderungen rückgängig machen, wenn die Seite nicht mehr sichtbar ist
Unloaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnUnloaded);
}
DependencyProperty^ LayoutAwarePage::_defaultViewModelProperty = nullptr;
void LayoutAwarePage::RegisterDependencyProperties()
{
if (_defaultViewModelProperty == nullptr)
{
_defaultViewModelProperty =
DependencyProperty::Register("DefaultViewModel",
TypeName(IObservableMap::typeid), TypeName(LayoutAwarePage::typeid), nullptr);
}
}
///
/// Identifiziert die -Abhängigkeitseigenschaft.
///
DependencyProperty^ LayoutAwarePage::DefaultViewModelProperty::get()
{
return _defaultViewModelProperty;
}
///
/// Ruft eine Implementierung von ab, das als
/// triviales Anzeigemodell verwendet werden kann.
///
IObservableMap^ LayoutAwarePage::DefaultViewModel::get()
{
return safe_cast^>(GetValue(DefaultViewModelProperty));
}
///
/// Legt eine Implementierung von fest, das als
/// triviales Anzeigemodell verwendet werden kann.
///
void LayoutAwarePage::DefaultViewModel::set(IObservableMap^ value)
{
SetValue(DefaultViewModelProperty, value);
}
///
/// Wird aufgerufen, wenn die Seite Teil der visuellen Struktur ist
///
/// Instanz, von der das Ereignis ausgelöst wurde.
/// Ereignisdaten, die die Bedingungen beschreiben, die zu dem Ereignis geführt haben.
void LayoutAwarePage::OnLoaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
this->StartLayoutUpdates(sender, e);
// Tastatur- und Mausnavigation trifft nur zu, wenn das gesamte Fenster ausgefüllt wird.
if (this->ActualHeight == Window::Current->Bounds.Height &&
this->ActualWidth == Window::Current->Bounds.Width)
{
// Direkt am Fenster lauschen, sodass kein Fokus erforderlich ist
_acceleratorKeyEventToken = Window::Current->CoreWindow->Dispatcher->AcceleratorKeyActivated +=
ref new TypedEventHandler(this,
&LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated);
_pointerPressedEventToken = Window::Current->CoreWindow->PointerPressed +=
ref new TypedEventHandler(this,
&LayoutAwarePage::CoreWindow_PointerPressed);
_navigationShortcutsRegistered = true;
}
}
///
/// Wird aufgerufen, wenn die Seite aus der visuellen Struktur entfernt wird
///
/// Instanz, von der das Ereignis ausgelöst wurde.
/// Ereignisdaten, die die Bedingungen beschreiben, die zu dem Ereignis geführt haben.
void LayoutAwarePage::OnUnloaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
if (_navigationShortcutsRegistered)
{
Window::Current->CoreWindow->Dispatcher->AcceleratorKeyActivated -= _acceleratorKeyEventToken;
Window::Current->CoreWindow->PointerPressed -= _pointerPressedEventToken;
_navigationShortcutsRegistered = false;
}
StopLayoutUpdates(sender, e);
}
#pragma region Navigation support
///
/// Wird aufgerufen als Ereignishandler, um rückwärts im mit der Seite verknüpften
/// zu navigieren, bis der Anfang des Navigationsstapels erreicht wird.
///
/// Instanz, von der das Ereignis ausgelöst wurde.
/// Ereignisdaten, die die Bedingungen beschreiben, die zu dem Ereignis geführt haben.
void LayoutAwarePage::GoHome(Object^ sender, RoutedEventArgs^ e)
{
(void) sender; // Nicht verwendeter Parameter
(void) e; // Nicht verwendeter Parameter
// Den Navigationsframe zum Zurückkehren zur obersten Seite verwenden
if (Frame != nullptr)
{
while (Frame->CanGoBack)
{
Frame->GoBack();
}
}
}
///
/// Wird aufgerufen als Ereignishandler, um rückwärts im Navigationsstapel zu navigieren,
/// der mit dem dieser Seite verknüpft ist.
///
/// Instanz, von der das Ereignis ausgelöst wurde.
/// Ereignisdaten, die die Bedingungen beschreiben, die zu dem Ereignis geführt haben.
void LayoutAwarePage::GoBack(Object^ sender, RoutedEventArgs^ e)
{
(void) sender; // Nicht verwendeter Parameter
(void) e; // Nicht verwendeter Parameter
// Den Navigationsframe zum Zurückkehren zur vorherigen Seite verwenden
if (Frame != nullptr && Frame->CanGoBack)
{
Frame->GoBack();
}
}
///
/// Wird aufgerufen als Ereignishandler, um vorwärts im Navigationsstapelereignis
/// der mit dem dieser Seite verknüpft ist.
///
/// Instanz, von der das Ereignis ausgelöst wurde.
/// Ereignisdaten, die die Bedingungen beschreiben, die zu dem Ereignis geführt haben.
void LayoutAwarePage::GoForward(Object^ sender, RoutedEventArgs^ e)
{
(void) sender; // Nicht verwendeter Parameter
(void) e; // Nicht verwendeter Parameter
// Den Navigationsframe zum Wechseln zur nächsten Seite verwenden
if (Frame != nullptr && Frame->CanGoForward)
{
Frame->GoForward();
}
}
///
/// Wird bei jeder Tastatureingabe aufgerufen, einschließlich Systemtasten wie ALT-Tastenkombinationen, wenn
/// diese Seite aktiv ist und das gesamte Fenster ausfüllt. Wird verwendet zum Erkennen von Tastaturnavigation
/// zwischen Seiten, auch wenn sich die Seite selbst nicht im Fokus befindet.
///
/// Instanz, von der das Ereignis ausgelöst wurde.
/// Ereignisdaten, die die Bedingungen beschreiben, die zu dem Ereignis geführt haben.
void LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher^ sender,
AcceleratorKeyEventArgs^ e)
{
auto virtualKey = e->VirtualKey;
// Weitere Untersuchungen nur durchführen, wenn die Taste "Nach links", "Nach rechts" oder die dezidierten Tasten "Zurück" oder "Weiter"
// gedrückt werden
if ((e->EventType == CoreAcceleratorKeyEventType::SystemKeyDown ||
e->EventType == CoreAcceleratorKeyEventType::KeyDown) &&
(virtualKey == VirtualKey::Left || virtualKey == VirtualKey::Right ||
(int)virtualKey == 166 || (int)virtualKey == 167))
{
auto coreWindow = Window::Current->CoreWindow;
auto downState = Windows::UI::Core::CoreVirtualKeyStates::Down;
bool menuKey = (coreWindow->GetKeyState(VirtualKey::Menu) & downState) == downState;
bool controlKey = (coreWindow->GetKeyState(VirtualKey::Control) & downState) == downState;
bool shiftKey = (coreWindow->GetKeyState(VirtualKey::Shift) & downState) == downState;
bool noModifiers = !menuKey && !controlKey && !shiftKey;
bool onlyAlt = menuKey && !controlKey && !shiftKey;
if (((int)virtualKey == 166 && noModifiers) ||
(virtualKey == VirtualKey::Left && onlyAlt))
{
// Wenn die Taste "Zurück" oder ALT+NACH-LINKS-TASTE gedrückt wird, zurück navigieren
e->Handled = true;
GoBack(this, ref new RoutedEventArgs());
}
else if (((int)virtualKey == 167 && noModifiers) ||
(virtualKey == VirtualKey::Right && onlyAlt))
{
// Wenn die Taste "Weiter" oder ALT+NACH-RECHTS-TASTE gedrückt wird, vorwärts navigieren
e->Handled = true;
GoForward(this, ref new RoutedEventArgs());
}
}
}
///
/// Wird bei jedem Mausklick, jeder Touchscreenberührung oder einer äquivalenten Interaktion aufgerufen, wenn diese
/// Seite aktiv ist und das gesamte Fenster ausfüllt. Wird zum Erkennen von "Weiter"- und "Zurück"-Maustastenklicks
/// im Browserstil verwendet, um zwischen Seiten zu navigieren.
///
/// Instanz, von der das Ereignis ausgelöst wurde.
/// Ereignisdaten, die die Bedingungen beschreiben, die zu dem Ereignis geführt haben.
void LayoutAwarePage::CoreWindow_PointerPressed(CoreWindow^ sender, PointerEventArgs^ e)
{
auto properties = e->CurrentPoint->Properties;
// Tastenkombinationen mit der linken, rechten und mittleren Taste ignorieren
if (properties->IsLeftButtonPressed || properties->IsRightButtonPressed ||
properties->IsMiddleButtonPressed) return;
// Wenn "Zurück" oder "Vorwärts" gedrückt wird (jedoch nicht gleichzeitig), entsprechend navigieren
bool backPressed = properties->IsXButton1Pressed;
bool forwardPressed = properties->IsXButton2Pressed;
if (backPressed ^ forwardPressed)
{
e->Handled = true;
if (backPressed) GoBack(this, ref new RoutedEventArgs());
if (forwardPressed) GoForward(this, ref new RoutedEventArgs());
}
}
#pragma endregion
#pragma region Visual state switching
///
/// Wird aufgerufen als Ereignishandler, normalerweise für das -Ereignis von einem
/// innerhalb der Seite, um anzugeben, dass der Absender mit dem Empfang von
/// Änderungen der visuellen Zustandsverwaltung beginnen soll, die Änderungen am Ansichtszustand der Anwendung entsprechen.
///
/// Instanz von , die die Verwaltung von visuellen Zuständen
/// entsprechend den Ansichtszuständen unterstützt.
/// Ereignisdaten, die beschreiben, wie die Anforderung durchgeführt wurde.
/// Der aktuelle Ansichtszustand wird sofort verwendet, um den entsprechenden visuellen Zustand festzulegen,
/// wenn Layoutaktualisierungen angefordert werden. Ein entsprechender -Ereignishandler,
/// der mit verbunden ist, wird dringend empfohlen. Instanzen von
/// rufen diese Handler in den zugehörigen Loaded- und Unloaded-Ereignissen
/// automatisch auf.
///
///
void LayoutAwarePage::StartLayoutUpdates(Object^ sender, RoutedEventArgs^ e)
{
(void) e; // Nicht verwendeter Parameter
auto control = safe_cast(sender);
if (_layoutAwareControls == nullptr)
{
// Lauschen der Änderungen am Ansichtszustand starten, wenn an Aktualisierungen interessierte Steuerelemente vorliegen
_layoutAwareControls = ref new Vector();
_windowSizeEventToken = Window::Current->SizeChanged += ref new WindowSizeChangedEventHandler(this, &LayoutAwarePage::WindowSizeChanged);
// Seite empfängt Benachrichtigungen für untergeordnete Elemente. Die Seite schützen, bis die Layout-Updates für alle Steuerelemente abgeschlossen sind.
_this = this;
}
_layoutAwareControls->Append(control);
// Den anfänglichen visuellen Zustand des Steuerelements festlegen
VisualStateManager::GoToState(control, DetermineVisualState(ApplicationView::Value), false);
}
void LayoutAwarePage::WindowSizeChanged(Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e)
{
(void) sender; // Nicht verwendeter Parameter
(void) e; // Nicht verwendeter Parameter
InvalidateVisualState();
}
///
/// Wird aufgerufen als Ereignishandler, normalerweise für das -Ereignis von einem
/// , um anzugeben, dass der Absender mit dem Empfang von
/// Änderungen der visuellen Zustandsverwaltung beginnen soll, die Änderungen am Ansichtszustand der Anwendung entsprechen.
///
/// Instanz von , die die Verwaltung von visuellen Zuständen
/// entsprechend den Ansichtszuständen unterstützt.
/// Ereignisdaten, die beschreiben, wie die Anforderung durchgeführt wurde.
/// Der aktuelle Ansichtszustand wird sofort verwendet, um den entsprechenden visuellen Zustand festzulegen,
/// wenn Layoutaktualisierungen angefordert werden.
///
void LayoutAwarePage::StopLayoutUpdates(Object^ sender, RoutedEventArgs^ e)
{
(void) e; // Nicht verwendeter Parameter
auto control = safe_cast(sender);
unsigned int index;
if (_layoutAwareControls != nullptr && _layoutAwareControls->IndexOf(control, &index))
{
_layoutAwareControls->RemoveAt(index);
if (_layoutAwareControls->Size == 0)
{
// Lauschen der Änderungen am Ansichtszustand beenden, wenn keine Steuerelemente an Aktualisierungen interessiert sind
Window::Current->SizeChanged -= _windowSizeEventToken;
_layoutAwareControls = nullptr;
// Das letzte Steuerelement hat die "Unload"-Benachrichtigung erhalten.
_this = nullptr;
}
}
}
///
/// Übersetzt -Werte in Zeichenfolgen für die visuelle Zustandsverwaltung
/// innerhalb der Seite. Die Standardimplementierung verwendet die Namen von Enumerationswerten. Unterklassen können
/// diese Methode überschreiben, um das verwendete Zuordnungsschema zu steuern.
///
/// Ansichtszustand, für den ein visueller Zustand gewünscht wird.
/// Name des visuellen Zustands zur Verwendung mit dem
///
String^ LayoutAwarePage::DetermineVisualState(ApplicationViewState viewState)
{
switch (viewState)
{
case ApplicationViewState::Filled:
return "Filled";
case ApplicationViewState::Snapped:
return "Snapped";
case ApplicationViewState::FullScreenPortrait:
return "FullScreenPortrait";
case ApplicationViewState::FullScreenLandscape:
default:
return "FullScreenLandscape";
}
}
///
/// Aktualisiert alle Steuerelemente, die auf Änderungen des visuellen Zustands lauschen, mit dem korrekten visuellen
/// Zustand.
///
///
/// Wird normalerweise in Verbindung mit dem Überschreiben von verwendet, um
/// zu signalisieren, dass ein anderer Wert zurückgegeben kann, obwohl der Ansichtszustand nicht geändert wurde.
///
void LayoutAwarePage::InvalidateVisualState()
{
if (_layoutAwareControls != nullptr)
{
String^ visualState = DetermineVisualState(ApplicationView::Value);
auto controlIterator = _layoutAwareControls->First();
while (controlIterator->HasCurrent)
{
auto control = controlIterator->Current;
VisualStateManager::GoToState(control, visualState, false);
controlIterator->MoveNext();
}
}
}
#pragma endregion
#pragma region Process lifetime management
///
/// Wird aufgerufen, wenn diese Seite in einem Rahmen angezeigt werden soll.
///
/// Ereignisdaten, die beschreiben, wie diese Seite erreicht wurde. Die
/// Parametereigenschaft stellt die anzuzeigende Gruppe bereit.
void LayoutAwarePage::OnNavigatedTo(NavigationEventArgs^ e)
{
auto frameState = SuspensionManager::SessionStateForFrame(Frame);
_pageKey = "Page-" + Frame->BackStackDepth;
if (e->NavigationMode == NavigationMode::New)
{
// Bestehenden Zustand für die Vorwärtsnavigation löschen, wenn dem Navigationsstapel eine neue
// Seite hinzugefügt wird
auto nextPageKey = _pageKey;
int nextPageIndex = Frame->BackStackDepth;
while (frameState->HasKey(nextPageKey))
{
frameState->Remove(nextPageKey);
nextPageIndex++;
nextPageKey = "Page-" + nextPageIndex;
}
// Den Navigationsparameter an die neue Seite übergeben
LoadState(e->Parameter, nullptr);
}
else
{
// Den Navigationsparameter und den beibehaltenen Seitenzustand an die Seite übergeben,
// dabei die gleiche Strategie verwenden wie zum Laden des angehaltenen Zustands und zum erneuten Erstellen von im Cache verworfenen
// Seiten
LoadState(e->Parameter, safe_cast^>(frameState->Lookup(_pageKey)));
}
}
///
/// Wird aufgerufen, wenn diese Seite nicht mehr in einem Rahmen angezeigt wird.
///
/// Ereignisdaten, die beschreiben, wie diese Seite erreicht wurde. Die
/// Parametereigenschaft stellt die anzuzeigende Gruppe bereit.
void LayoutAwarePage::OnNavigatedFrom(NavigationEventArgs^ e)
{
auto frameState = SuspensionManager::SessionStateForFrame(Frame);
auto pageState = ref new Map();
SaveState(pageState);
frameState->Insert(_pageKey, pageState);
}
///
/// Füllt die Seite mit Inhalt auf, der bei der Navigation übergeben wird. Gespeicherte Zustände werden ebenfalls
/// bereitgestellt, wenn eine Seite aus einer vorherigen Sitzung neu erstellt wird.
///
/// Der Parameterwert, der an
/// übergeben wurde, als diese Seite ursprünglich angefordert wurde.
///
/// Ein Übersicht des Zustands, der von dieser Seite während einer früheren Sitzung
/// beibehalten wurde. Beim ersten Aufrufen einer Seite ist dieser Wert NULL.
void LayoutAwarePage::LoadState(Object^ navigationParameter, IMap^ pageState)
{
}
///
/// Behält den dieser Seite zugeordneten Zustand bei, wenn die Anwendung angehalten oder
/// die Seite im Navigationscache verworfen wird. Die Werte müssen den Serialisierungsanforderungen
/// von entsprechen.
///
/// Eine leere Übersicht, die mit dem serialisierbaren Zustand aufgefüllt wird.
void LayoutAwarePage::SaveState(IMap^ pageState)
{
}
#pragma endregion