#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