diff --git a/src/Calculator/App.xaml.cpp b/src/Calculator/App.xaml.cpp index 2c701ea4..90e504da 100644 --- a/src/Calculator/App.xaml.cpp +++ b/src/Calculator/App.xaml.cpp @@ -12,7 +12,6 @@ #include "CalcViewModel\Common\Automation\NarratorNotifier.h" #include "CalcViewModel\Common\AppResourceProvider.h" #include "CalcViewModel\Common\LocalizationSettings.h" -#include "Common\SuspensionManager.h" #include "Views\MainPage.xaml.h" using namespace CalculatorApp; @@ -283,10 +282,8 @@ void App::OnAppLaunch(IActivatedEventArgs^ args, String^ argument) } } - // Create a Frame to act as the navigation context and associate it with - // a SuspensionManager key + // Create a Frame to act as the navigation context rootFrame = App::CreateFrame(); - //SuspensionManager::RegisterFrame(rootFrame, "AppFrame"); // When the navigation stack isn't restored navigate to the first page, // configuring the new page by passing required information as a navigation diff --git a/src/Calculator/Calculator.vcxproj b/src/Calculator/Calculator.vcxproj index 88c75dcf..cfa37198 100644 --- a/src/Calculator/Calculator.vcxproj +++ b/src/Calculator/Calculator.vcxproj @@ -219,8 +219,6 @@ - - @@ -355,8 +353,6 @@ - - diff --git a/src/Calculator/Calculator.vcxproj.filters b/src/Calculator/Calculator.vcxproj.filters index 72aea210..c702af96 100644 --- a/src/Calculator/Calculator.vcxproj.filters +++ b/src/Calculator/Calculator.vcxproj.filters @@ -231,12 +231,6 @@ Common - - Common - - - Common - Controls @@ -327,12 +321,6 @@ Common - - Common - - - Common - Controls @@ -428,7 +416,6 @@ - @@ -1579,4 +1566,7 @@ Assets + + + \ No newline at end of file diff --git a/src/Calculator/Common/LayoutAwarePage.cpp b/src/Calculator/Common/LayoutAwarePage.cpp deleted file mode 100644 index c4856407..00000000 --- a/src/Calculator/Common/LayoutAwarePage.cpp +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "LayoutAwarePage.h" -#include "SuspensionManager.h" -#include "CalcViewModel\Common\LocalizationService.h" -#include "App.xaml.h" - -using namespace CalculatorApp::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; - -/// -/// Initializes a new instance of the class. -/// -LayoutAwarePage::LayoutAwarePage() -{ - if (Windows::ApplicationModel::DesignMode::DesignModeEnabled) - { - return; - } - - // Create an empty default view model - DefaultViewModel = ref new Map(std::less()); - - // When this page is part of the visual tree make two changes: - // 1) Map application view state to visual state for the page - // 2) Handle keyboard and mouse navigation requests - Loaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnLoaded); - - // Undo the same changes when the page is no longer visible - Unloaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnUnloaded); - - Language = LocalizationService::GetInstance()->GetLanguage(); -} - -static DependencyProperty^ _defaultViewModelProperty = - DependencyProperty::Register("DefaultViewModel", - TypeName(IObservableMap::typeid), TypeName(LayoutAwarePage::typeid), nullptr); - -/// -/// Identifies the dependency property. -/// -DependencyProperty^ LayoutAwarePage::DefaultViewModelProperty::get() -{ - return _defaultViewModelProperty; -} - -/// -/// Gets an implementation of designed to be -/// used as a trivial view model. -/// -IObservableMap^ LayoutAwarePage::DefaultViewModel::get() -{ - return safe_cast^>(GetValue(DefaultViewModelProperty)); -} - -/// -/// Sets an implementation of designed to be -/// used as a trivial view model. -/// -void LayoutAwarePage::DefaultViewModel::set(IObservableMap^ value) -{ - SetValue(DefaultViewModelProperty, value); -} - -/// -/// Invoked when the page is part of the visual tree -/// -/// Instance that triggered the event. -/// Event data describing the conditions that led to the event. -void LayoutAwarePage::OnLoaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) -{ - // Keyboard and mouse navigation only apply when occupying the entire window - if (this->ActualHeight == Window::Current->Bounds.Height && - this->ActualWidth == Window::Current->Bounds.Width) - { - // Listen to the window directly so focus isn't required - _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; - } -} - -/// -/// Invoked when the page is removed from visual tree -/// -/// Instance that triggered the event. -/// Event data describing the conditions that led to the event. -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; - } -} - -#pragma region Navigation support - -/// -/// Invoked as an event handler to navigate backward in the page's associated -/// until it reaches the top of the navigation stack. -/// -/// Instance that triggered the event. -/// Event data describing the conditions that led to the event. -void LayoutAwarePage::GoHome(Object^ sender, RoutedEventArgs^ e) -{ - (void) sender; // Unused parameter - (void) e; // Unused parameter - - // Use the navigation frame to return to the topmost page - if (Frame != nullptr) - { - while (Frame->CanGoBack) - { - Frame->GoBack(); - } - } -} - -/// -/// Invoked as an event handler to navigate backward in the navigation stack -/// associated with this page's . -/// -/// Instance that triggered the event. -/// Event data describing the conditions that led to the event. -void LayoutAwarePage::GoBack(Object^ sender, RoutedEventArgs^ e) -{ - (void) sender; // Unused parameter - (void) e; // Unused parameter - - // Use the navigation frame to return to the previous page - if (Frame != nullptr && Frame->CanGoBack) - { - Frame->GoBack(); - } -} - -/// -/// Invoked as an event handler to navigate forward in the navigation stack -/// associated with this page's . -/// -/// Instance that triggered the event. -/// Event data describing the conditions that led to the event. -void LayoutAwarePage::GoForward(Object^ sender, RoutedEventArgs^ e) -{ - (void) sender; // Unused parameter - (void) e; // Unused parameter - - // Use the navigation frame to advance to the next page - if (Frame != nullptr && Frame->CanGoForward) - { - Frame->GoForward(); - } -} - -/// -/// Invoked on every keystroke, including system keys such as Alt key combinations, when -/// this page is active and occupies the entire window. Used to detect keyboard navigation -/// between pages even when the page itself doesn't have focus. -/// -/// Instance that triggered the event. -/// Event data describing the conditions that led to the event. -void LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher^ sender, - AcceleratorKeyEventArgs^ args) -{ - auto virtualKey = args->VirtualKey; - - // Only investigate further when Left, Right, or the dedicated Previous or Next keys - // are pressed - if ((args->EventType == CoreAcceleratorKeyEventType::SystemKeyDown || - args->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)) - { - // When the previous key or Alt+Left are pressed navigate back - args->Handled = true; - GoBack(this, ref new RoutedEventArgs()); - } - else if (((int)virtualKey == 167 && noModifiers) || - (virtualKey == VirtualKey::Right && onlyAlt)) - { - // When the next key or Alt+Right are pressed navigate forward - args->Handled = true; - GoForward(this, ref new RoutedEventArgs()); - } - } -} - -/// -/// Invoked on every mouse click, touch screen tap, or equivalent interaction when this -/// page is active and occupies the entire window. Used to detect browser-style next and -/// previous mouse button clicks to navigate between pages. -/// -/// Instance that triggered the event. -/// Event data describing the conditions that led to the event. -void LayoutAwarePage::CoreWindow_PointerPressed(CoreWindow^ sender, PointerEventArgs^ args) -{ - auto properties = args->CurrentPoint->Properties; - - // Ignore button chords with the left, right, and middle buttons - if (properties->IsLeftButtonPressed || properties->IsRightButtonPressed || - properties->IsMiddleButtonPressed) return; - - // If back or foward are pressed (but not both) navigate appropriately - bool backPressed = properties->IsXButton1Pressed; - bool forwardPressed = properties->IsXButton2Pressed; - if (backPressed ^ forwardPressed) - { - args->Handled = true; - if (backPressed) GoBack(this, ref new RoutedEventArgs()); - if (forwardPressed) GoForward(this, ref new RoutedEventArgs()); - } -} - -#pragma endregion - -#pragma region Process lifetime management - -/// -/// Invoked when this page is about to be displayed in a Frame. -/// -/// Event data that describes how this page was reached. The Parameter -/// property provides the group to be displayed. -void LayoutAwarePage::OnNavigatedTo(NavigationEventArgs^ e) -{ - // Returning to a cached page through navigation shouldn't trigger state loading - if (_pageKey != nullptr) return; - - auto frameState = SuspensionManager::SessionStateForFrame(Frame); - _pageKey = "Page-" + Frame->BackStackDepth; - - if (e->NavigationMode == NavigationMode::New) - { - // Clear existing state for forward navigation when adding a new page to the - // navigation stack - auto nextPageKey = _pageKey; - int nextPageIndex = Frame->BackStackDepth; - while (frameState->HasKey(nextPageKey)) - { - frameState->Remove(nextPageKey); - nextPageIndex++; - nextPageKey = "Page-" + nextPageIndex; - } - - // Pass the navigation parameter to the new page - LoadState(e->Parameter, nullptr); - } - else - { - // Pass the navigation parameter and preserved page state to the page, using - // the same strategy for loading suspended state and recreating pages discarded - // from cache - LoadState(e->Parameter, safe_cast^>(frameState->Lookup(_pageKey))); - } -} - -/// -/// Invoked when this page will no longer be displayed in a Frame. -/// -/// Event data that describes how this page was reached. The Parameter -/// property provides the group to be displayed. -void LayoutAwarePage::OnNavigatedFrom(NavigationEventArgs^ e) -{ - auto frameState = SuspensionManager::SessionStateForFrame(Frame); - auto pageState = ref new Map(); - SaveState(pageState); - frameState->Insert(_pageKey, pageState); -} - -/// -/// Populates the page with content passed during navigation. Any saved state is also -/// provided when recreating a page from a prior session. -/// -/// The parameter value passed to -/// when this page was initially requested. -/// -/// A map of state preserved by this page during an earlier -/// session. This will be null the first time a page is visited. -void LayoutAwarePage::LoadState(Object^ navigationParameter, IMap^ pageState) -{ -} - -/// -/// Preserves state associated with this page in case the application is suspended or the -/// page is discarded from the navigation cache. Values must conform to the serialization -/// requirements of . -/// -/// An empty map to be populated with serializable state. -void LayoutAwarePage::SaveState(IMap^ pageState) -{ -} - -#pragma endregion diff --git a/src/Calculator/Common/LayoutAwarePage.h b/src/Calculator/Common/LayoutAwarePage.h deleted file mode 100644 index 298b58b3..00000000 --- a/src/Calculator/Common/LayoutAwarePage.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include - -namespace CalculatorApp -{ - namespace Common - { - /// - /// Typical implementation of Page that provides several important conveniences: - /// - /// - /// Application view state to visual state mapping - /// - /// - /// GoBack, GoForward, and GoHome event handlers - /// - /// - /// Mouse and keyboard shortcuts for navigation - /// - /// - /// State management for navigation and process lifetime management - /// - /// - /// A default view model - /// - /// - /// - [Windows::Foundation::Metadata::WebHostHidden] - public ref class LayoutAwarePage : Windows::UI::Xaml::Controls::Page - { - internal: - LayoutAwarePage(); - - public: - static property Windows::UI::Xaml::DependencyProperty^ DefaultViewModelProperty - { - Windows::UI::Xaml::DependencyProperty^ get(); - }; - property Windows::Foundation::Collections::IObservableMap^ DefaultViewModel - { - Windows::Foundation::Collections::IObservableMap^ get(); - void set(Windows::Foundation::Collections::IObservableMap^ value); - } - - protected: - virtual void GoHome(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - virtual void GoBack(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - virtual void GoForward(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; - virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; - virtual void LoadState(Platform::Object^ navigationParameter, - Windows::Foundation::Collections::IMap^ pageState); - virtual void SaveState(Windows::Foundation::Collections::IMap^ pageState); - - private: - Platform::String^ _pageKey; - bool _navigationShortcutsRegistered; - Platform::Collections::Map^ _defaultViewModel; - Windows::Foundation::EventRegistrationToken _windowSizeEventToken, - _acceleratorKeyEventToken, _pointerPressedEventToken; - Platform::Collections::Vector^ _layoutAwareControls; - void OnLoaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void OnUnloaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void CoreDispatcher_AcceleratorKeyActivated(Windows::UI::Core::CoreDispatcher^ sender, - Windows::UI::Core::AcceleratorKeyEventArgs^ args); - void CoreWindow_PointerPressed(Windows::UI::Core::CoreWindow^ sender, - Windows::UI::Core::PointerEventArgs^ args); - LayoutAwarePage^ _this; // Strong reference to self, cleaned up in OnUnload - }; - } -} diff --git a/src/Calculator/Common/SuspensionManager.cpp b/src/Calculator/Common/SuspensionManager.cpp deleted file mode 100644 index 9cb7b91d..00000000 --- a/src/Calculator/Common/SuspensionManager.cpp +++ /dev/null @@ -1,494 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// -// SuspensionManager.cpp -// Implementation of the SuspensionManager class -// - -#include "pch.h" -#include "SuspensionManager.h" - -using namespace CalculatorApp::Common; - -using namespace Concurrency; -using namespace Platform; -using namespace Platform::Collections; -using namespace Windows::Foundation; -using namespace Windows::Foundation::Collections; -using namespace Windows::Storage; -using namespace Windows::Storage::FileProperties; -using namespace Windows::Storage::Streams; -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::UI::Xaml::Interop; - -namespace -{ - Map^ _sessionState = ref new Map(); - String^ sessionStateFilename = "_sessionState.dat"; - - // Forward declarations for object object read / write support - void WriteObject(Windows::Storage::Streams::DataWriter^ writer, Platform::Object^ object); - Platform::Object^ ReadObject(Windows::Storage::Streams::DataReader^ reader); -} - -/// -/// Provides access to global session state for the current session. This state is serialized by -/// and restored by which require values to be -/// one of the following: boxed values including integers, floating-point singles and doubles, -/// wide characters, boolean, Strings and Guids, or Map where map values are -/// subject to the same constraints. Session state should be as compact as possible. -/// -IMap^ SuspensionManager::SessionState::get(void) -{ - return _sessionState; -} - -/// -/// Wrap a WeakReference as a reference object for use in a collection. -/// -private ref class WeakFrame sealed -{ -private: - WeakReference _frameReference; - -internal: - WeakFrame(Frame^ frame) { _frameReference = frame; } - property Frame^ ResolvedFrame - { - Frame^ get(void) { return _frameReference.Resolve(); } - }; -}; - -namespace -{ - std::vector _registeredFrames; - DependencyProperty^ FrameSessionStateKeyProperty = - DependencyProperty::RegisterAttached("_FrameSessionStateKeyProperty", - TypeName(String::typeid), TypeName(SuspensionManager::typeid), nullptr); - DependencyProperty^ FrameSessionStateProperty = - DependencyProperty::RegisterAttached("_FrameSessionStateProperty", - TypeName(IMap::typeid), TypeName(SuspensionManager::typeid), nullptr); -} - -/// -/// Registers a instance to allow its navigation history to be saved to -/// and restored from . Frames should be registered once -/// immediately after creation if they will participate in session state management. Upon -/// registration if state has already been restored for the specified key -/// the navigation history will immediately be restored. Subsequent invocations of -/// will also restore navigation history. -/// -/// An instance whose navigation history should be managed by -/// -/// A unique key into used to -/// store navigation-related information. -void SuspensionManager::RegisterFrame(Frame^ frame, String^ sessionStateKey) -{ - if (frame->GetValue(FrameSessionStateKeyProperty) != nullptr) - { - throw ref new FailureException("Frames can only be registered to one session state key"); - } - - if (frame->GetValue(FrameSessionStateProperty) != nullptr) - { - throw ref new FailureException("Frames must be either be registered before accessing frame session state, or not registered at all"); - } - - // Use a dependency property to associate the session key with a frame, and keep a list of frames whose - // navigation state should be managed - frame->SetValue(FrameSessionStateKeyProperty, sessionStateKey); - _registeredFrames.insert(_registeredFrames.begin(), ref new WeakFrame(frame)); - - // Check to see if navigation state can be restored - RestoreFrameNavigationState(frame); -} - -/// -/// Disassociates a previously registered by -/// from . Any navigation state previously captured will be -/// removed. -/// -/// An instance whose navigation history should no longer be -/// managed. -void SuspensionManager::UnregisterFrame(Frame^ frame) -{ - // Remove session state and remove the frame from the list of frames whose navigation - // state will be saved (along with any weak references that are no longer reachable) - auto key = safe_cast(frame->GetValue(FrameSessionStateKeyProperty)); - if (SessionState->HasKey(key)) SessionState->Remove(key); - _registeredFrames.erase( - std::remove_if(_registeredFrames.begin(), _registeredFrames.end(), [=](WeakFrame^& e) - { - auto testFrame = e->ResolvedFrame; - return testFrame == nullptr || testFrame == frame; - }), - _registeredFrames.end() - ); -} - -/// -/// Provides storage for session state associated with the specified . -/// Frames that have been previously registered with have -/// their session state saved and restored automatically as a part of the global -/// . Frames that are not registered have transient state -/// that can still be useful when restoring pages that have been discarded from the -/// navigation cache. -/// -/// Apps may choose to rely on to manage -/// page-specific state instead of working with frame session state directly. -/// The instance for which session state is desired. -/// A collection of state subject to the same serialization mechanism as -/// . -IMap^ SuspensionManager::SessionStateForFrame(Frame^ frame) -{ - auto frameState = safe_cast^>(frame->GetValue(FrameSessionStateProperty)); - - if (frameState == nullptr) - { - auto frameSessionKey = safe_cast(frame->GetValue(FrameSessionStateKeyProperty)); - if (frameSessionKey != nullptr) - { - // Registered frames reflect the corresponding session state - if (!_sessionState->HasKey(frameSessionKey)) - { - _sessionState->Insert(frameSessionKey, ref new Map()); - } - frameState = safe_cast^>(_sessionState->Lookup(frameSessionKey)); - } - else - { - // Frames that aren't registered have transient state - frameState = ref new Map(); - } - frame->SetValue(FrameSessionStateProperty, frameState); - } - return frameState; -} - -void SuspensionManager::RestoreFrameNavigationState(Frame^ frame) -{ - auto frameState = SessionStateForFrame(frame); - if (frameState->HasKey("Navigation")) - { - frame->SetNavigationState(safe_cast(frameState->Lookup("Navigation"))); - } -} - -void SuspensionManager::SaveFrameNavigationState(Frame^ frame) -{ - auto frameState = SessionStateForFrame(frame); - frameState->Insert("Navigation", frame->GetNavigationState()); -} - -/// -/// Save the current . Any instances -/// registered with will also preserve their current -/// navigation stack, which in turn gives their active an opportunity -/// to save its state. -/// -/// An asynchronous task that reflects when session state has been saved. -task SuspensionManager::SaveAsync(void) -{ - // Save the navigation state for all registered frames - for (auto&& weakFrame : _registeredFrames) - { - auto frame = weakFrame->ResolvedFrame; - if (frame != nullptr) SaveFrameNavigationState(frame); - } - - // Serialize the session state synchronously to avoid asynchronous access to shared - // state - auto sessionData = ref new InMemoryRandomAccessStream(); - auto sessionDataWriter = ref new DataWriter(sessionData->GetOutputStreamAt(0)); - WriteObject(sessionDataWriter, _sessionState); - - // Once session state has been captured synchronously, begin the asynchronous process - // of writing the result to disk - return task(sessionDataWriter->StoreAsync()).then([=](unsigned int) - { - return ApplicationData::Current->LocalFolder->CreateFileAsync(sessionStateFilename, - CreationCollisionOption::ReplaceExisting); - }).then([=](StorageFile^ createdFile) - { - return createdFile->OpenAsync(FileAccessMode::ReadWrite); - }).then([=](IRandomAccessStream^ newStream) - { - return RandomAccessStream::CopyAsync( - sessionData->GetInputStreamAt(0), newStream->GetOutputStreamAt(0)); - }).then([=](UINT64 copiedBytes) - { - (void)copiedBytes; // Unused parameter - return; - }); -} - -/// -/// Restores previously saved . Any instances -/// registered with will also restore their prior navigation -/// state, which in turn gives their active an opportunity restore its -/// state. -/// -/// A version identifer compared to the session state to prevent -/// incompatible versions of session state from reaching app code. Saved state with a -/// different version will be ignored, resulting in an empty -/// dictionary. -/// An asynchronous task that reflects when session state has been read. The -/// content of should not be relied upon until this task -/// completes. -task SuspensionManager::RestoreAsync(void) -{ - _sessionState->Clear(); - - task getFileTask(ApplicationData::Current->LocalFolder->GetFileAsync(sessionStateFilename)); - return getFileTask.then([=](StorageFile^ stateFile) - { - task getBasicPropertiesTask(stateFile->GetBasicPropertiesAsync()); - return getBasicPropertiesTask.then([=](BasicProperties^ stateFileProperties) - { - auto size = unsigned int(stateFileProperties->Size); - if (size != stateFileProperties->Size) throw ref new FailureException("Session state larger than 4GB"); - task openReadTask(stateFile->OpenReadAsync()); - return openReadTask.then([=](IRandomAccessStreamWithContentType^ stateFileStream) - { - auto stateReader = ref new DataReader(stateFileStream); - return task(stateReader->LoadAsync(size)).then([=](unsigned int bytesRead) - { - (void)bytesRead; // Unused parameter - // Deserialize the Session State - Object^ content = ReadObject(stateReader); - _sessionState = (Map^)content; - - // Restore any registered frames to their saved state - for (auto&& weakFrame : _registeredFrames) - { - auto frame = weakFrame->ResolvedFrame; - if (frame != nullptr) - { - frame->ClearValue(FrameSessionStateProperty); - RestoreFrameNavigationState(frame); - } - } - }, task_continuation_context::use_current()); - }); - }); - }); -} - -#pragma region Object serialization for a known set of types - -namespace -{ - // Codes used for identifying serialized types - enum StreamTypes { - NullPtrType = 0, - - // Supported IPropertyValue types - UInt8Type, UInt16Type, UInt32Type, UInt64Type, Int16Type, Int32Type, Int64Type, - SingleType, DoubleType, BooleanType, Char16Type, GuidType, StringType, - - // Array types - UInt8ArrayType, - - // Additional supported types - StringToObjectMapType, - - // Marker values used to ensure stream integrity - MapEndMarker - }; - - void WriteString(DataWriter^ writer, String^ string) - { - writer->WriteByte(StringType); - writer->WriteUInt32(writer->MeasureString(string)); - writer->WriteString(string); - } - - void WriteByteArray(DataWriter^ writer, Platform::Array^ data) - { - writer->WriteByte(UInt8ArrayType); - writer->WriteUInt32(data->Length); - writer->WriteBytes(data); - } - - void WriteProperty(DataWriter^ writer, IPropertyValue^ propertyValue) - { - switch (propertyValue->Type) - { - case PropertyType::UInt8: - writer->WriteByte(UInt8Type); - writer->WriteByte(propertyValue->GetUInt8()); - return; - case PropertyType::UInt8Array: - { - Array^ data; - propertyValue->GetUInt8Array(&data); - WriteByteArray(writer, data); - } - return; - case PropertyType::UInt16: - writer->WriteByte(UInt16Type); - writer->WriteUInt16(propertyValue->GetUInt16()); - return; - case PropertyType::UInt32: - writer->WriteByte(UInt32Type); - writer->WriteUInt32(propertyValue->GetUInt32()); - return; - case PropertyType::UInt64: - writer->WriteByte(UInt64Type); - writer->WriteUInt64(propertyValue->GetUInt64()); - return; - case PropertyType::Int16: - writer->WriteByte(Int16Type); - writer->WriteUInt16(propertyValue->GetInt16()); - return; - case PropertyType::Int32: - writer->WriteByte(Int32Type); - writer->WriteUInt32(propertyValue->GetInt32()); - return; - case PropertyType::Int64: - writer->WriteByte(Int64Type); - writer->WriteUInt64(propertyValue->GetInt64()); - return; - case PropertyType::Single: - writer->WriteByte(SingleType); - writer->WriteSingle(propertyValue->GetSingle()); - return; - case PropertyType::Double: - writer->WriteByte(DoubleType); - writer->WriteDouble(propertyValue->GetDouble()); - return; - case PropertyType::Boolean: - writer->WriteByte(BooleanType); - writer->WriteBoolean(propertyValue->GetBoolean()); - return; - case PropertyType::Char16: - writer->WriteByte(Char16Type); - writer->WriteUInt16(propertyValue->GetChar16()); - return; - case PropertyType::Guid: - writer->WriteByte(GuidType); - writer->WriteGuid(propertyValue->GetGuid()); - return; - case PropertyType::String: - WriteString(writer, propertyValue->GetString()); - return; - default: - throw ref new InvalidArgumentException("Unsupported property type"); - } - } - - void WriteStringToObjectMap(DataWriter^ writer, IMap^ map) - { - writer->WriteByte(StringToObjectMapType); - writer->WriteUInt32(map->Size); - for (auto&& pair : map) - { - WriteObject(writer, pair->Key); - WriteObject(writer, pair->Value); - } - writer->WriteByte(MapEndMarker); - } - - void WriteObject(DataWriter^ writer, Object^ object) - { - if (object == nullptr) - { - writer->WriteByte(NullPtrType); - return; - } - - auto propertyObject = dynamic_cast(object); - if (propertyObject != nullptr) - { - WriteProperty(writer, propertyObject); - return; - } - - auto mapObject = dynamic_cast^>(object); - if (mapObject != nullptr) - { - WriteStringToObjectMap(writer, mapObject); - return; - } - - throw ref new InvalidArgumentException("Unsupported data type"); - } - - String^ ReadString(DataReader^ reader) - { - int length = reader->ReadUInt32(); - String^ string = reader->ReadString(length); - return string; - } - - Object^ ReadByteArray(DataReader^ reader) - { - unsigned int length = reader->ReadUInt32(); - Array^ data = ref new Array(length); - reader->ReadBytes(data); - return data; - } - - IMap^ ReadStringToObjectMap(DataReader^ reader) - { - auto map = ref new Map(); - auto size = reader->ReadUInt32(); - for (unsigned int index = 0; index < size; index++) - { - auto key = safe_cast(ReadObject(reader)); - auto value = ReadObject(reader); - map->Insert(key, value); - } - if (reader->ReadByte() != MapEndMarker) - { - throw ref new InvalidArgumentException("Invalid stream"); - } - return map; - } - - Object^ ReadObject(DataReader^ reader) - { - auto type = reader->ReadByte(); - switch (type) - { - case NullPtrType: - return nullptr; - case UInt8Type: - return reader->ReadByte(); - case UInt8ArrayType: - return ReadByteArray(reader); - case UInt16Type: - return reader->ReadUInt16(); - case UInt32Type: - return reader->ReadUInt32(); - case UInt64Type: - return reader->ReadUInt64(); - case Int16Type: - return reader->ReadInt16(); - case Int32Type: - return reader->ReadInt32(); - case Int64Type: - return reader->ReadInt64(); - case SingleType: - return reader->ReadSingle(); - case DoubleType: - return reader->ReadDouble(); - case BooleanType: - return reader->ReadBoolean(); - case Char16Type: - return static_cast(reader->ReadUInt16()); - case GuidType: - return reader->ReadGuid(); - case StringType: - return ReadString(reader); - case StringToObjectMapType: - return ReadStringToObjectMap(reader); - default: - throw ref new InvalidArgumentException("Unsupported property type"); - } - } -} - -#pragma endregion diff --git a/src/Calculator/Common/SuspensionManager.h b/src/Calculator/Common/SuspensionManager.h deleted file mode 100644 index d96ece49..00000000 --- a/src/Calculator/Common/SuspensionManager.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// -// SuspensionManager.h -// Declaration of the SuspensionManager class -// - -#pragma once - -#include - -namespace CalculatorApp -{ - namespace Common - { - /// - /// SuspensionManager captures global session state to simplify process lifetime management - /// for an application. Note that session state will be automatically cleared under a variety - /// of conditions and should only be used to store information that would be convenient to - /// carry across sessions, but that should be disacarded when an application crashes or is - /// upgraded. - /// - ref class SuspensionManager sealed - { - internal: - static void RegisterFrame(Windows::UI::Xaml::Controls::Frame^ frame, Platform::String^ sessionStateKey); - static void UnregisterFrame(Windows::UI::Xaml::Controls::Frame^ frame); - static Concurrency::task SaveAsync(void); - static Concurrency::task RestoreAsync(void); - static property Windows::Foundation::Collections::IMap^ SessionState - { - Windows::Foundation::Collections::IMap^ get(void); - }; - static Windows::Foundation::Collections::IMap^ SessionStateForFrame( - Windows::UI::Xaml::Controls::Frame^ frame); - - private: - static void RestoreFrameNavigationState(Windows::UI::Xaml::Controls::Frame^ frame); - static void SaveFrameNavigationState(Windows::UI::Xaml::Controls::Frame^ frame); - }; - } -} diff --git a/src/Calculator/Views/MainPage.xaml b/src/Calculator/Views/MainPage.xaml index e8a1d831..6136f42f 100644 --- a/src/Calculator/Views/MainPage.xaml +++ b/src/Calculator/Views/MainPage.xaml @@ -1,20 +1,20 @@ - + @@ -160,4 +160,4 @@ - + diff --git a/src/Calculator/Views/MainPage.xaml.cpp b/src/Calculator/Views/MainPage.xaml.cpp index e8bf8d30..4cf229be 100644 --- a/src/Calculator/Views/MainPage.xaml.cpp +++ b/src/Calculator/Views/MainPage.xaml.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -85,105 +85,32 @@ MainPage::MainPage() : } } -/// -/// Populates the page with content passed during navigation. Any saved state is also -/// provided when recreating a page from a prior session. -/// -/// The parameter value passed to -/// when this page was initially requested. -/// -/// A map of state preserved by this page during an earlier -/// session. This will be null the first time a page is visited. -void MainPage::LoadState(_In_ Object^ navigationParameter, _In_ IMap^ pageState) +void MainPage::OnNavigatedTo(NavigationEventArgs^ e) { - if (pageState != nullptr) + if (m_model->CalculatorViewModel) { - if (pageState->HasKey("ConverterViewModelState")) + m_model->CalculatorViewModel->HistoryVM->ClearHistory(); + } + + ViewMode initialMode = ViewMode::Standard; + if (e->Parameter != nullptr) + { + String^ stringParameter = dynamic_cast(e->Parameter); + if (stringParameter != nullptr) { - auto converterViewModelState = safe_cast(pageState->Lookup("ConverterViewModelState")); - - m_model->ConverterViewModel->Deserialize(converterViewModelState); + initialMode = (ViewMode)stoi(stringParameter->Data()); } - - //Moving these below the converter view model deserialize, since the converter modes are also displayed in the MainPage NavBar and thus need to be deserialized before setting the current mode - if (pageState->HasKey(ApplicationViewModelProperties::Mode)) - { - m_model->Mode = NavCategory::Deserialize(pageState->Lookup(ApplicationViewModelProperties::Mode)); - } - - if (pageState->HasKey(ApplicationViewModelProperties::PreviousMode)) - { - m_model->PreviousMode = NavCategory::Deserialize(pageState->Lookup(ApplicationViewModelProperties::PreviousMode)); - } - - // rehydrate - if (pageState->HasKey("CalculatorViewModelState")) - { - auto calculatorViewModelState = safe_cast^>(pageState->Lookup("CalculatorViewModelState")); - - m_model->CalculatorViewModel->Deserialize(calculatorViewModelState); - } - - m_model->CalculatorViewModel->HistoryVM->RestoreCompleteHistory(); - m_model->CalculatorViewModel->HistoryVM->ReloadHistory(m_model->Mode); } else { - // initialize - if (m_model->CalculatorViewModel) + ApplicationDataContainer^ localSettings = ApplicationData::Current->LocalSettings; + if (localSettings->Values->HasKey(ApplicationViewModelProperties::Mode)) { - m_model->CalculatorViewModel->HistoryVM->ClearHistory(); + initialMode = NavCategory::Deserialize(localSettings->Values->Lookup(ApplicationViewModelProperties::Mode)); } - - ViewMode initialMode = ViewMode::Standard; - if (navigationParameter != nullptr) - { - String^ stringParameter = dynamic_cast(navigationParameter); - if (stringParameter != nullptr) - { - initialMode = (ViewMode)stoi(stringParameter->Data()); - } - } - else - { - ApplicationDataContainer^ localSettings = ApplicationData::Current->LocalSettings; - if (localSettings->Values->HasKey(ApplicationViewModelProperties::Mode)) - { - initialMode = NavCategory::Deserialize(localSettings->Values->Lookup(ApplicationViewModelProperties::Mode)); - } - } - - m_model->Initialize(initialMode); - } -} - -/// -/// Preserves state associated with this page in case the application is suspended or the -/// page is discarded from the navigation cache. Values must conform to the serialization -/// requirements of . -/// -/// An empty map to be populated with serializable state. -void MainPage::SaveState(_In_ IMap^ pageState) -{ - int serializedCurrentMode = NavCategory::Serialize(m_model->Mode); - - pageState->Insert(ApplicationViewModelProperties::Mode, serializedCurrentMode); - pageState->Insert(ApplicationViewModelProperties::PreviousMode, NavCategory::Serialize(m_model->PreviousMode)); - - ApplicationDataContainer^ localSettings = ApplicationData::Current->LocalSettings; - localSettings->Values->Insert(ApplicationViewModelProperties::Mode, serializedCurrentMode); - - auto serializedCalculatorData = m_model->CalculatorViewModel->Serialize(); - auto serializedConverterData = m_model->ConverterViewModel->Serialize(); - if (serializedCalculatorData->Length > 0) - { - pageState->Insert("CalculatorViewModelState", serializedCalculatorData); } - if (serializedConverterData != nullptr) - { - pageState->Insert("ConverterViewModelState", serializedConverterData); - } + m_model->Initialize(initialMode); } void MainPage::WindowSizeChanged(_In_ Platform::Object^ /*sender*/, _In_ Windows::UI::Core::WindowSizeChangedEventArgs^ e) diff --git a/src/Calculator/Views/MainPage.xaml.h b/src/Calculator/Views/MainPage.xaml.h index 902328be..4db633e6 100644 --- a/src/Calculator/Views/MainPage.xaml.h +++ b/src/Calculator/Views/MainPage.xaml.h @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once -#include "Common\LayoutAwarePage.h" // Required by generated header #include "Views\Calculator.xaml.h" #include "Views\MainPage.g.h" #include "Views\DateCalculator.xaml.h" @@ -40,9 +39,7 @@ namespace CalculatorApp Windows::Foundation::Collections::IObservableVector^ CreateUIElementsForCategories(_In_ Windows::Foundation::Collections::IObservableVector^ categories); protected: - virtual void LoadState(_In_ Platform::Object^ navigationParameter, - _In_ Windows::Foundation::Collections::IMap^ pageState) override; - virtual void SaveState(_In_ Windows::Foundation::Collections::IMap^ pageState) override; + void OnNavigatedTo(_In_ Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override; private: void WindowSizeChanged(_In_ Platform::Object^ sender, _In_ Windows::UI::Core::WindowSizeChangedEventArgs^ e); diff --git a/src/Calculator/WindowFrameService.cpp b/src/Calculator/WindowFrameService.cpp index d0eb9c7a..387a9580 100644 --- a/src/Calculator/WindowFrameService.cpp +++ b/src/Calculator/WindowFrameService.cpp @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" #include "WindowFrameService.h" -#include "Common\SuspensionManager.h" #include "CalcViewModel\Common\KeyboardShortcutManager.h" using namespace concurrency;