Cherry-pick for 2403 (#2166)

* Fix #2146: SWIPE DELETE FUNCTION FREEZES APP (#2157)

* fix stackoverflow

* space

* Multi-instance (#2161)

* launch multi instances

* trace error

* simplify the graphing test

* remove an assertion

* simplify some code

* remove some trivial code.

* fix runtime cast

* Resize on the first launch (#2165)
This commit is contained in:
Tian L 2024-04-28 22:13:13 +08:00 committed by GitHub
parent fcbda43c12
commit f96b7a56ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 85 additions and 595 deletions

View file

@ -50,34 +50,19 @@ static constexpr int GRAPHING_ID = 17;
namespace // put the utils within this TU
{
Platform::String^ CurrentUserId;
std::mutex GraphingModeCheckMutex;
bool IsGraphingModeEnabled()
{
static bool isChecked = false;
static bool isEnabled = false;
std::scoped_lock<std::mutex> lock(GraphingModeCheckMutex);
if (isChecked)
{
return isEnabled;
}
else
static auto enabled = []
{
auto user = User::GetFromId(CurrentUserId);
if (user == nullptr)
{
return true;
}
auto namedPolicyData = NamedPolicy::GetPolicyFromPathForUser(
user,
L"Education",
L"AllowGraphingCalculator");
isEnabled = namedPolicyData->GetBoolean();
isChecked = true;
return isEnabled;
}
return NamedPolicy::GetPolicyFromPathForUser(user, L"Education", L"AllowGraphingCalculator")->GetBoolean();
}();
return enabled;
}
// The order of items in this list determines the order of items in the menu.
@ -318,7 +303,6 @@ NavCategoryGroup::NavCategoryGroup(const NavCategoryGroupInitializer& groupIniti
void NavCategoryStates::SetCurrentUser(Platform::String^ userId)
{
std::scoped_lock<std::mutex> lock(GraphingModeCheckMutex);
CurrentUserId = userId;
}
@ -518,13 +502,6 @@ bool NavCategoryStates::IsValidViewMode(ViewMode mode)
bool NavCategoryStates::IsViewModeEnabled(ViewMode mode)
{
if (mode != ViewMode::Graphing)
{
return true;
}
else
{
return IsGraphingModeEnabled();
}
return mode != ViewMode::Graphing ? true : IsGraphingModeEnabled();
}

View file

@ -6,37 +6,24 @@
// Declaration of the App class.
//
using CalculatorApp.ViewModel.Common;
using CalculatorApp.ViewModel.Common.Automation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.Storage;
using Windows.UI.Core;
using Windows.UI.StartScreen;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using CalculatorApp.Utils;
using CalculatorApp.ViewModel.Common;
using CalculatorApp.ViewModel.Common.Automation;
namespace CalculatorApp
{
namespace ApplicationResourceKeys
{
public static class Globals
{
public static readonly string AppMinWindowHeight = "AppMinWindowHeight";
public static readonly string AppMinWindowWidth = "AppMinWindowWidth";
}
}
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
@ -49,17 +36,12 @@ namespace CalculatorApp
public App()
{
InitializeComponent();
m_preLaunched = false;
RegisterDependencyProperties();
NarratorNotifier.RegisterDependencyProperties();
// TODO: MSFT 14645325: Set this directly from XAML.
// Currently this is bugged so the property is only respected from code-behind.
HighContrastAdjustment = ApplicationHighContrastAdjustment.None;
Suspending += OnSuspending;
#if DEBUG
DebugSettings.IsBindingTracingEnabled = true;
DebugSettings.BindingFailed += (sender, args) =>
@ -81,18 +63,12 @@ namespace CalculatorApp
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
if (args.PrelaunchActivated)
{
// If the app got pre-launch activated, then save that state in a flag
m_preLaunched = true;
}
NavCategoryStates.SetCurrentUser(args.User.NonRoamableId);
// It takes time to check GraphingMode at the 1st time. So, do it in a background thread
// It takes time to check GraphingMode at the very first time. Warm up in a background thread.
Task.Run(() => NavCategoryStates.IsViewModeEnabled(ViewMode.Graphing));
OnAppLaunch(args, args.Arguments);
OnAppLaunch(args, args.Arguments, args.PrelaunchActivated);
}
protected override void OnActivated(IActivatedEventArgs args)
@ -101,76 +77,36 @@ namespace CalculatorApp
{
// We currently don't pass the uri as an argument,
// and handle any protocol launch as a normal app launch.
OnAppLaunch(args, null);
OnAppLaunch(args, null, false);
}
}
internal void RemoveWindow(WindowFrameService frameService)
{
// Shell does not allow killing the main window.
if (m_mainViewId != frameService.GetViewId())
{
_ = HandleViewReleaseAndRemoveWindowFromMap(frameService);
}
}
internal void RemoveSecondaryWindow(WindowFrameService frameService)
{
// Shell does not allow killing the main window.
if (m_mainViewId != frameService.GetViewId())
{
RemoveWindowFromMap(frameService.GetViewId());
}
}
private static Frame CreateFrame()
{
var frame = new Frame
{
FlowDirection = LocalizationService.GetInstance().GetFlowDirection()
};
return frame;
}
private static void SetMinWindowSizeAndThemeAndActivate(Frame rootFrame, Size minWindowSize)
{
// SetPreferredMinSize should always be called before Window.Activate
ApplicationView appView = ApplicationView.GetForCurrentView();
appView.SetPreferredMinSize(minWindowSize);
// Place the frame in the current Window
Window.Current.Content = rootFrame;
CalculatorApp.Utils.ThemeHelper.InitializeAppTheme();
Window.Current.Activate();
}
private void OnAppLaunch(IActivatedEventArgs args, string argument)
private void OnAppLaunch(IActivatedEventArgs args, string argument, bool isPreLaunch)
{
// Uncomment the following lines to display frame-rate and per-frame CPU usage info.
//#if _DEBUG
//#if DEBUG
// if (IsDebuggerPresent())
// {
// DebugSettings->EnableFrameRateCounter = true;
// DebugSettings.EnableFrameRateCounter = true;
// }
//#endif
args.SplashScreen.Dismissed += DismissedEventHandler;
args.SplashScreen.Dismissed += async (_, __) => await SetupJumpListAsync();
var rootFrame = (Window.Current.Content as Frame);
WeakReference weak = new WeakReference(this);
var minWindowWidth = Convert.ToSingle(Resources["AppMinWindowWidth"]);
var minWindowHeight = Convert.ToSingle(Resources["AppMinWindowHeight"]);
var minWindowSize = SizeHelper.FromDimensions(minWindowWidth, minWindowHeight);
var appView = ApplicationView.GetForCurrentView();
var localSettings = ApplicationData.Current.LocalSettings;
float minWindowWidth = (float)((double)Resources[ApplicationResourceKeys.Globals.AppMinWindowWidth]);
float minWindowHeight = (float)((double)Resources[ApplicationResourceKeys.Globals.AppMinWindowHeight]);
Size minWindowSize = SizeHelper.FromDimensions(minWindowWidth, minWindowHeight);
// SetPreferredMinSize should always be called before Window.Activate
appView.SetPreferredMinSize(minWindowSize);
ApplicationView appView = ApplicationView.GetForCurrentView();
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
// For very first launch, set the size of the calc as size of the default standard mode
if (!localSettings.Values.ContainsKey("VeryFirstLaunch"))
{
localSettings.Values["VeryFirstLaunch"] = false;
appView.SetPreferredMinSize(minWindowSize);
appView.TryResizeView(minWindowSize);
appView.TryResizeView(minWindowSize); // the requested size must not be less than the min size.
}
else
{
@ -179,190 +115,34 @@ namespace CalculatorApp
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
var rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
if (!Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) // PC Family
rootFrame = new Frame
{
// Disable the system view activation policy during the first launch of the app
// only for PC family devices and not for phone family devices
try
{
ApplicationViewSwitcher.DisableSystemViewActivationPolicy();
}
catch (Exception)
{
// Log that DisableSystemViewActionPolicy didn't work
}
}
// Create a Frame to act as the navigation context
rootFrame = App.CreateFrame();
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(MainPage), argument))
{
// We couldn't navigate to the main page, kill the app so we have a good
// stack to debug
throw new SystemException();
}
SetMinWindowSizeAndThemeAndActivate(rootFrame, minWindowSize);
m_mainViewId = ApplicationView.GetForCurrentView().Id;
AddWindowToMap(WindowFrameService.CreateNewWindowFrameService(rootFrame, false, weak));
FlowDirection = LocalizationService.GetInstance().GetFlowDirection()
};
}
else
if (isPreLaunch)
{
// For first launch, LaunchStart is logged in constructor, this is for subsequent launches.
// !Phone check is required because even in continuum mode user interaction mode is Mouse not Touch
if ((UIViewSettings.GetForCurrentView().UserInteractionMode == UserInteractionMode.Mouse)
&& (!Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")))
{
// If the pre-launch hasn't happened then allow for the new window/view creation
if (!m_preLaunched)
{
var newCoreAppView = CoreApplication.CreateNewView();
_ = newCoreAppView.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal, async () =>
{
if (weak.Target is App that)
{
var newRootFrame = App.CreateFrame();
SetMinWindowSizeAndThemeAndActivate(newRootFrame, minWindowSize);
if (!newRootFrame.Navigate(typeof(MainPage), argument))
{
// We couldn't navigate to the main page, kill the app so we have a good
// stack to debug
throw new SystemException();
}
var frameService = WindowFrameService.CreateNewWindowFrameService(newRootFrame, true, weak);
that.AddWindowToMap(frameService);
var dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
// CSHARP_MIGRATION_ANNOTATION:
// class SafeFrameWindowCreation is being interpreted into a IDisposable class
// in order to enhance its RAII capability that was written in C++/CX
using (var safeFrameServiceCreation = new SafeFrameWindowCreation(frameService, that))
{
int newWindowId = ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread());
ActivationViewSwitcher activationViewSwitcher = null;
var activateEventArgs = (args as IViewSwitcherProvider);
if (activateEventArgs != null)
{
activationViewSwitcher = activateEventArgs.ViewSwitcher;
}
if (activationViewSwitcher != null)
{
_ = activationViewSwitcher.ShowAsStandaloneAsync(newWindowId, ViewSizePreference.Default);
safeFrameServiceCreation.SetOperationSuccess(true);
}
else
{
var activatedEventArgs = (args as IApplicationViewActivatedEventArgs);
if ((activatedEventArgs != null) && (activatedEventArgs.CurrentlyShownApplicationViewId != 0))
{
// CSHARP_MIGRATION_ANNOTATION:
// here we don't use ContinueWith() to interpret origin code because we would like to
// pursue the design of class SafeFrameWindowCreate whichi was using RAII to ensure
// some states get handled properly when its instance is being destructed.
//
// To achieve that, SafeFrameWindowCreate has been reinterpreted using IDisposable
// pattern, which forces we use below way to keep async works being controlled within
// a same code block.
var viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(
frameService.GetViewId(),
ViewSizePreference.Default,
activatedEventArgs.CurrentlyShownApplicationViewId,
ViewSizePreference.Default);
// SafeFrameServiceCreation is used to automatically remove the frame
// from the list of frames if something goes bad.
safeFrameServiceCreation.SetOperationSuccess(viewShown);
}
}
}
}
});
}
else
{
ActivationViewSwitcher activationViewSwitcher = null;
var activateEventArgs = (args as IViewSwitcherProvider);
if (activateEventArgs != null)
{
activationViewSwitcher = activateEventArgs.ViewSwitcher;
}
if (activationViewSwitcher != null)
{
_ = activationViewSwitcher.ShowAsStandaloneAsync(
ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread()), ViewSizePreference.Default);
}
else
{
TraceLogger.GetInstance().LogError(ViewMode.None, "App.OnAppLaunch", "Null_ActivationViewSwitcher");
}
}
// Set the preLaunched flag to false
m_preLaunched = false;
}
else // for touch devices
{
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(MainPage), argument))
{
// We couldn't navigate to the main page,
// kill the app so we have a good stack to debug
throw new SystemException();
}
}
if (ApplicationView.GetForCurrentView().ViewMode != ApplicationViewMode.CompactOverlay)
{
if (!Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
{
// for tablet mode: since system view activation policy is disabled so do ShowAsStandaloneAsync if activationViewSwitcher exists in
// activationArgs
ActivationViewSwitcher activationViewSwitcher = null;
var activateEventArgs = (args as IViewSwitcherProvider);
if (activateEventArgs != null)
{
activationViewSwitcher = activateEventArgs.ViewSwitcher;
}
if (activationViewSwitcher != null)
{
var viewId = (args as IApplicationViewActivatedEventArgs).CurrentlyShownApplicationViewId;
if (viewId != 0)
{
_ = activationViewSwitcher.ShowAsStandaloneAsync(viewId);
}
}
}
// Ensure the current window is active
Window.Current.Activate();
}
}
return;
}
}
private void DismissedEventHandler(SplashScreen sender, object e)
{
_ = SetupJumpList();
}
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (rootFrame.Content == null && !rootFrame.Navigate(typeof(MainPage), argument))
{
// We couldn't navigate to the main page, kill the app so we have a good
// stack to debug
throw new SystemException("6d430286-eb5d-4f8d-95d2-3d1059552968");
}
private void RegisterDependencyProperties()
{
NarratorNotifier.RegisterDependencyProperties();
// Place the frame in the current Window
Window.Current.Content = rootFrame;
ThemeHelper.InitializeAppTheme();
Window.Current.Activate();
}
private void OnSuspending(object sender, SuspendingEventArgs args)
@ -370,43 +150,7 @@ namespace CalculatorApp
TraceLogger.GetInstance().LogButtonUsage();
}
private sealed class SafeFrameWindowCreation : IDisposable
{
public SafeFrameWindowCreation(WindowFrameService frameService, App parent)
{
m_frameService = frameService;
m_frameOpenedInWindow = false;
m_parent = parent;
}
public void SetOperationSuccess(bool success)
{
m_frameOpenedInWindow = success;
}
public void Dispose()
{
if (!m_frameOpenedInWindow)
{
// Close the window as the navigation to the window didn't succeed
// and this is not visible to the user.
m_parent.RemoveWindowFromMap(m_frameService.GetViewId());
}
GC.SuppressFinalize(this);
}
~SafeFrameWindowCreation()
{
Dispose();
}
private readonly WindowFrameService m_frameService;
private bool m_frameOpenedInWindow;
private readonly App m_parent;
};
private async Task SetupJumpList()
private async Task SetupJumpListAsync()
{
try
{
@ -426,87 +170,19 @@ namespace CalculatorApp
var item = JumpListItem.CreateWithArguments(((int)mode).ToString(), "ms-resource:///Resources/" + NavCategoryStates.GetNameResourceKey(mode));
item.Description = "ms-resource:///Resources/" + NavCategoryStates.GetNameResourceKey(mode);
item.Logo = new Uri("ms-appx:///Assets/" + mode + ".png");
jumpList.Items.Add(item);
}
await jumpList.SaveAsync();
}
catch
catch (Exception ex)
{
TraceLogger.GetInstance().LogError(ViewMode.None, nameof(SetupJumpListAsync), ex.ToString());
#if DEBUG
throw;
#endif
}
}
private async Task HandleViewReleaseAndRemoveWindowFromMap(WindowFrameService frameService)
{
WeakReference weak = new WeakReference(this);
// Unregister the event handler of the Main Page
var frame = (Window.Current.Content as Frame);
var mainPage = (frame.Content as MainPage);
mainPage.UnregisterEventHandlers();
await frameService.HandleViewRelease();
await Task.Run(() =>
{
var that = weak.Target as App;
that.RemoveWindowFromMap(frameService.GetViewId());
}).ConfigureAwait(false /* task_continuation_context::use_arbitrary() */);
}
private void AddWindowToMap(WindowFrameService frameService)
{
m_windowsMapLock.EnterWriteLock();
try
{
m_secondaryWindows[frameService.GetViewId()] = frameService;
TraceLogger.GetInstance().UpdateWindowCount(Convert.ToUInt64(m_secondaryWindows.Count));
}
finally
{
m_windowsMapLock.ExitWriteLock();
}
}
private WindowFrameService GetWindowFromMap(int viewId)
{
m_windowsMapLock.EnterReadLock();
try
{
if (m_secondaryWindows.TryGetValue(viewId, out var windowMapEntry))
{
return windowMapEntry;
}
else
{
return null;
}
}
finally
{
m_windowsMapLock.ExitReadLock();
}
}
private void RemoveWindowFromMap(int viewId)
{
m_windowsMapLock.EnterWriteLock();
try
{
bool removed = m_secondaryWindows.Remove(viewId);
Debug.Assert(removed != false, "Window does not exist in the list");
}
finally
{
m_windowsMapLock.ExitWriteLock();
}
}
private readonly ReaderWriterLockSlim m_windowsMapLock = new ReaderWriterLockSlim();
private readonly Dictionary<int, WindowFrameService> m_secondaryWindows = new Dictionary<int, WindowFrameService>();
private int m_mainViewId;
private bool m_preLaunched;
}
}

View file

@ -250,7 +250,6 @@
<Compile Include="Views\UnitConverter.xaml.cs">
<DependentUpon>UnitConverter.xaml</DependentUpon>
</Compile>
<Compile Include="WindowFrameService.cs" />
</ItemGroup>
<ItemGroup Condition="'$(UseReleaseAppxManifest)' == 'True'">
<AppxManifest Include="Package.Release.appxmanifest">

View file

@ -1,5 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" IgnorableNamespaces="uap uap3 uap5 mp">
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:iot2="http://schemas.microsoft.com/appx/manifest/iot/windows10/2"
IgnorableNamespaces="uap uap3 uap5 mp desktop4 iot2">
<Identity Name="Microsoft.WindowsCalculator" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="10.1604.27012.0" />
<mp:PhoneIdentity PhoneProductId="b58171c6-c70c-4266-a2e8-8f9c994f4456" PhonePublisherId="95d94207-0c7c-47ed-82db-d75c81153c35" />
<Properties>
@ -14,7 +21,11 @@
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="Calculator.App">
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="Calculator.App"
desktop4:SupportsMultipleInstances="true"
iot2:SupportsMultipleInstances="true">
<uap:VisualElements DisplayName="ms-resource:AppName" Square150x150Logo="Assets\CalculatorMedTile.png" Square44x44Logo="Assets\CalculatorAppList.png" Description="ms-resource:AppDescription" BackgroundColor="#0078D4">
<uap:DefaultTile ShortName="ms-resource:AppName" Square310x310Logo="Assets\CalculatorLargeTile.png" Wide310x150Logo="Assets\CalculatorWideTile.png" Square71x71Logo="Assets\CalculatorSmallTile.png">
<uap:ShowNameOnTiles>

View file

@ -1,5 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" IgnorableNamespaces="uap uap3 uap5 mp">
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:iot2="http://schemas.microsoft.com/appx/manifest/iot/windows10/2"
IgnorableNamespaces="uap uap3 uap5 mp desktop4 iot2">
<Identity Name="Microsoft.WindowsCalculator.Dev" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="0.0.1.0" />
<mp:PhoneIdentity PhoneProductId="b58171c6-c70c-4266-a2e8-8f9c994f4456" PhonePublisherId="95d94207-0c7c-47ed-82db-d75c81153c35" />
<Properties>
@ -14,7 +21,11 @@
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="Calculator.App">
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="Calculator.App"
desktop4:SupportsMultipleInstances="true"
iot2:SupportsMultipleInstances="true">
<uap:VisualElements DisplayName="ms-resource:DevAppName" Square150x150Logo="Assets\CalculatorMedTile.png" Square44x44Logo="Assets\CalculatorAppList.png" Description="ms-resource:DevAppDescription" BackgroundColor="transparent">
<uap:DefaultTile ShortName="ms-resource:DevAppName" Square310x310Logo="Assets\CalculatorLargeTile.png" Wide310x150Logo="Assets\CalculatorWideTile.png" Square71x71Logo="Assets\CalculatorSmallTile.png">
<uap:ShowNameOnTiles>

View file

@ -189,7 +189,6 @@ namespace CalculatorApp
}
}
public void UpdatePanelViewState()
{
UpdateHistoryState();
@ -772,7 +771,10 @@ namespace CalculatorApp
private void SetChildAsMemory()
{
DockMemoryHolder.Child = GetMemory();
if (DockMemoryHolder.Child != GetMemory())
{
DockMemoryHolder.Child = GetMemory();
}
}
private void SetChildAsHistory()
@ -782,7 +784,10 @@ namespace CalculatorApp
InitializeHistoryView(Model.HistoryVM);
}
DockHistoryHolder.Child = m_historyList;
if (DockHistoryHolder.Child != m_historyList)
{
DockHistoryHolder.Child = m_historyList;
}
}
private Memory GetMemory()

View file

@ -1,189 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.Common;
using CalculatorApp.ViewModel.Common;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace CalculatorApp
{
public sealed class WindowFrameService
{
public Page GetCurrentPage()
{
return (m_frame.Content as Page);
}
public void SetNewFrame(Windows.UI.Xaml.Controls.Frame frame)
{
Debug.Assert(frame.BackStackDepth == 0);
m_frame = frame;
}
// createdByUs means any window that we create.
// !createdByUs means the main window
internal static WindowFrameService CreateNewWindowFrameService(Frame viewFrame, bool createdByUs, WeakReference parent)
{
Debug.Assert(CoreWindow.GetForCurrentThread() != null);
var frameService = new WindowFrameService(viewFrame, parent);
frameService.InitializeFrameService(createdByUs);
return frameService;
}
public CoreDispatcher GetCoreDispatcher()
{
return m_coreDispatcher;
}
public int GetViewId()
{
return m_viewId;
}
public void RegisterOnWindowClosingHandler(Action onWindowClosingHandler)
{
m_onWindowClosingHandlers.Add(onWindowClosingHandler);
}
public Task HandleViewRelease()
{
TaskCompletionSource<object> tsource = new TaskCompletionSource<object>();
_ = m_coreDispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
KeyboardShortcutManager.OnWindowClosed(this.m_viewId);
Window.Current.Content = null;
this.InvokeWindowClosingHandlers();
// This is to ensure InvokeWindowClosingHandlers is be done before RemoveWindowFromMap
// If InvokeWindowClosingHandlers throws any exception we want it to crash the application
// so we are OK not setting closingHandlersCompletedEvent in that case
tsource.SetResult(new object());
this.m_coreDispatcher.StopProcessEvents();
Window.Current.Close();
});
return tsource.Task;
}
// Throws InvalidArgumentException if a service is already registered with the specified id
public void RegisterRuntimeWindowService(Type serviceId, object service)
{
if (TryResolveRuntimeWindowService(serviceId) != null)
{
throw new DuplicateNameException(serviceId + " already registered");
}
m_runtimeServicesMap[serviceId.Name] = service;
}
// Returns false if no service was registered with the specified id
public bool RemoveRuntimeWindowService(Type serviceId)
{
return m_runtimeServicesMap.Remove(serviceId.Name);
}
// Throws InvalidArgumentException if no service is registered with the specified id
public object ResolveRuntimeWindowService(Type serviceId)
{
var service = TryResolveRuntimeWindowService(serviceId);
if (service != null)
{
return service;
}
else
{
throw new EntryPointNotFoundException(serviceId.Name + " not found");
}
}
public Frame GetFrame()
{
return m_frame;
}
public void InvokeWindowClosingHandlers()
{
// Should be called only once just before we kill the window.
foreach (var handler in m_onWindowClosingHandlers)
{
handler();
}
m_onWindowClosingHandlers.Clear();
}
private WindowFrameService(Frame frame, WeakReference parent)
{
m_currentWindow = CoreWindow.GetForCurrentThread();
m_coreDispatcher = m_currentWindow.Dispatcher;
m_frame = frame;
m_parent = parent;
m_viewId = ApplicationView.GetApplicationViewIdForWindow(m_currentWindow);
}
private void InitializeFrameService(bool createdByUs)
{
Debug.Assert(createdByUs == (!CoreApplication.GetCurrentView().IsHosted && !CoreApplication.GetCurrentView().IsMain));
if (createdByUs)
{
ApplicationView.GetForCurrentView().Consolidated += OnConsolidated;
}
else
{
CoreWindow.GetForCurrentThread().Closed += OnClosed;
}
}
private void OnConsolidated(ApplicationView sender, ApplicationViewConsolidatedEventArgs e)
{
TraceLogger.GetInstance().DecreaseWindowCount();
if (m_parent.IsAlive)
{
var parent = m_parent.Target as App;
parent.RemoveWindow(this);
}
}
private void OnClosed(CoreWindow sender, CoreWindowEventArgs args)
{
if (m_parent.IsAlive)
{
var parent = m_parent.Target as App;
parent.RemoveSecondaryWindow(this);
}
}
// Returns nullptr if no service is registered with the specified id
private object TryResolveRuntimeWindowService(Type serviceId)
{
if (m_runtimeServicesMap.TryGetValue(serviceId.Name, out object retval))
{
return retval;
}
else
{
return null;
}
}
private readonly Windows.UI.Core.CoreWindow m_currentWindow;
private readonly Windows.UI.Core.CoreDispatcher m_coreDispatcher;
private Windows.UI.Xaml.Controls.Frame m_frame;
private readonly int m_viewId;
private readonly WeakReference m_parent;
private readonly Dictionary<string, object> m_runtimeServicesMap = new Dictionary<string, object>();
private readonly List<Action> m_onWindowClosingHandlers = new List<Action>();
}
}