initially migrated C# codebase by tian (#7)

* initial migrated C# codebase by tian

* format the codebase

* resolve comments

* undo: modifications on UI test project

* Remove the blocks that have more than 1 empty line.

* Register DP using keyword 'nameof'
This commit is contained in:
Tian L 2021-04-07 17:40:06 +08:00 committed by GitHub
commit 419a69c101
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 9430 additions and 0 deletions

View file

@ -25,6 +25,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GraphControl", "GraphContro
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TraceLogging", "TraceLogging\TraceLogging.vcxproj", "{FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calculator", "Calculator\Calculator.csproj", "{3B773403-B0D6-4F9A-948E-512A7A5FB315}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
@ -165,6 +167,30 @@ Global
{FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|x64.Build.0 = Release|x64
{FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|x86.ActiveCfg = Release|Win32
{FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|x86.Build.0 = Release|Win32
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM.ActiveCfg = Debug|ARM
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM.Build.0 = Debug|ARM
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM.Deploy.0 = Debug|ARM
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM64.ActiveCfg = Debug|ARM64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM64.Build.0 = Debug|ARM64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM64.Deploy.0 = Debug|ARM64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x64.ActiveCfg = Debug|x64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x64.Build.0 = Debug|x64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x64.Deploy.0 = Debug|x64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x86.ActiveCfg = Debug|x86
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x86.Build.0 = Debug|x86
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x86.Deploy.0 = Debug|x86
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM.ActiveCfg = Release|ARM
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM.Build.0 = Release|ARM
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM.Deploy.0 = Release|ARM
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM64.ActiveCfg = Release|ARM64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM64.Build.0 = Release|ARM64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM64.Deploy.0 = Release|ARM64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x64.ActiveCfg = Release|x64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x64.Build.0 = Release|x64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x64.Deploy.0 = Release|x64
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x86.ActiveCfg = Release|x86
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x86.Build.0 = Release|x86
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x86.Deploy.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

1778
src/Calculator/App.xaml Normal file

File diff suppressed because it is too large Load diff

511
src/Calculator/App.xaml.cs Normal file
View file

@ -0,0 +1,511 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// App.xaml.h
// Declaration of the App class.
//
using CalculatorApp.Common;
using CalculatorApp.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;
namespace CalculatorApp
{
namespace ApplicationResourceKeys
{
static public partial 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>
sealed partial class App
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
InitializeComponent();
m_preLaunched = false;
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;
// CSHARP_MIGRATION: TODO:
#if DEBUG
DebugSettings.IsBindingTracingEnabled = true;
DebugSettings.BindingFailed += (sender, args) =>
{
if (Debugger.IsAttached)
{
string errorMessage = args.Message;
Debugger.Break();
}
};
#endif
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// </summary>
/// <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;
}
OnAppLaunch(args, args.Arguments);
}
protected override void OnActivated(IActivatedEventArgs args)
{
if (args.Kind == ActivationKind.Protocol)
{
// We currently don't pass the uri as an argument,
// and handle any protocol launch as a normal app launch.
OnAppLaunch(args, null);
}
}
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();
frame.FlowDirection = LocalizationService.GetInstance().GetFlowDirection();
return frame;
}
private static void SetMinWindowSizeAndActivate(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;
Window.Current.Activate();
}
private void OnAppLaunch(IActivatedEventArgs args, string argument)
{
// Uncomment the following lines to display frame-rate and per-frame CPU usage info.
//#if _DEBUG
// if (IsDebuggerPresent())
// {
// DebugSettings->EnableFrameRateCounter = true;
// }
//#endif
args.SplashScreen.Dismissed += DismissedEventHandler;
var rootFrame = (Window.Current.Content as Frame);
WeakReference weak = new WeakReference(this);
float minWindowWidth = (float)((double)Resources[ApplicationResourceKeys.Globals.AppMinWindowWidth]);
float minWindowHeight = (float)((double)Resources[ApplicationResourceKeys.Globals.AppMinWindowHeight]);
Size minWindowSize = SizeHelper.FromDimensions(minWindowWidth, minWindowHeight);
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.Add("VeryFirstLaunch", false);
appView.SetPreferredMinSize(minWindowSize);
appView.TryResizeView(minWindowSize);
}
else
{
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.Auto;
}
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
if (!Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) // PC Family
{
// 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();
}
SetMinWindowSizeAndActivate(rootFrame, minWindowSize);
m_mainViewId = ApplicationView.GetForCurrentView().Id;
AddWindowToMap(WindowFrameService.CreateNewWindowFrameService(rootFrame, false, weak));
}
else
{
// 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 () =>
{
var that = weak.Target as App;
if (that != null)
{
var newRootFrame = App.CreateFrame();
SetMinWindowSizeAndActivate(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();
}
}
}
}
private void DismissedEventHandler(SplashScreen sender, object e)
{
_ = SetupJumpList();
}
private void RegisterDependencyProperties()
{
NarratorNotifier.RegisterDependencyProperties();
}
private void OnSuspending(object sender, SuspendingEventArgs args)
{
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 WindowFrameService m_frameService;
private bool m_frameOpenedInWindow;
private App m_parent;
};
// CSHARP_MIGRATION: TODO: check what is the pragma used for???
//#pragma optimize("", off) // Turn off optimizations to work around coroutine optimization bug
private async Task SetupJumpList()
{
try
{
// CSHARP_MIGRATION: TODO:
var calculatorOptions = NavCategoryGroup.CreateCalculatorCategory();
var jumpList = await JumpList.LoadCurrentAsync();
jumpList.SystemGroupKind = JumpListSystemGroupKind.None;
jumpList.Items.Clear();
// CSHARP_MIGRATION: TODO:
foreach (NavCategory option in calculatorOptions.Categories)
{
if (!option.IsEnabled)
{
continue;
}
ViewMode mode = option.Mode;
var item = JumpListItem.CreateWithArguments(((int)mode).ToString(), "ms-resource:///Resources/" + NavCategory.GetNameResourceKey(mode));
item.Description = "ms-resource:///Resources/" + NavCategory.GetNameResourceKey(mode);
item.Logo = new Uri("ms-appx:///Assets/" + mode.ToString() + ".png");
jumpList.Items.Add(item);
}
await jumpList.SaveAsync();
}
catch
{
}
}
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(m_secondaryWindows.size());
}
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 Dictionary<int, WindowFrameService> m_secondaryWindows = new Dictionary<int, WindowFrameService>();
private int m_mainViewId;
private bool m_preLaunched;
// CSHARP_MIGRATION: TODO: check whether or not this field is in use.
private Windows.UI.Xaml.Controls.Primitives.Popup m_aboutPopup;
}
}

View file

@ -0,0 +1,728 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{3B773403-B0D6-4F9A-948E-512A7A5FB315}</ProjectGuid>
<OutputType>AppContainerExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CalculatorApp</RootNamespace>
<AssemblyName>CalculatorApp</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.19041.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<PackageCertificateThumbprint>B06D4942DD6AAC6D5659E3AF866A11D0081C12C1</PackageCertificateThumbprint>
<PackageCertificateKeyFile>WindowsDev_TemporaryKey.pfx</PackageCertificateKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
<OutputPath>bin\ARM64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<PropertyGroup>
<AppVersion Condition="'$(AppVersion)' == ''">0.0.0.0</AppVersion>
</PropertyGroup>
<ItemGroup>
<ResourceCompile Include="Calculator.rc" PreprocessorDefinitions="%(PreprocessorDefinitions);APP_VERSION_MAJOR=$(AppVersion.Split(`.`)[0]);APP_VERSION_MINOR=$(AppVersion.Split(`.`)[1]);APP_VERSION_BUILD=$(AppVersion.Split(`.`)[2]);APP_VERSION_REVISION=$(AppVersion.Split(`.`)[3])" />
</ItemGroup>
<ItemGroup>
<Compile Include="AboutFlyout.xaml.cs">
<DependentUpon>AboutFlyout.xaml</DependentUpon>
</Compile>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="Common\AlwaysSelectedCollectionView.cs" />
<Compile Include="Common\AppLifecycleLogger.cs" />
<Compile Include="Common\KeyboardShortcuManager.cs" />
<Compile Include="Common\ValidatingConverters.cs" />
<Compile Include="Common\ViewState.cs" />
<Compile Include="Controls\CalculationResult.cs" />
<Compile Include="Controls\CalculationResultAutomationPeer.cs" />
<Compile Include="Controls\CalculatorButton.cs" />
<Compile Include="Controls\OperatorPanelButton.cs" />
<Compile Include="Controls\OperatorPanelListView.cs" />
<Compile Include="Controls\OverflowTextBlock.cs" />
<Compile Include="Controls\OverflowTextBlockAutomationPeer.cs" />
<Compile Include="Controls\EquationTextBox.cs" />
<Compile Include="Controls\FlipButtons.cs" />
<Compile Include="Controls\HorizontalNoOverflowStackPanel.cs" />
<Compile Include="Controls\MathRichEditBox.cs" />
<Compile Include="Controls\RadixButton.cs" />
<Compile Include="Controls\SupplementaryItemsControl.cs" />
<Compile Include="Converters\BooleanNegationConverter.cs" />
<Compile Include="Converters\BooleanToVisibilityConverter.cs" />
<Compile Include="Converters\ExpressionItemTemplateSelector.cs" />
<Compile Include="Converters\ItemSizeToVisibilityConverter.cs" />
<Compile Include="Converters\RadixToStringConverter.cs" />
<Compile Include="Converters\VisibilityNegationConverter.cs" />
<Compile Include="DelegateCommand.cs" />
<Compile Include="EquationStylePanelControl.xaml.cs">
<DependentUpon>EquationStylePanelControl.xaml</DependentUpon>
</Compile>
<Compile Include="KeyGraphFeaturesTemplateSelector.cs" />
<Compile Include="Views\Calculator.xaml.cs">
<DependentUpon>Calculator.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorProgrammerBitFlipPanel.xaml.cs">
<DependentUpon>CalculatorProgrammerBitFlipPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorProgrammerOperators.xaml.cs">
<DependentUpon>CalculatorProgrammerOperators.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorProgrammerRadixOperators.xaml.cs">
<DependentUpon>CalculatorProgrammerRadixOperators.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorScientificAngleButtons.xaml.cs">
<DependentUpon>CalculatorScientificAngleButtons.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorScientificOperators.xaml.cs">
<DependentUpon>CalculatorScientificOperators.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorStandardOperators.xaml.cs">
<DependentUpon>CalculatorStandardOperators.xaml</DependentUpon>
</Compile>
<Compile Include="Views\DateCalculator.xaml.cs">
<DependentUpon>DateCalculator.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\EquationInputArea.xaml.cs">
<DependentUpon>EquationInputArea.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\GraphingCalculator.xaml.cs">
<DependentUpon>GraphingCalculator.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\GraphingNumPad.xaml.cs">
<DependentUpon>GraphingNumPad.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\GraphingSettings.xaml.cs">
<DependentUpon>GraphingSettings.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml.cs">
<DependentUpon>KeyGraphFeaturesPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\HistoryList.xaml.cs">
<DependentUpon>HistoryList.xaml</DependentUpon>
</Compile>
<Compile Include="Views\MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\DispatcherTimerDelayer.cs" />
<Compile Include="Utils\VisualTree.cs" />
<Compile Include="Views\Memory.xaml.cs">
<DependentUpon>Memory.xaml</DependentUpon>
</Compile>
<Compile Include="Views\MemoryListItem.xaml.cs">
<DependentUpon>MemoryListItem.xaml</DependentUpon>
</Compile>
<Compile Include="Views\NumberPad.xaml.cs">
<DependentUpon>NumberPad.xaml</DependentUpon>
</Compile>
<Compile Include="Views\OperatorsPanel.xaml.cs">
<DependentUpon>OperatorsPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\StateTriggers\AspectRatioTrigger.cs" />
<Compile Include="Views\StateTriggers\CalculatorProgrammerDisplayPanel.xaml.cs">
<DependentUpon>CalculatorProgrammerDisplayPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\StateTriggers\ControlSizeTrigger.cs" />
<Compile Include="Views\SupplementaryResults.xaml.cs">
<DependentUpon>SupplementaryResults.xaml</DependentUpon>
</Compile>
<Compile Include="Views\TitleBar.xaml.cs">
<DependentUpon>TitleBar.xaml</DependentUpon>
</Compile>
<Compile Include="WindowFrameService.cs" />
<Compile Include="WinMeta.cs" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="Assets\CalculatorAppList.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorLargeTile.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorLargeTile.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorLargeTile.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorLargeTile.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorLargeTile.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorMedTile.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorMedTile.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorMedTile.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorMedTile.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorMedTile.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorMedTile.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorMedTile.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorMedTile.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorMedTile.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorMedTile.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorSmallTile.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorSmallTile.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorSmallTile.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorSmallTile.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorSmallTile.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorSmallTile.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorSmallTile.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorSmallTile.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorSmallTile.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorSmallTile.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-100_altform-colorful.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-125_altform-colorful.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-150_altform-colorful.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-200_altform-colorful.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-400.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-400_altform-colorful.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorWideTile.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorWideTile.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorWideTile.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorWideTile.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorWideTile.scale-400_contrast-white.png" />
<Content Include="Assets\Date.targetsize-16_contrast-black.png" />
<Content Include="Assets\Date.targetsize-16_contrast-white.png" />
<Content Include="Assets\Date.targetsize-20_contrast-black.png" />
<Content Include="Assets\Date.targetsize-20_contrast-white.png" />
<Content Include="Assets\Date.targetsize-24_contrast-black.png" />
<Content Include="Assets\Date.targetsize-24_contrast-white.png" />
<Content Include="Assets\Date.targetsize-32_contrast-black.png" />
<Content Include="Assets\Date.targetsize-32_contrast-white.png" />
<Content Include="Assets\Date.targetsize-64_contrast-black.png" />
<Content Include="Assets\Date.targetsize-64_contrast-white.png" />
<Content Include="Assets\Graphing.targetsize-16.png" />
<Content Include="Assets\Graphing.targetsize-16_contrast-black.png" />
<Content Include="Assets\Graphing.targetsize-16_contrast-white.png" />
<Content Include="Assets\Graphing.targetsize-20.png" />
<Content Include="Assets\Graphing.targetsize-20_contrast-black.png" />
<Content Include="Assets\Graphing.targetsize-20_contrast-white.png" />
<Content Include="Assets\Graphing.targetsize-24.png" />
<Content Include="Assets\Graphing.targetsize-24_contrast-black.png" />
<Content Include="Assets\Graphing.targetsize-24_contrast-white.png" />
<Content Include="Assets\Graphing.targetsize-32.png" />
<Content Include="Assets\Graphing.targetsize-32_contrast-black.png" />
<Content Include="Assets\Graphing.targetsize-32_contrast-white.png" />
<Content Include="Assets\Graphing.targetsize-64.png" />
<Content Include="Assets\Graphing.targetsize-64_contrast-black.png" />
<Content Include="Assets\Graphing.targetsize-64_contrast-white.png" />
<Content Include="Assets\Programmer.targetsize-16_contrast-black.png" />
<Content Include="Assets\Programmer.targetsize-16_contrast-white.png" />
<Content Include="Assets\Programmer.targetsize-20_contrast-black.png" />
<Content Include="Assets\Programmer.targetsize-20_contrast-white.png" />
<Content Include="Assets\Programmer.targetsize-24_contrast-black.png" />
<Content Include="Assets\Programmer.targetsize-24_contrast-white.png" />
<Content Include="Assets\Programmer.targetsize-32_contrast-black.png" />
<Content Include="Assets\Programmer.targetsize-32_contrast-white.png" />
<Content Include="Assets\Programmer.targetsize-64_contrast-black.png" />
<Content Include="Assets\Programmer.targetsize-64_contrast-white.png" />
<Content Include="Assets\Scientific.targetsize-16_contrast-black.png" />
<Content Include="Assets\Scientific.targetsize-16_contrast-white.png" />
<Content Include="Assets\Scientific.targetsize-20_contrast-black.png" />
<Content Include="Assets\Scientific.targetsize-20_contrast-white.png" />
<Content Include="Assets\Scientific.targetsize-24_contrast-black.png" />
<Content Include="Assets\Scientific.targetsize-24_contrast-white.png" />
<Content Include="Assets\Scientific.targetsize-32_contrast-black.png" />
<Content Include="Assets\Scientific.targetsize-32_contrast-white.png" />
<Content Include="Assets\Scientific.targetsize-64_contrast-black.png" />
<Content Include="Assets\Scientific.targetsize-64_contrast-white.png" />
<Content Include="Assets\Standard.targetsize-16_contrast-black.png" />
<Content Include="Assets\Standard.targetsize-16_contrast-white.png" />
<Content Include="Assets\Standard.targetsize-20_contrast-black.png" />
<Content Include="Assets\Standard.targetsize-20_contrast-white.png" />
<Content Include="Assets\Standard.targetsize-24_contrast-black.png" />
<Content Include="Assets\Standard.targetsize-24_contrast-white.png" />
<Content Include="Assets\Standard.targetsize-32_contrast-black.png" />
<Content Include="Assets\Standard.targetsize-32_contrast-white.png" />
<Content Include="Assets\Standard.targetsize-64_contrast-black.png" />
<Content Include="Assets\Standard.targetsize-64_contrast-white.png" />
<Content Include="Properties\Default.rd.xml" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Resources\af-ZA\CEngineStrings.resw" />
<PRIResource Include="Resources\af-ZA\Resources.resw" />
<PRIResource Include="Resources\am-et\CEngineStrings.resw" />
<PRIResource Include="Resources\am-et\Resources.resw" />
<PRIResource Include="Resources\ar-sa\CEngineStrings.resw" />
<PRIResource Include="Resources\ar-sa\Resources.resw" />
<PRIResource Include="Resources\az-Latn-AZ\CEngineStrings.resw" />
<PRIResource Include="Resources\az-Latn-AZ\Resources.resw" />
<PRIResource Include="Resources\bg-BG\CEngineStrings.resw" />
<PRIResource Include="Resources\bg-BG\Resources.resw" />
<PRIResource Include="Resources\ca-es\CEngineStrings.resw" />
<PRIResource Include="Resources\ca-es\Resources.resw" />
<PRIResource Include="Resources\cs-cz\CEngineStrings.resw" />
<PRIResource Include="Resources\cs-cz\Resources.resw" />
<PRIResource Include="Resources\da-DK\CEngineStrings.resw" />
<PRIResource Include="Resources\da-DK\Resources.resw" />
<PRIResource Include="Resources\de-de\CEngineStrings.resw" />
<PRIResource Include="Resources\de-de\Resources.resw" />
<PRIResource Include="Resources\el-GR\CEngineStrings.resw" />
<PRIResource Include="Resources\el-GR\Resources.resw" />
<PRIResource Include="Resources\en-gb\CEngineStrings.resw" />
<PRIResource Include="Resources\en-gb\Resources.resw" />
<PRIResource Include="Resources\en-US\CEngineStrings.resw" />
<PRIResource Include="Resources\en-US\Resources.resw">
<SubType>Designer</SubType>
</PRIResource>
<PRIResource Include="Resources\es-es\CEngineStrings.resw" />
<PRIResource Include="Resources\es-es\Resources.resw" />
<PRIResource Include="Resources\es-mx\CEngineStrings.resw" />
<PRIResource Include="Resources\es-mx\resources.resw" />
<PRIResource Include="Resources\et-EE\CEngineStrings.resw" />
<PRIResource Include="Resources\et-EE\Resources.resw" />
<PRIResource Include="Resources\eu-ES\CEngineStrings.resw" />
<PRIResource Include="Resources\eu-ES\Resources.resw" />
<PRIResource Include="Resources\fa-IR\CEngineStrings.resw" />
<PRIResource Include="Resources\fa-IR\Resources.resw" />
<PRIResource Include="Resources\fi-fi\CEngineStrings.resw" />
<PRIResource Include="Resources\fi-fi\Resources.resw" />
<PRIResource Include="Resources\fil-PH\CEngineStrings.resw" />
<PRIResource Include="Resources\fil-PH\Resources.resw" />
<PRIResource Include="Resources\fr-ca\CEngineStrings.resw" />
<PRIResource Include="Resources\fr-ca\resources.resw" />
<PRIResource Include="Resources\fr-fr\CEngineStrings.resw" />
<PRIResource Include="Resources\fr-fr\Resources.resw" />
<PRIResource Include="Resources\gl-ES\CEngineStrings.resw" />
<PRIResource Include="Resources\gl-ES\Resources.resw" />
<PRIResource Include="Resources\he-IL\CEngineStrings.resw" />
<PRIResource Include="Resources\he-IL\Resources.resw" />
<PRIResource Include="Resources\hi-in\CEngineStrings.resw" />
<PRIResource Include="Resources\hi-in\Resources.resw" />
<PRIResource Include="Resources\hr-HR\CEngineStrings.resw" />
<PRIResource Include="Resources\hr-HR\Resources.resw" />
<PRIResource Include="Resources\hu-HU\CEngineStrings.resw" />
<PRIResource Include="Resources\hu-HU\Resources.resw" />
<PRIResource Include="Resources\id-ID\CEngineStrings.resw" />
<PRIResource Include="Resources\id-ID\Resources.resw" />
<PRIResource Include="Resources\is-IS\CEngineStrings.resw" />
<PRIResource Include="Resources\is-IS\Resources.resw" />
<PRIResource Include="Resources\it-it\CEngineStrings.resw" />
<PRIResource Include="Resources\it-it\Resources.resw" />
<PRIResource Include="Resources\ja-jp\CEngineStrings.resw" />
<PRIResource Include="Resources\ja-jp\Resources.resw" />
<PRIResource Include="Resources\kk-KZ\CEngineStrings.resw" />
<PRIResource Include="Resources\kk-KZ\Resources.resw" />
<PRIResource Include="Resources\km-KH\CEngineStrings.resw" />
<PRIResource Include="Resources\km-KH\Resources.resw" />
<PRIResource Include="Resources\kn-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\kn-IN\Resources.resw" />
<PRIResource Include="Resources\ko-kr\CEngineStrings.resw" />
<PRIResource Include="Resources\ko-kr\Resources.resw" />
<PRIResource Include="Resources\lo-LA\CEngineStrings.resw" />
<PRIResource Include="Resources\lo-LA\Resources.resw" />
<PRIResource Include="Resources\lt-LT\CEngineStrings.resw" />
<PRIResource Include="Resources\lt-LT\Resources.resw" />
<PRIResource Include="Resources\lv-LV\CEngineStrings.resw" />
<PRIResource Include="Resources\lv-LV\Resources.resw" />
<PRIResource Include="Resources\mk-MK\CEngineStrings.resw" />
<PRIResource Include="Resources\mk-MK\Resources.resw" />
<PRIResource Include="Resources\ml-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\ml-IN\Resources.resw" />
<PRIResource Include="Resources\ms-MY\CEngineStrings.resw" />
<PRIResource Include="Resources\ms-MY\Resources.resw" />
<PRIResource Include="Resources\nb-NO\CEngineStrings.resw" />
<PRIResource Include="Resources\nb-NO\Resources.resw" />
<PRIResource Include="Resources\nl-nl\CEngineStrings.resw" />
<PRIResource Include="Resources\nl-nl\Resources.resw" />
<PRIResource Include="Resources\pl-pl\CEngineStrings.resw" />
<PRIResource Include="Resources\pl-pl\Resources.resw" />
<PRIResource Include="Resources\pt-br\CEngineStrings.resw" />
<PRIResource Include="Resources\pt-br\Resources.resw" />
<PRIResource Include="Resources\pt-PT\CEngineStrings.resw" />
<PRIResource Include="Resources\pt-PT\Resources.resw" />
<PRIResource Include="Resources\ro-RO\CEngineStrings.resw" />
<PRIResource Include="Resources\ro-RO\Resources.resw" />
<PRIResource Include="Resources\ru-ru\CEngineStrings.resw" />
<PRIResource Include="Resources\ru-ru\Resources.resw" />
<PRIResource Include="Resources\sk-SK\CEngineStrings.resw" />
<PRIResource Include="Resources\sk-SK\Resources.resw" />
<PRIResource Include="Resources\sl-SI\CEngineStrings.resw" />
<PRIResource Include="Resources\sl-SI\Resources.resw" />
<PRIResource Include="Resources\sq-AL\CEngineStrings.resw" />
<PRIResource Include="Resources\sq-AL\Resources.resw" />
<PRIResource Include="Resources\sr-Latn-RS\CEngineStrings.resw" />
<PRIResource Include="Resources\sr-Latn-RS\Resources.resw" />
<PRIResource Include="Resources\sv-se\CEngineStrings.resw" />
<PRIResource Include="Resources\sv-se\Resources.resw" />
<PRIResource Include="Resources\ta-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\ta-IN\Resources.resw" />
<PRIResource Include="Resources\te-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\te-IN\Resources.resw" />
<PRIResource Include="Resources\th-th\CEngineStrings.resw" />
<PRIResource Include="Resources\th-th\Resources.resw" />
<PRIResource Include="Resources\tr-tr\CEngineStrings.resw" />
<PRIResource Include="Resources\tr-tr\Resources.resw" />
<PRIResource Include="Resources\uk-UA\CEngineStrings.resw" />
<PRIResource Include="Resources\uk-UA\Resources.resw" />
<PRIResource Include="Resources\vi-vn\CEngineStrings.resw" />
<PRIResource Include="Resources\vi-vn\Resources.resw" />
<PRIResource Include="Resources\zh-cn\CEngineStrings.resw" />
<PRIResource Include="Resources\zh-cn\Resources.resw" />
<PRIResource Include="Resources\zh-tw\CEngineStrings.resw" />
<PRIResource Include="Resources\zh-tw\Resources.resw" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="EquationStylePanelControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="AboutFlyout.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Calculator.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorProgrammerBitFlipPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorProgrammerOperators.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorProgrammerRadixOperators.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorScientificAngleButtons.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorScientificOperators.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorStandardOperators.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\DateCalculator.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\GraphingCalculator\EquationInputArea.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\GraphingCalculator\GraphingCalculator.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\GraphingCalculator\GraphingNumPad.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\GraphingCalculator\GraphingSettings.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\HistoryList.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\MainPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\Memory.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\MemoryListItem.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\NumberPad.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\OperatorsPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\StateTriggers\CalculatorProgrammerDisplayPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SupplementaryResults.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\TitleBar.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.10</Version>
</PackageReference>
<PackageReference Include="Microsoft.UI.Xaml" Version="2.4.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CalcViewModel\CalcViewModel.vcxproj">
<Project>{812d1a7b-b8ac-49e4-8e6d-af5d59500d56}</Project>
<Name>CalcViewModel</Name>
</ProjectReference>
<ProjectReference Include="..\GraphControl\GraphControl.vcxproj">
<Project>{e727a92b-f149-492c-8117-c039a298719b}</Project>
<Name>GraphControl</Name>
</ProjectReference>
<ProjectReference Include="..\TraceLogging\TraceLogging.vcxproj">
<Project>{fc81ff41-02cd-4cd9-9bc5-45a1e39ac6ed}</Project>
<Name>TraceLogging</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="Assets\CalcMDL2.ttf" />
<None Include="WindowsDev_TemporaryKey.pfx" />
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -0,0 +1,256 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections;
using System.Collections.Generic;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml.Data;
namespace CalculatorApp
{
namespace Common
{
sealed class AlwaysSelectedCollectionView : Windows.UI.Xaml.DependencyObject, Windows.UI.Xaml.Data.ICollectionView
{
internal AlwaysSelectedCollectionView(IList source)
{
m_currentPosition = -1;
m_source = source;
var observable = source as Windows.UI.Xaml.Interop.IBindableObservableVector;
if (observable != null)
{
observable.VectorChanged += OnSourceBindableVectorChanged;
}
}
public bool MoveCurrentTo(object item)
{
if (item != null)
{
int newCurrentPosition = m_source.IndexOf(item);
if (newCurrentPosition != -1)
{
m_currentPosition = newCurrentPosition;
CurrentChanged(this, null);
return true;
}
}
// The item is not in the collection
// We're going to schedule a call back later so we
// restore the selection to the way we wanted it to begin with
if (m_currentPosition >= 0 && m_currentPosition < m_source.Count)
{
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, new Windows.UI.Core.DispatchedHandler(() =>
{
CurrentChanged(this, null);
})).AsTask().Wait();
}
return false;
}
public bool MoveCurrentToPosition(int index)
{
if (index < 0 || index >= m_source.Count)
{
return false;
}
m_currentPosition = index;
CurrentChanged(this, null);
return true;
}
#region no implementations
public bool MoveCurrentToFirst()
{
throw new NotImplementedException();
}
public bool MoveCurrentToLast()
{
throw new NotImplementedException();
}
public bool MoveCurrentToNext()
{
throw new NotImplementedException();
}
public bool MoveCurrentToPrevious()
{
throw new NotImplementedException();
}
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
throw new NotImplementedException();
}
public void Insert(int index, object item)
{
throw new NotImplementedException();
}
public void RemoveAt(int index)
{
throw new NotImplementedException();
}
public void Add(object item)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(object item)
{
throw new NotImplementedException();
}
public void CopyTo(object[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(object item)
{
throw new NotImplementedException();
}
public bool IsReadOnly => throw new NotImplementedException();
#endregion no implementations
public object this[int index]
{
get
{
return m_source[index];
}
set => throw new NotImplementedException();
}
public int Count
{
get
{
return m_source.Count;
}
}
public IObservableVector<object> CollectionGroups
{
get
{
return (IObservableVector<object>)new List<object>();
}
}
public object CurrentItem
{
get
{
if (m_currentPosition >= 0 && m_currentPosition < m_source.Count)
{
return m_source[m_currentPosition];
}
return null;
}
}
public int CurrentPosition
{
get
{
return m_currentPosition;
}
}
public bool HasMoreItems
{
get
{
return false;
}
}
public bool IsCurrentAfterLast
{
get
{
return m_currentPosition >= m_source.Count;
}
}
public bool IsCurrentBeforeFirst
{
get
{
return m_currentPosition < 0;
}
}
public int IndexOf(object item)
{
return m_source.IndexOf(item);
}
public IEnumerator<object> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
// Event handlers
void OnSourceBindableVectorChanged(Windows.UI.Xaml.Interop.IBindableObservableVector source, object e)
{
Windows.Foundation.Collections.IVectorChangedEventArgs args = (Windows.Foundation.Collections.IVectorChangedEventArgs)e;
VectorChanged(this, args);
}
public event EventHandler<object> CurrentChanged;
public event CurrentChangingEventHandler CurrentChanging; // CSHARP_MIGRATION: TODO: check why this member is never being used.
public event VectorChangedEventHandler<object> VectorChanged;
IList m_source;
int m_currentPosition;
}
public sealed class AlwaysSelectedCollectionViewConverter : Windows.UI.Xaml.Data.IValueConverter
{
public AlwaysSelectedCollectionViewConverter()
{
}
public object Convert(object value, Type targetType, object parameter, string language)
{
var result = value as IList;
if (result != null)
{
return new AlwaysSelectedCollectionView(result);
}
return Windows.UI.Xaml.DependencyProperty.UnsetValue; // Can't convert
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return Windows.UI.Xaml.DependencyProperty.UnsetValue;
}
}
}
}

View file

@ -0,0 +1,151 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Core;
using Windows.Foundation.Diagnostics;
using Windows.UI.ViewManagement;
namespace CalculatorApp
{
static public partial class Globals
{
#if SEND_DIAGNOSTICS
// c.f. WINEVENT_KEYWORD_RESERVED_63-56 0xFF00000000000000 // Bits 63-56 - channel keywords
// c.f. WINEVENT_KEYWORD_* 0x00FF000000000000 // Bits 55-48 - system-reserved keywords
public const long MICROSOFT_KEYWORD_LEVEL_1 = 0x0000800000000000; // Bit 47
public const long MICROSOFT_KEYWORD_LEVEL_2 = 0x0000400000000000; // Bit 46
public const long MICROSOFT_KEYWORD_LEVEL_3 = 0x0000200000000000; // Bit 45
public const long MICROSOFT_KEYWORD_RESERVED_44 = 0x0000100000000000; // Bit 44 (reserved for future assignment)
#else
// define all Keyword options as 0 when we do not want to upload app diagnostics
public const long MICROSOFT_KEYWORD_LEVEL_1 = 0;
public const long MICROSOFT_KEYWORD_LEVEL_2 = 0;
public const long MICROSOFT_KEYWORD_LEVEL_3 = 0;
public const long MICROSOFT_KEYWORD_RESERVED_44 = 0;
#endif
}
class AppLifecycleLogger
{
public static AppLifecycleLogger GetInstance()
{
return s_selfInstance.Value;
}
public bool GetTraceLoggingProviderEnabled()
{
return m_appLifecycleProvider.Enabled;
}
public void LaunchUIResponsive()
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
LogAppLifecycleEvent("ModernAppLaunch_UIResponsive", fields);
}
public void LaunchVisibleComplete()
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
LogAppLifecycleEvent("ModernAppLaunch_VisibleComplete", fields);
}
public void ResumeUIResponsive()
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
LogAppLifecycleEvent("ModernAppResume_UIResponsive", fields);
}
public void ResumeVisibleComplete()
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
LogAppLifecycleEvent("ModernAppResume_VisibleComplete", fields);
}
public void ResizeUIResponsive()
{
ResizeUIResponsive(ApplicationView.GetForCurrentView().Id);
}
public void ResizeVisibleComplete()
{
ResizeVisibleComplete(ApplicationView.GetForCurrentView().Id);
}
public void ResizeUIResponsive(int viewId)
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
fields.AddInt32("ViewId", viewId);
LogAppLifecycleEvent("ModernAppResize_UIResponsive", fields);
}
public void ResizeVisibleComplete(int viewId)
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
fields.AddInt32("ViewId", viewId);
LogAppLifecycleEvent("ModernAppResize_VisibleComplete", fields);
}
// Make the object construction private to allow singleton access to this class
private AppLifecycleLogger()
{
m_appLifecycleProvider = new LoggingChannel(
"Microsoft.Windows.AppLifeCycle",
new LoggingChannelOptions(new Guid(0x4f50731a, 0x89cf, 0x4782, 0xb3, 0xe0, 0xdc, 0xe8, 0xc9, 0x4, 0x76, 0xba)),
new Guid(0xef00584a, 0x2655, 0x462c, 0xbc, 0x24, 0xe7, 0xde, 0x63, 0xe, 0x7f, 0xbf));
}
// Any new Log method should
// a) Decide the level of logging. This will help us in limiting recording of events only up to a certain level. See this link for guidance
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363742(v=vs.85).aspx We're using Verbose level for events that are called frequently and
// needed only for debugging or capturing perf for specific scenarios b) Should decide whether or not to log to diagnostics and pass
// TraceLoggingKeyword(MICROSOFT_KEYWORD_LEVEL_3) accordingly c) Should accept a variable number of additional data arguments if needed
private void LogAppLifecycleEvent(string eventName, LoggingFields fields)
{
m_appLifecycleProvider.LogEvent(
eventName, fields, LoggingLevel.Information, new LoggingOptions(Globals.MICROSOFT_KEYWORD_LEVEL_3 | WinMeta.WINEVENT_KEYWORD_RESPONSE_TIME));
}
private void PopulateAppInfo(LoggingFields fields)
{
var appId = CoreApplication.Id;
var aumId = Package.Current.Id.FamilyName + "!" + appId;
var packageFullName = Package.Current.Id.FullName;
var psmKey = Package.Current.Id.FullName + "+" + appId;
fields.AddString("AumId", aumId);
fields.AddString("PackageFullName", packageFullName);
fields.AddString("PsmKey", psmKey);
}
private LoggingChannel m_appLifecycleProvider;
private static readonly Lazy<AppLifecycleLogger> s_selfInstance = new Lazy<AppLifecycleLogger>(() => new AppLifecycleLogger(), true);
}
}

View file

@ -0,0 +1,834 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.ViewModel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using MUXC = Microsoft.UI.Xaml.Controls;
namespace CalculatorApp
{
namespace Common
{
static partial class KeyboardShortcutManagerLocals
{
// Lights up all of the buttons in the given range
// The range is defined by a pair of iterators
static public void LightUpButtons(IEnumerable<WeakReference> buttons)
{
foreach (var button in buttons)
{
var btn = button.Target as ButtonBase;
if (btn != null && btn.IsEnabled)
{
LightUpButton(btn);
}
}
}
static public void LightUpButton(ButtonBase button)
{
// If the button is a toggle button then we don't need
// to change the UI of the button
if (button is ToggleButton)
{
return;
}
// The button will go into the visual Pressed state with this call
VisualStateManager.GoToState(button, "Pressed", true);
// This timer will fire after lightUpTime and make the button
// go back to the normal state.
// This timer will only fire once after which it will be destroyed
var timer = new DispatcherTimer();
TimeSpan lightUpTime = TimeSpan.FromMilliseconds(500); // half second
timer.Interval = lightUpTime;
var timerWeakReference = new WeakReference(timer);
var buttonWeakReference = new WeakReference(button);
timer.Tick += (sender, args) =>
{
var btn = buttonWeakReference.Target as ButtonBase;
if (btn != null)
{
VisualStateManager.GoToState(button, "Normal", true);
}
var tmr = timerWeakReference.Target as DispatcherTimer;
if (tmr != null)
{
tmr.Stop();
}
};
timer.Start();
}
// Looks for the first button reference that it can resolve
// and execute its command.
// NOTE: It is assumed that all buttons associated with a particular
// key have the same command
static public void RunFirstEnabledButtonCommand(IEnumerable<WeakReference> buttons)
{
foreach (var button in buttons)
{
var btn = button.Target as ButtonBase;
if (btn != null && btn.IsEnabled)
{
RunButtonCommand(btn);
break;
}
}
}
static public void RunButtonCommand(ButtonBase button)
{
if (button.IsEnabled)
{
var command = button.Command;
var parameter = button.CommandParameter;
if (command != null && command.CanExecute(parameter))
{
command.Execute(parameter);
}
var radio = (button as RadioButton);
if (radio != null)
{
radio.IsChecked = true;
return;
}
var toggle = (button as ToggleButton);
if (toggle != null)
{
toggle.IsChecked = !(toggle.IsChecked != null && toggle.IsChecked.Value);
return;
}
}
}
}
public sealed class KeyboardShortcutManager : DependencyObject
{
public KeyboardShortcutManager()
{
}
public static readonly DependencyProperty CharacterProperty =
DependencyProperty.RegisterAttached(
"Character",
typeof(string),
typeof(KeyboardShortcutManager),
new PropertyMetadata(string.Empty, (sender, args) =>
{
OnCharacterPropertyChanged(sender, (string)args.OldValue, (string)args.NewValue);
}));
public static string GetCharacter(DependencyObject target)
{
return (string)target.GetValue(CharacterProperty);
}
public static void SetCharacter(DependencyObject target, string value)
{
target.SetValue(CharacterProperty, value);
}
public static readonly DependencyProperty VirtualKeyProperty =
DependencyProperty.RegisterAttached(
"VirtualKey",
typeof(MyVirtualKey),
typeof(KeyboardShortcutManager),
new PropertyMetadata(default(MyVirtualKey), (sender, args) =>
{
OnVirtualKeyPropertyChanged(sender, (MyVirtualKey)args.OldValue, (MyVirtualKey)args.NewValue);
}));
public static MyVirtualKey GetVirtualKey(DependencyObject target)
{
return (MyVirtualKey)target.GetValue(VirtualKeyProperty);
}
public static void SetVirtualKey(DependencyObject target, MyVirtualKey value)
{
target.SetValue(VirtualKeyProperty, value);
}
public static readonly DependencyProperty VirtualKeyControlChordProperty =
DependencyProperty.RegisterAttached(
"VirtualKey",
typeof(MyVirtualKey),
typeof(KeyboardShortcutManager),
new PropertyMetadata(default(MyVirtualKey), (sender, args) =>
{
OnVirtualKeyControlChordPropertyChanged(sender, (MyVirtualKey)args.OldValue, (MyVirtualKey)args.NewValue);
}));
public static MyVirtualKey GetVirtualKeyControlChord(DependencyObject target)
{
return (MyVirtualKey)target.GetValue(VirtualKeyControlChordProperty);
}
public static void SetVirtualKeyControlChord(DependencyObject target, MyVirtualKey value)
{
target.SetValue(VirtualKeyControlChordProperty, value);
}
public static readonly DependencyProperty VirtualKeyShiftChordProperty =
DependencyProperty.RegisterAttached(
"VirtualKey",
typeof(MyVirtualKey),
typeof(KeyboardShortcutManager),
new PropertyMetadata(default(MyVirtualKey), (sender, args) =>
{
OnVirtualKeyShiftChordPropertyChanged(sender, (MyVirtualKey)args.OldValue, (MyVirtualKey)args.NewValue);
}));
public static MyVirtualKey GetVirtualKeyShiftChord(DependencyObject target)
{
return (MyVirtualKey)target.GetValue(VirtualKeyShiftChordProperty);
}
public static void SetVirtualKeyShiftChord(DependencyObject target, MyVirtualKey value)
{
target.SetValue(VirtualKeyShiftChordProperty, value);
}
public static readonly DependencyProperty VirtualKeyAltChordProperty =
DependencyProperty.RegisterAttached(
"VirtualKey",
typeof(MyVirtualKey),
typeof(KeyboardShortcutManager),
new PropertyMetadata(default(MyVirtualKey), (sender, args) =>
{
OnVirtualKeyAltChordPropertyChanged(sender, (MyVirtualKey)args.OldValue, (MyVirtualKey)args.NewValue);
}));
public static MyVirtualKey GetVirtualKeyAltChord(DependencyObject target)
{
return (MyVirtualKey)target.GetValue(VirtualKeyAltChordProperty);
}
public static void SetVirtualKeyAltChord(DependencyObject target, MyVirtualKey value)
{
target.SetValue(VirtualKeyAltChordProperty, value);
}
public static readonly DependencyProperty VirtualKeyControlShiftChordProperty =
DependencyProperty.RegisterAttached(
"VirtualKey",
typeof(MyVirtualKey),
typeof(KeyboardShortcutManager),
new PropertyMetadata(default(MyVirtualKey), (sender, args) =>
{
OnVirtualKeyControlShiftChordPropertyChanged(sender, (MyVirtualKey)args.OldValue, (MyVirtualKey)args.NewValue);
}));
public static MyVirtualKey GetVirtualKeyControlShiftChord(DependencyObject target)
{
return (MyVirtualKey)target.GetValue(VirtualKeyControlShiftChordProperty);
}
public static void SetVirtualKeyControlShiftChord(DependencyObject target, MyVirtualKey value)
{
target.SetValue(VirtualKeyControlShiftChordProperty, value);
}
internal static void Initialize()
{
var coreWindow = Window.Current.CoreWindow;
coreWindow.CharacterReceived += OnCharacterReceivedHandler;
coreWindow.KeyDown += OnKeyDownHandler;
coreWindow.Dispatcher.AcceleratorKeyActivated += OnAcceleratorKeyActivated;
KeyboardShortcutManager.RegisterNewAppViewId();
}
// Sometimes, like with popups, escape is treated as special and even
// though it is handled we get it passed through to us. In those cases
// we need to be able to ignore it (looking at e->Handled isn't sufficient
// because that always returns true).
// The onlyOnce flag is used to indicate whether we should only ignore the
// next escape, or keep ignoring until you explicitly HonorEscape.
public static void IgnoreEscape(bool onlyOnce)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
int viewId = Utilities.GetWindowId();
if (s_ignoreNextEscape.ContainsKey(viewId))
{
s_ignoreNextEscape[viewId] = true;
}
if (s_keepIgnoringEscape.ContainsKey(viewId))
{
s_keepIgnoringEscape[viewId] = !onlyOnce;
}
}
}
public static void HonorEscape()
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
int viewId = Utilities.GetWindowId();
if (s_ignoreNextEscape.ContainsKey(viewId))
{
s_ignoreNextEscape[viewId] = false;
}
if (s_keepIgnoringEscape.ContainsKey(viewId))
{
s_keepIgnoringEscape[viewId] = false;
}
}
}
public static void HonorShortcuts(bool allow)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
int viewId = Utilities.GetWindowId();
if (s_fHonorShortcuts.ContainsKey(viewId))
{
if (s_fDisableShortcuts.ContainsKey(viewId))
{
if (s_fDisableShortcuts[viewId])
{
s_fHonorShortcuts[viewId] = false;
return;
}
}
s_fHonorShortcuts[viewId] = allow;
}
}
}
public static void DisableShortcuts(bool disable)
{
int viewId = Utilities.GetWindowId();
if (s_fDisableShortcuts.ContainsKey(viewId))
{
s_fDisableShortcuts[viewId] = disable;
}
HonorShortcuts(!disable);
}
public static void UpdateDropDownState(bool isOpen)
{
int viewId = Utilities.GetWindowId();
if (s_IsDropDownOpen.ContainsKey(viewId))
{
s_IsDropDownOpen[viewId] = isOpen;
}
}
public static void RegisterNewAppViewId()
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
int appViewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (!s_characterForButtons.ContainsKey(appViewId))
{
s_characterForButtons.Add(appViewId, new SortedDictionary<char, List<WeakReference>>());
}
if (!s_virtualKey.ContainsKey(appViewId))
{
s_virtualKey.Add(appViewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
}
if (!s_VirtualKeyControlChordsForButtons.ContainsKey(appViewId))
{
s_VirtualKeyControlChordsForButtons.Add(appViewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
}
if (!s_VirtualKeyShiftChordsForButtons.ContainsKey(appViewId))
{
s_VirtualKeyShiftChordsForButtons.Add(appViewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
}
if (!s_VirtualKeyAltChordsForButtons.ContainsKey(appViewId))
{
s_VirtualKeyAltChordsForButtons.Add(appViewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
}
if (!s_VirtualKeyControlShiftChordsForButtons.ContainsKey(appViewId))
{
s_VirtualKeyControlShiftChordsForButtons.Add(appViewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
}
s_IsDropDownOpen[appViewId] = false;
s_ignoreNextEscape[appViewId] = false;
s_keepIgnoringEscape[appViewId] = false;
s_fHonorShortcuts[appViewId] = true;
s_fDisableShortcuts[appViewId] = false;
}
}
public static void OnWindowClosed(int viewId)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
s_characterForButtons.Remove(viewId);
s_virtualKey.Remove(viewId);
s_VirtualKeyControlChordsForButtons.Remove(viewId);
s_VirtualKeyShiftChordsForButtons.Remove(viewId);
s_VirtualKeyAltChordsForButtons.Remove(viewId);
s_VirtualKeyControlShiftChordsForButtons.Remove(viewId);
s_IsDropDownOpen.Remove(viewId);
s_ignoreNextEscape.Remove(viewId);
s_keepIgnoringEscape.Remove(viewId);
s_fHonorShortcuts.Remove(viewId);
s_fDisableShortcuts.Remove(viewId);
}
}
private static void OnCharacterPropertyChanged(DependencyObject target, string oldValue, string newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
var button = (target as ButtonBase);
int viewId = Utilities.GetWindowId();
if (s_characterForButtons.TryGetValue(viewId, out var iterViewMap))
{
if (!string.IsNullOrEmpty(oldValue))
{
iterViewMap.Remove(oldValue[0]);
}
if (!string.IsNullOrEmpty(newValue))
{
if (newValue == ".")
{
char decSep = LocalizationSettings.GetInstance().GetDecimalSeparator();
Insert(iterViewMap, decSep, new WeakReference(button));
}
else
{
Insert(iterViewMap, newValue[0], new WeakReference(button));
}
}
}
else
{
s_characterForButtons.Add(viewId, new SortedDictionary<char, List<WeakReference>>());
if (newValue == ".")
{
char decSep = LocalizationSettings.GetInstance().GetDecimalSeparator();
Insert(s_characterForButtons[viewId], decSep, new WeakReference(button));
}
else
{
Insert(s_characterForButtons[viewId], newValue[0], new WeakReference(button));
}
}
}
}
private static void OnVirtualKeyPropertyChanged(DependencyObject target, MyVirtualKey oldValue, MyVirtualKey newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
var button = ((ButtonBase)target);
int viewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (s_virtualKey.TryGetValue(viewId, out var iterViewMap))
{
Insert(iterViewMap, newValue, new WeakReference(button));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_virtualKey.Add(viewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
Insert(s_virtualKey[viewId], newValue, new WeakReference(button));
}
}
}
private static void OnVirtualKeyControlChordPropertyChanged(DependencyObject target, MyVirtualKey oldValue, MyVirtualKey newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
Control control = (target as ButtonBase);
if (control == null)
{
// Handling Ctrl+E shortcut for Date Calc, target would be NavigationView^ in that case
control = (target as MUXC.NavigationView);
}
int viewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (s_VirtualKeyControlChordsForButtons.TryGetValue(viewId, out var iterViewMap))
{
Insert(iterViewMap, newValue, new WeakReference(control));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyControlChordsForButtons.Add(viewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
Insert(s_VirtualKeyControlChordsForButtons[viewId], newValue, new WeakReference(control));
}
}
}
private static void OnVirtualKeyShiftChordPropertyChanged(DependencyObject target, MyVirtualKey oldValue, MyVirtualKey newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
var button = (target as ButtonBase);
int viewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (s_VirtualKeyShiftChordsForButtons.TryGetValue(viewId, out var iterViewMap))
{
Insert(iterViewMap, newValue, new WeakReference(button));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyShiftChordsForButtons.Add(viewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
Insert(s_VirtualKeyShiftChordsForButtons[viewId], newValue, new WeakReference(button));
}
}
}
private static void OnVirtualKeyAltChordPropertyChanged(DependencyObject target, MyVirtualKey oldValue, MyVirtualKey newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
MUXC.NavigationView navView = (target as MUXC.NavigationView);
int viewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (s_VirtualKeyAltChordsForButtons.TryGetValue(viewId, out var iterViewMap))
{
Insert(iterViewMap, newValue, new WeakReference(navView));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyAltChordsForButtons.Add(viewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
Insert(s_VirtualKeyAltChordsForButtons[viewId], newValue, new WeakReference(navView));
}
}
}
private static void OnVirtualKeyControlShiftChordPropertyChanged(DependencyObject target, MyVirtualKey oldValue, MyVirtualKey newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
var button = (target as ButtonBase);
int viewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (s_VirtualKeyControlShiftChordsForButtons.TryGetValue(viewId, out var iterViewMap))
{
Insert(iterViewMap, newValue, new WeakReference(button));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyControlShiftChordsForButtons.Add(viewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
Insert(s_VirtualKeyControlShiftChordsForButtons[viewId], newValue, new WeakReference(button));
}
}
}
// In the three event handlers below we will not mark the event as handled
// because this is a supplemental operation and we don't want to interfere with
// the normal keyboard handling.
private static void OnCharacterReceivedHandler(CoreWindow sender, CharacterReceivedEventArgs args)
{
int viewId = Utilities.GetWindowId();
bool hit = s_fHonorShortcuts.TryGetValue(viewId, out var currentHonorShortcuts);
if (!hit || currentHonorShortcuts)
{
char character = ((char)args.KeyCode);
var buttons = EqualRange(s_characterForButtons[viewId], character);
KeyboardShortcutManagerLocals.RunFirstEnabledButtonCommand(buttons);
KeyboardShortcutManagerLocals.LightUpButtons(buttons);
}
}
private static void OnKeyDownHandler(CoreWindow sender, KeyEventArgs args)
{
if (args.Handled)
{
return;
}
var key = args.VirtualKey;
int viewId = Utilities.GetWindowId();
bool isControlKeyPressed = (Window.Current.CoreWindow.GetKeyState(Windows.System.VirtualKey.Control) & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
bool isShiftKeyPressed = (Window.Current.CoreWindow.GetKeyState(Windows.System.VirtualKey.Shift) & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
bool isAltKeyPressed = (Window.Current.CoreWindow.GetKeyState(Windows.System.VirtualKey.Menu) & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
// Handle Ctrl + E for DateCalculator
if ((key == Windows.System.VirtualKey.E) && isControlKeyPressed && !isShiftKeyPressed && !isAltKeyPressed)
{
var lookupMap = GetCurrentKeyDictionary(isControlKeyPressed, isShiftKeyPressed, false);
if (lookupMap == null)
{
return;
}
var buttons = EqualRange(lookupMap, (MyVirtualKey)key);
var navView = buttons.ElementAt(0).Target as MUXC.NavigationView; // CSHARP_MIGRATION: TODO: double check if button[0] exists
var appViewModel = (navView.DataContext as ApplicationViewModel);
appViewModel.Mode = ViewMode.Date;
var categoryName = AppResourceProvider.GetInstance().GetResourceString("DateCalculationModeText");
appViewModel.CategoryName = categoryName;
var menuItems = ((IObservableVector<object>)navView.MenuItemsSource);
var flatIndex = NavCategory.GetFlatIndex(ViewMode.Date);
navView.SelectedItem = menuItems[flatIndex];
return;
}
if (s_ignoreNextEscape.TryGetValue(viewId, out var currentIgnoreNextEscape))
{
if (currentIgnoreNextEscape && key == Windows.System.VirtualKey.Escape)
{
if (s_keepIgnoringEscape.TryGetValue(viewId, out var currentKeepIgnoringEscape))
{
if (!currentKeepIgnoringEscape)
{
HonorEscape();
}
return;
}
}
}
if (s_fHonorShortcuts.TryGetValue(viewId, out var currentHonorShortcuts))
{
if (currentHonorShortcuts)
{
var myVirtualKey = key;
var lookupMap = GetCurrentKeyDictionary(isControlKeyPressed, isShiftKeyPressed, isAltKeyPressed);
if (lookupMap == null)
{
return;
}
var buttons = EqualRange(lookupMap, (MyVirtualKey)myVirtualKey);
if (buttons.Count() <= 0) // CSHARP_MIGRATION: TODO: double check if this is equivalent to `if (buttons.first == buttons.second)`
{
return;
}
KeyboardShortcutManagerLocals.RunFirstEnabledButtonCommand(buttons);
// Ctrl+C and Ctrl+V shifts focus to some button because of which enter doesn't work after copy/paste. So don't shift focus if Ctrl+C or Ctrl+V
// is pressed. When drop down is open, pressing escape shifts focus to clear button. So dont's shift focus if drop down is open. Ctrl+Insert is
// equivalent to Ctrl+C and Shift+Insert is equivalent to Ctrl+V
//var currentIsDropDownOpen = s_IsDropDownOpen.find(viewId);
if (!s_IsDropDownOpen.TryGetValue(viewId, out var currentIsDropDownOpen) || !currentIsDropDownOpen)
{
// Do not Light Up Buttons when Ctrl+C, Ctrl+V, Ctrl+Insert or Shift+Insert is pressed
if (!(isControlKeyPressed && (key == Windows.System.VirtualKey.C || key == Windows.System.VirtualKey.V || key == Windows.System.VirtualKey.Insert))
& !(isShiftKeyPressed && (key == Windows.System.VirtualKey.Insert)))
{
KeyboardShortcutManagerLocals.LightUpButtons(buttons);
}
}
}
}
}
private static void OnAcceleratorKeyActivated(CoreDispatcher dispatcher, AcceleratorKeyEventArgs args)
{
if (args.KeyStatus.IsKeyReleased)
{
var key = args.VirtualKey;
bool altPressed = args.KeyStatus.IsMenuKeyDown;
// If the Alt/Menu key is not pressed then we don't care about the key anymore
if (!altPressed)
{
return;
}
bool controlKeyPressed = (Window.Current.CoreWindow.GetKeyState(Windows.System.VirtualKey.Control) & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
// Ctrl is pressed in addition to alt, this means Alt Gr is intended. do not navigate.
if (controlKeyPressed)
{
return;
}
bool shiftKeyPressed = (Window.Current.CoreWindow.GetKeyState(Windows.System.VirtualKey.Shift) & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
var lookupMap = GetCurrentKeyDictionary(controlKeyPressed, shiftKeyPressed, altPressed);
if (lookupMap != null)
{
var listItems = EqualRange(lookupMap, (MyVirtualKey)key);
foreach (var itemRef in listItems)
{
var item = itemRef.Target as MUXC.NavigationView;
if (item != null)
{
var navView = item as MUXC.NavigationView; // CSHARP_MIGRATION: TODO: check if this line is still needed
var menuItems = ((IObservableVector<object>)navView.MenuItemsSource);
if (menuItems != null)
{
var vm = (navView.DataContext as ApplicationViewModel);
if (null != vm)
{
ViewMode toMode = NavCategory.GetViewModeForVirtualKey(((MyVirtualKey)key));
var nvi = (menuItems[NavCategory.GetFlatIndex(toMode)] as MUXC.NavigationViewItem);
if (nvi != null && nvi.IsEnabled && NavCategory.IsValidViewMode(toMode))
{
vm.Mode = toMode;
navView.SelectedItem = nvi;
}
}
}
break;
}
}
}
}
}
// CSHARP_MIGRATION: TODO: reinterpreted SortedDictionary<MyVirtualKey, List<WeakReference>> to SortedDictionary<char, List<WeakReference>>
// double check this is equivalent before and after migration
private static SortedDictionary<MyVirtualKey, List<WeakReference>> GetCurrentKeyDictionary(bool controlKeyPressed, bool shiftKeyPressed, bool altPressed)
{
int viewId = Utilities.GetWindowId();
if (controlKeyPressed)
{
if (altPressed)
{
return null;
}
else
{
if (shiftKeyPressed)
{
return s_VirtualKeyControlShiftChordsForButtons[viewId];
}
else
{
return s_VirtualKeyControlChordsForButtons[viewId];
}
}
}
else
{
if (altPressed)
{
if (!shiftKeyPressed)
{
return s_VirtualKeyAltChordsForButtons[viewId];
}
else
{
return null;
}
}
else
{
if (shiftKeyPressed)
{
return s_VirtualKeyShiftChordsForButtons[viewId];
}
else
{
return s_virtualKey[viewId];
}
}
}
}
// CSHARP_MIGRATION: TODO: double check below design
// EqualRange is a helper function to pick a range from std::multimap.
private static IEnumerable<TValue> EqualRange<TKey, TValue>(SortedDictionary<TKey, List<TValue>> source, TKey key)
{
Debug.Assert(source != null);
if (source.TryGetValue(key, out List<TValue> items))
{
return items;
}
else
{
return Enumerable.Empty<TValue>();
}
}
// CSHARP_MIGRATION: TODO: double check below design
// Insert is a helper function to insert a pair into std::multimap.
private static void Insert<Tkey, TValue>(SortedDictionary<Tkey, List<TValue>> dest, Tkey key, TValue value)
{
if (dest.TryGetValue(key, out List<TValue> items))
{
items.Add(value);
}
else
{
items = new List<TValue> { value };
dest.Add(key, items);
}
}
private static SortedDictionary<int, SortedDictionary<char, List<WeakReference>>> s_characterForButtons = new SortedDictionary<int, SortedDictionary<char, List<WeakReference>>>();
private static SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>> s_virtualKey = new SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>>();
private static SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>> s_VirtualKeyControlChordsForButtons = new SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>>();
private static SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>> s_VirtualKeyShiftChordsForButtons = new SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>>();
private static SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>> s_VirtualKeyAltChordsForButtons = new SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>>();
private static SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>> s_VirtualKeyControlShiftChordsForButtons = new SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>>();
private static SortedDictionary<int, bool> s_IsDropDownOpen = new SortedDictionary<int, bool>();
private static SortedDictionary<int, bool> s_ignoreNextEscape = new SortedDictionary<int, bool>();
private static SortedDictionary<int, bool> s_keepIgnoringEscape = new SortedDictionary<int, bool>();
private static SortedDictionary<int, bool> s_fHonorShortcuts = new SortedDictionary<int, bool>();
private static SortedDictionary<int, bool> s_fDisableShortcuts = new SortedDictionary<int, bool>();
//private static Concurrency.reader_writer_lock s_keyboardShortcutMapLock;
private static readonly object s_keyboardShortcutMapLockMutex = new object();
}
}
}

View file

@ -0,0 +1,65 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
namespace CalculatorApp
{
namespace Common
{
public sealed class ValidSelectedItemConverter : Windows.UI.Xaml.Data.IValueConverter
{
public ValidSelectedItemConverter()
{ }
public object Convert(object value, Type targetType, object parameter, string language)
{
// Pass through as we don't want to change the value from the source
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (value != null)
{
return value;
}
// Stop the binding if the object is nullptr
return Windows.UI.Xaml.DependencyProperty.UnsetValue;
}
}
public sealed class ValidSelectedIndexConverter : Windows.UI.Xaml.Data.IValueConverter
{
public ValidSelectedIndexConverter()
{ }
public object Convert(object value, Type targetType, object parameter, string language)
{
// Pass through as we don't want to change the value from the source
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
// The value to be valid has to be a boxed int32 value
// extract that value and ensure it is valid, ie >= 0
if (value != null)
{
var box = value as Windows.Foundation.IPropertyValue;
if (box != null && box.Type == Windows.Foundation.PropertyType.Int32)
{
int index = box.GetInt32();
if (index >= 0)
{
return value;
}
}
}
// The value is not valid therefore stop the binding right here
return Windows.UI.Xaml.DependencyProperty.UnsetValue;
}
}
}
}

View file

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace CalculatorApp
{
static class ViewState
{
public static readonly string Snap = "Snap";
public static readonly string DockedView = "DockedView";
public static bool IsValidViewState(string viewState)
{
return (viewState == Snap) || (viewState == DockedView);
}
}
}

View file

@ -0,0 +1,626 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.Common;
using System;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Input;
namespace CalculatorApp
{
namespace Controls
{
public sealed class EquationTextBox : Windows.UI.Xaml.Controls.Control
{
public EquationTextBox()
{
}
public Windows.UI.Xaml.Media.SolidColorBrush EquationColor
{
get { return (Windows.UI.Xaml.Media.SolidColorBrush)GetValue(EquationColorProperty); }
set { SetValue(EquationColorProperty, value); }
}
// Using a DependencyProperty as the backing store for EquationColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EquationColorProperty =
DependencyProperty.Register(nameof(EquationColor), typeof(Windows.UI.Xaml.Media.SolidColorBrush), typeof(EquationTextBox), new PropertyMetadata(default(Windows.UI.Xaml.Media.SolidColorBrush)));
public Windows.UI.Xaml.Media.SolidColorBrush EquationButtonForegroundColor
{
get { return (Windows.UI.Xaml.Media.SolidColorBrush)GetValue(EquationButtonForegroundColorProperty); }
set { SetValue(EquationButtonForegroundColorProperty, value); }
}
// Using a DependencyProperty as the backing store for EquationButtonForegroundColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EquationButtonForegroundColorProperty =
DependencyProperty.Register(nameof(EquationButtonForegroundColor), typeof(Windows.UI.Xaml.Media.SolidColorBrush), typeof(EquationTextBox), new PropertyMetadata(default(Windows.UI.Xaml.Media.SolidColorBrush)));
public Windows.UI.Xaml.Controls.Flyout ColorChooserFlyout
{
get { return (Windows.UI.Xaml.Controls.Flyout)GetValue(ColorChooserFlyoutProperty); }
set { SetValue(ColorChooserFlyoutProperty, value); }
}
// Using a DependencyProperty as the backing store for ColorChooserFlyout. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ColorChooserFlyoutProperty =
DependencyProperty.Register(nameof(ColorChooserFlyout), typeof(Windows.UI.Xaml.Controls.Flyout), typeof(EquationTextBox), new PropertyMetadata(default(Windows.UI.Xaml.Controls.Flyout)));
public string EquationButtonContentIndex
{
get { return (string)GetValue(EquationButtonContentIndexProperty); }
set { SetValue(EquationButtonContentIndexProperty, value); }
}
// Using a DependencyProperty as the backing store for EquationButtonContentIndex. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EquationButtonContentIndexProperty =
DependencyProperty.Register(nameof(EquationButtonContentIndex), typeof(string), typeof(EquationTextBox), new PropertyMetadata(string.Empty, (sender, args) =>
{
var self = (EquationTextBox)sender;
self.OnEquationButtonContentIndexPropertyChanged((string)args.OldValue, (string)args.NewValue);
}));
public string MathEquation
{
get { return (string)GetValue(MathEquationProperty); }
set { SetValue(MathEquationProperty, value); }
}
// Using a DependencyProperty as the backing store for MathEquation. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MathEquationProperty =
DependencyProperty.Register(nameof(MathEquation), typeof(string), typeof(EquationTextBox), new PropertyMetadata(string.Empty));
public bool HasError
{
get { return (bool)GetValue(HasErrorProperty); }
set { SetValue(HasErrorProperty, value); }
}
// Using a DependencyProperty as the backing store for HasError. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HasErrorProperty =
DependencyProperty.Register(nameof(HasError), typeof(bool), typeof(EquationTextBox), new PropertyMetadata(default(bool), (sender, args) =>
{
var self = (EquationTextBox)sender;
self.OnHasErrorPropertyChanged((bool)args.OldValue, (bool)args.NewValue);
}));
public bool IsAddEquationMode
{
get { return (bool)GetValue(IsAddEquationModeProperty); }
set { SetValue(IsAddEquationModeProperty, value); }
}
// Using a DependencyProperty as the backing store for IsAddEquationMode. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsAddEquationModeProperty =
DependencyProperty.Register(nameof(IsAddEquationMode), typeof(bool), typeof(EquationTextBox), new PropertyMetadata(default(bool), (sender, args) =>
{
var self = (EquationTextBox)sender;
self.OnIsAddEquationModePropertyChanged((bool)args.OldValue, (bool)args.NewValue);
}));
public string ErrorText
{
get { return (string)GetValue(ErrorTextProperty); }
set { SetValue(ErrorTextProperty, value); }
}
// Using a DependencyProperty as the backing store for ErrorText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ErrorTextProperty =
DependencyProperty.Register(nameof(ErrorText), typeof(string), typeof(EquationTextBox), new PropertyMetadata(string.Empty));
public bool IsEquationLineDisabled
{
get { return (bool)GetValue(IsEquationLineDisabledProperty); }
set { SetValue(IsEquationLineDisabledProperty, value); }
}
// Using a DependencyProperty as the backing store for IsEquationLineDisabled. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsEquationLineDisabledProperty =
DependencyProperty.Register(nameof(IsEquationLineDisabled), typeof(bool), typeof(EquationTextBox), new PropertyMetadata(default(bool)));
public bool HasFocus
{
get => m_HasFocus;
}
private bool m_HasFocus;
public event Windows.UI.Xaml.RoutedEventHandler RemoveButtonClicked;
public event Windows.UI.Xaml.RoutedEventHandler KeyGraphFeaturesButtonClicked;
public event System.EventHandler<MathRichEditBoxSubmission> EquationSubmitted;
public event System.EventHandler<MathRichEditBoxFormatRequest> EquationFormatRequested;
public event Windows.UI.Xaml.RoutedEventHandler EquationButtonClicked;
public void SetEquationText(string equationText)
{
if (m_richEditBox != null)
{
m_richEditBox.MathText = equationText;
}
}
public void FocusTextBox()
{
if (m_richEditBox != null)
{
_ = FocusManager.TryFocusAsync(m_richEditBox, FocusState.Programmatic);
}
}
protected override void OnApplyTemplate()
{
m_equationButton = GetTemplateChild("EquationButton") as ToggleButton;
m_richEditBox = GetTemplateChild("MathRichEditBox") as MathRichEditBox;
m_deleteButton = GetTemplateChild("DeleteButton") as Button;
m_removeButton = GetTemplateChild("RemoveButton") as Button;
m_functionButton = GetTemplateChild("FunctionButton") as Button;
m_colorChooserButton = GetTemplateChild("ColorChooserButton") as ToggleButton;
m_richEditContextMenu = GetTemplateChild("MathRichEditContextMenu") as MenuFlyout;
m_kgfEquationMenuItem = GetTemplateChild("FunctionAnalysisMenuItem") as MenuFlyoutItem;
m_removeMenuItem = GetTemplateChild("RemoveFunctionMenuItem") as MenuFlyoutItem;
m_colorChooserMenuItem = GetTemplateChild("ChangeFunctionStyleMenuItem") as MenuFlyoutItem;
m_cutMenuItem = GetTemplateChild("CutMenuItem") as MenuFlyoutItem;
m_copyMenuItem = GetTemplateChild("CopyMenuItem") as MenuFlyoutItem;
m_pasteMenuItem = GetTemplateChild("PasteMenuItem") as MenuFlyoutItem;
m_undoMenuItem = GetTemplateChild("UndoMenuItem") as MenuFlyoutItem;
m_selectAllMenuItem = GetTemplateChild("SelectAllMenuItem") as MenuFlyoutItem;
var resProvider = AppResourceProvider.GetInstance();
if (m_richEditBox != null)
{
m_richEditBox.GotFocus += OnRichEditBoxGotFocus;
m_richEditBox.LostFocus += OnRichEditBoxLostFocus;
m_richEditBox.TextChanged += OnRichEditTextChanged;
m_richEditBox.SelectionFlyout = null;
m_richEditBox.EquationSubmitted += OnEquationSubmitted;
m_richEditBox.FormatRequest += OnEquationFormatRequested;
}
if (m_equationButton != null)
{
m_equationButton.Click += OnEquationButtonClicked;
}
if (m_richEditContextMenu != null)
{
m_richEditContextMenu.Opened += OnRichEditMenuOpened;
}
if (m_deleteButton != null)
{
m_deleteButton.Click += OnDeleteButtonClicked;
}
if (m_removeButton != null)
{
m_removeButton.Click += OnRemoveButtonClicked;
}
if (m_removeMenuItem != null)
{
m_removeMenuItem.Text = resProvider.GetResourceString("removeMenuItem");
m_removeMenuItem.Click += OnRemoveButtonClicked;
}
if (m_colorChooserButton != null)
{
m_colorChooserButton.Click += OnColorChooserButtonClicked;
}
if (m_colorChooserMenuItem != null)
{
m_colorChooserMenuItem.Text = resProvider.GetResourceString("colorChooserMenuItem");
m_colorChooserMenuItem.Click += OnColorChooserButtonClicked;
}
if (m_functionButton != null)
{
m_functionButton.Click += OnFunctionButtonClicked;
m_functionButton.IsEnabled = false;
}
if (m_kgfEquationMenuItem != null)
{
m_kgfEquationMenuItem.Text = resProvider.GetResourceString("functionAnalysisMenuItem");
m_kgfEquationMenuItem.Click += OnFunctionMenuButtonClicked;
}
if (ColorChooserFlyout != null)
{
ColorChooserFlyout.Opened += OnColorFlyoutOpened;
ColorChooserFlyout.Closed += OnColorFlyoutClosed;
}
if (m_cutMenuItem != null)
{
m_cutMenuItem.Click += OnCutClicked;
}
if (m_copyMenuItem != null)
{
m_copyMenuItem.Click += OnCopyClicked;
}
if (m_pasteMenuItem != null)
{
m_pasteMenuItem.Click += OnPasteClicked;
}
if (m_undoMenuItem != null)
{
m_undoMenuItem.Click += OnUndoClicked;
}
if (m_selectAllMenuItem != null)
{
m_selectAllMenuItem.Click += OnSelectAllClicked;
}
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
protected override void OnPointerEntered(PointerRoutedEventArgs e)
{
m_isPointerOver = true;
UpdateCommonVisualState();
}
protected override void OnPointerExited(PointerRoutedEventArgs e)
{
m_isPointerOver = false;
UpdateCommonVisualState();
}
protected override void OnPointerCanceled(PointerRoutedEventArgs e)
{
m_isPointerOver = false;
UpdateCommonVisualState();
}
protected override void OnPointerCaptureLost(PointerRoutedEventArgs e)
{
m_isPointerOver = false;
UpdateCommonVisualState();
}
private void OnIsAddEquationModePropertyChanged(bool oldValue, bool newValue)
{
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
private void UpdateCommonVisualState()
{
string state = null;
bool richEditHasContent = RichEditHasContent();
if (m_HasFocus && HasError)
{
state = "FocusedError";
}
else if (IsAddEquationMode && m_HasFocus && !richEditHasContent)
{
state = "AddEquationFocused";
}
else if (m_HasFocus)
{
state = "Focused";
}
else if (IsAddEquationMode && m_isPointerOver && !richEditHasContent)
{
state = "AddEquation";
}
else if (HasError && (m_isPointerOver || m_isColorChooserFlyoutOpen))
{
state = "PointerOverError";
}
else if (m_isPointerOver || m_isColorChooserFlyoutOpen)
{
state = "PointerOver";
}
else if (HasError)
{
state = "Error";
}
else if (IsAddEquationMode)
{
state = "AddEquation";
}
else
{
state = "Normal";
}
VisualStateManager.GoToState(this, state, false);
}
private void UpdateButtonsVisualState()
{
string state;
if (m_HasFocus && RichEditHasContent())
{
state = "ButtonVisible";
}
else if (IsAddEquationMode)
{
state = "ButtonHideRemove";
}
else
{
state = "ButtonCollapsed";
}
VisualStateManager.GoToState(this, state, true);
}
private bool RichEditHasContent()
{
string text = null;
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.GetText(Windows.UI.Text.TextGetOptions.NoHidden, out text);
}
return !string.IsNullOrEmpty(text);
}
private void OnRichEditBoxGotFocus(object sender, RoutedEventArgs e)
{
m_HasFocus = true;
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
private void OnRichEditBoxLostFocus(object sender, RoutedEventArgs e)
{
if (!m_richEditBox.ContextFlyout.IsOpen)
{
m_HasFocus = false;
}
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
private void OnRichEditTextChanged(object sender, RoutedEventArgs e)
{
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
private void OnDeleteButtonClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.SetText(TextSetOptions.None, "");
if (m_functionButton != null)
{
m_functionButton.IsEnabled = false;
}
}
}
private void OnEquationButtonClicked(object sender, RoutedEventArgs e)
{
EquationButtonClicked(this, new RoutedEventArgs());
SetEquationButtonTooltipAndAutomationName();
}
private void OnRemoveButtonClicked(object sender, RoutedEventArgs e)
{
if (IsAddEquationMode)
{
// Don't remove the last equation
return;
}
if (m_richEditBox != null)
{
m_richEditBox.MathText = "";
}
RemoveButtonClicked(this, new RoutedEventArgs());
if (m_functionButton != null)
{
m_functionButton.IsEnabled = false;
}
if (m_equationButton != null)
{
IsEquationLineDisabled = false;
}
TraceLogger.GetInstance().LogGraphButtonClicked(GraphButton.RemoveFunction, GraphButtonValue.None);
VisualStateManager.GoToState(this, "Normal", true);
}
private void OnColorChooserButtonClicked(object sender, RoutedEventArgs e)
{
if (ColorChooserFlyout != null && m_richEditBox != null)
{
ColorChooserFlyout.ShowAt(m_richEditBox);
TraceLogger.GetInstance().LogGraphButtonClicked(GraphButton.StylePicker, GraphButtonValue.None);
}
}
private void OnFunctionButtonClicked(object sender, RoutedEventArgs e)
{
KeyGraphFeaturesButtonClicked(this, new RoutedEventArgs());
}
private void OnFunctionMenuButtonClicked(object sender, RoutedEventArgs e)
{
// Submit the equation before trying to analyze it if invoked from context menu
if (m_richEditBox != null)
{
m_richEditBox.SubmitEquation(EquationSubmissionSource.FOCUS_LOST);
}
KeyGraphFeaturesButtonClicked(this, new RoutedEventArgs());
}
private void OnRichEditMenuOpened(object sender, object args)
{
if (m_removeMenuItem != null)
{
m_removeMenuItem.IsEnabled = !IsAddEquationMode;
}
if (m_kgfEquationMenuItem != null)
{
m_kgfEquationMenuItem.IsEnabled = m_HasFocus && !HasError && RichEditHasContent();
}
if (m_colorChooserMenuItem != null)
{
m_colorChooserMenuItem.IsEnabled = !HasError && !IsAddEquationMode;
}
if (m_richEditBox != null && m_cutMenuItem != null)
{
m_cutMenuItem.IsEnabled = m_richEditBox.TextDocument.CanCopy();
}
if (m_richEditBox != null && m_copyMenuItem != null)
{
m_copyMenuItem.IsEnabled = m_richEditBox.TextDocument.CanCopy();
}
if (m_richEditBox != null && m_pasteMenuItem != null)
{
m_pasteMenuItem.IsEnabled = m_richEditBox.TextDocument.CanPaste();
}
if (m_richEditBox != null && m_undoMenuItem != null)
{
m_undoMenuItem.IsEnabled = m_richEditBox.TextDocument.CanUndo();
}
}
private void OnCutClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.Selection.Cut();
}
}
private void OnCopyClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.Selection.Copy();
}
}
private void OnPasteClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.Selection.Paste(0);
}
}
private void OnUndoClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.Undo();
}
}
private void OnSelectAllClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.Selection.SetRange(0, m_richEditBox.TextDocument.Selection.EndPosition);
}
}
private void OnColorFlyoutOpened(object sender, object e)
{
m_isColorChooserFlyoutOpen = true;
UpdateCommonVisualState();
}
private void OnColorFlyoutClosed(object sender, object e)
{
m_colorChooserButton.IsChecked = false;
m_isColorChooserFlyoutOpen = false;
UpdateCommonVisualState();
}
private void OnHasErrorPropertyChanged(bool oldValue, bool newValue)
{
UpdateCommonVisualState();
}
private void OnEquationButtonContentIndexPropertyChanged(string oldValue, string newValue)
{
SetEquationButtonTooltipAndAutomationName();
}
private void SetEquationButtonTooltipAndAutomationName()
{
var toolTip = new ToolTip();
var resProvider = AppResourceProvider.GetInstance();
var equationButtonMessage = LocalizationStringUtil.GetLocalizedString(
IsEquationLineDisabled ? resProvider.GetResourceString("showEquationButtonAutomationName")
: resProvider.GetResourceString("hideEquationButtonAutomationName"),
EquationButtonContentIndex);
var equationButtonTooltip = LocalizationStringUtil.GetLocalizedString(
IsEquationLineDisabled ? resProvider.GetResourceString("showEquationButtonToolTip") : resProvider.GetResourceString("hideEquationButtonToolTip"));
toolTip.Content = equationButtonTooltip;
ToolTipService.SetToolTip(m_equationButton, toolTip);
AutomationProperties.SetName(m_equationButton, equationButtonMessage);
}
private CalculatorApp.Controls.MathRichEditBox m_richEditBox;
private Windows.UI.Xaml.Controls.Primitives.ToggleButton m_equationButton;
private Windows.UI.Xaml.Controls.Button m_deleteButton;
private Windows.UI.Xaml.Controls.Button m_removeButton;
private Windows.UI.Xaml.Controls.Button m_functionButton;
private Windows.UI.Xaml.Controls.Primitives.ToggleButton m_colorChooserButton;
private Windows.UI.Xaml.Controls.MenuFlyout m_richEditContextMenu;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_cutMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_copyMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_pasteMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_undoMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_selectAllMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_kgfEquationMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_removeMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_colorChooserMenuItem;
private bool m_isPointerOver;
private bool m_isColorChooserFlyoutOpen;
private void OnEquationSubmitted(object sender, MathRichEditBoxSubmission args)
{
if (args.HasTextChanged)
{
if (m_functionButton != null && m_richEditBox.MathText != "")
{
m_functionButton.IsEnabled = true;
}
}
EquationSubmitted(this, args);
}
private void OnEquationFormatRequested(object sender, MathRichEditBoxFormatRequest args)
{
EquationFormatRequested(this, args);
}
}
}
}

View file

@ -0,0 +1,92 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
namespace CalculatorApp
{
namespace Controls
{
public sealed class FlipButtons : Windows.UI.Xaml.Controls.Primitives.ToggleButton
{
public NumbersAndOperatorsEnum ButtonId
{
get { return (NumbersAndOperatorsEnum)GetValue(ButtonIdProperty); }
set { SetValue(ButtonIdProperty, value); }
}
// Using a DependencyProperty as the backing store for ButtonId. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ButtonIdProperty =
DependencyProperty.Register(nameof(ButtonId), typeof(NumbersAndOperatorsEnum), typeof(FlipButtons), new PropertyMetadata(default(NumbersAndOperatorsEnum)));
public Windows.UI.Xaml.Media.Brush HoverBackground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(HoverBackgroundProperty); }
set { SetValue(HoverBackgroundProperty, value); }
}
// Using a DependencyProperty as the backing store for HoverBackground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HoverBackgroundProperty =
DependencyProperty.Register(nameof(HoverBackground), typeof(Windows.UI.Xaml.Media.Brush), typeof(FlipButtons), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
public Windows.UI.Xaml.Media.Brush HoverForeground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(HoverForegroundProperty); }
set { SetValue(HoverForegroundProperty, value); }
}
// Using a DependencyProperty as the backing store for HoverForeground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HoverForegroundProperty =
DependencyProperty.Register(nameof(HoverForeground), typeof(Windows.UI.Xaml.Media.Brush), typeof(FlipButtons), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
public Windows.UI.Xaml.Media.Brush PressBackground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(PressBackgroundProperty); }
set { SetValue(PressBackgroundProperty, value); }
}
// Using a DependencyProperty as the backing store for PressBackground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PressBackgroundProperty =
DependencyProperty.Register(nameof(PressBackground), typeof(Windows.UI.Xaml.Media.Brush), typeof(FlipButtons), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
public Windows.UI.Xaml.Media.Brush PressForeground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(PressForegroundProperty); }
set { SetValue(PressForegroundProperty, value); }
}
// Using a DependencyProperty as the backing store for PressForeground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PressForegroundProperty =
DependencyProperty.Register(nameof(PressForeground), typeof(Windows.UI.Xaml.Media.Brush), typeof(FlipButtons), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
// Ignore the Enter key
if (e.Key == VirtualKey.Enter)
{
return;
}
base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyRoutedEventArgs e)
{
// Ignore the Enter key
if (e.Key == VirtualKey.Enter)
{
return;
}
base.OnKeyUp(e);
}
private void OnButtonIdPropertyChanged(NumbersAndOperatorsEnum oldValue, NumbersAndOperatorsEnum newValue)
{
CommandParameter = newValue;
}
}
}
}

View file

@ -0,0 +1,83 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// HorizontalNoOverflowStackPanel.h
// Declaration of the HorizontalNoOverflowStackPanel class
//
using System;
using Windows.Foundation;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
namespace CalculatorApp
{
namespace Controls
{
public class HorizontalNoOverflowStackPanel : Windows.UI.Xaml.Controls.Panel
{
// Prioritize the last item over all other items (except the first one)
internal HorizontalNoOverflowStackPanel()
{ }
protected override Size MeasureOverride(Size availableSize)
{
float maxHeight = 0;
float width = 0;
foreach (var child in Children)
{
child.Measure(new Size(float.PositiveInfinity, float.PositiveInfinity));
maxHeight = (float)Math.Max(maxHeight, child.DesiredSize.Height);
width += (float)child.DesiredSize.Width;
}
return new Size(Math.Min(width, availableSize.Width), Math.Min(availableSize.Height, maxHeight));
}
protected override Size ArrangeOverride(Size finalSize)
{
if (Children.Count == 0)
{
return finalSize;
}
float posX = 0;
var lastChild = Children[Children.Count - 1];
float lastChildWidth = 0;
if (Children.Count > 2 && ShouldPrioritizeLastItem())
{
lastChildWidth = (float)lastChild.DesiredSize.Width;
}
foreach (var item in Children)
{
var widthAvailable = finalSize.Width - posX;
if (item != lastChild)
{
widthAvailable -= lastChildWidth;
}
float itemWidth = (float)item.DesiredSize.Width;
if (widthAvailable > 0 && itemWidth <= widthAvailable)
{
// stack the items horizontally (left to right)
item.Arrange(new Rect(posX, 0, itemWidth, finalSize.Height));
AutomationProperties.SetAccessibilityView(item, AccessibilityView.Content);
posX += (float)item.RenderSize.Width;
}
else
{
// Not display the item
item.Arrange(new Rect(0, 0, 0, 0));
AutomationProperties.SetAccessibilityView(item, AccessibilityView.Raw);
}
}
return finalSize;
}
protected virtual bool ShouldPrioritizeLastItem()
{
return false;
}
}
}
}

View file

@ -0,0 +1,243 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Runtime.InteropServices;
using Windows.System;
using Windows.UI.Core;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
//using Microsoft.WRL;
namespace CalculatorApp
{
namespace Controls
{
namespace Windows_2004_Prerelease
{
public enum RichEditMathMode : int
{
NoMath,
MathOnly
}
[Guid("619c20f2-cb3b-4521-981f-2865b1b93f04")]
interface ITextDocument4
{
int SetMath(string value);
int GetMath(out string value);
int SetMathMode(RichEditMathMode mathMode);
}
}
public enum EquationSubmissionSource
{
FOCUS_LOST,
ENTER_KEY,
PROGRAMMATIC
}
public sealed class MathRichEditBoxSubmission
{
public bool HasTextChanged
{
get => m_HasTextChanged;
}
public EquationSubmissionSource Source
{
get => m_Source;
}
public MathRichEditBoxSubmission(bool hasTextChanged, EquationSubmissionSource source)
{
m_HasTextChanged = hasTextChanged;
m_Source = source;
}
private bool m_HasTextChanged;
private EquationSubmissionSource m_Source;
}
public sealed class MathRichEditBoxFormatRequest
{
public string OriginalText
{
get => m_OriginalText;
}
public string FormattedText
{
get => m_FormattedText;
set => m_FormattedText = value;
}
public MathRichEditBoxFormatRequest(string originalText)
{
m_OriginalText = originalText;
}
private string m_OriginalText;
private string m_FormattedText;
}
public sealed class MathRichEditBox : Windows.UI.Xaml.Controls.RichEditBox
{
public MathRichEditBox()
{
TextDocument.SetMathMode(RichEditMathMode.MathOnly);
LosingFocus += OnLosingFocus;
KeyUp += OnKeyUp;
}
public string MathText
{
get { return (string)GetValue(MathTextProperty); }
set { SetValue(MathTextProperty, value); }
}
// Using a DependencyProperty as the backing store for MathText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MathTextProperty =
DependencyProperty.Register(nameof(MathText), typeof(string), typeof(MathRichEditBox), new PropertyMetadata(string.Empty, (sender, args) =>
{
var self = (MathRichEditBox)sender;
self.OnMathTextPropertyChanged((string)args.OldValue, (string)args.NewValue);
}));
public event EventHandler<MathRichEditBoxFormatRequest> FormatRequest;
public event EventHandler<MathRichEditBoxSubmission> EquationSubmitted;
public void OnMathTextPropertyChanged(string oldValue, string newValue)
{
SetMathTextProperty(newValue);
// Get the new math text directly from the TextBox since the textbox may have changed its formatting
SetValue(MathTextProperty, GetMathTextProperty());
}
public void InsertText(string text, int cursorOffSet, int selectionLength)
{
// If the rich edit is empty, the math zone may not exist, and so selection (and thus the resulting text) will not be in a math zone.
// If the rich edit has content already, then the mathzone will already be created due to mathonly mode being set and the selection will exist inside the
// math zone. To handle this, we will force a math zone to be created in teh case of the text being empty and then replacing the text inside of the math
// zone with the newly inserted text.
if (GetMathTextProperty() == null)
{
SetMathTextProperty("<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mi>x</mi></math>");
TextDocument.Selection.StartPosition = 0;
TextDocument.Selection.EndPosition = 1;
}
// insert the text in place of selection
TextDocument.Selection.SetText(Windows.UI.Text.TextSetOptions.FormatRtf, text);
// Move the cursor to the next logical place for users to enter text.
TextDocument.Selection.StartPosition += cursorOffSet;
TextDocument.Selection.EndPosition = TextDocument.Selection.StartPosition + selectionLength;
}
public void SubmitEquation(EquationSubmissionSource source)
{
// Clear formatting since the graph control doesn't work with bold/underlines
var range = TextDocument.GetRange(0, TextDocument.Selection.EndPosition);
if (range != null)
{
range.CharacterFormat.Underline = UnderlineType.None;
}
var newVal = GetMathTextProperty();
if (MathText != newVal)
{
// Request the final formatting of the text
var formatRequest = new MathRichEditBoxFormatRequest(newVal);
FormatRequest(this, formatRequest);
if (!string.IsNullOrEmpty(formatRequest.FormattedText))
{
newVal = formatRequest.FormattedText;
}
SetValue(MathTextProperty, newVal);
EquationSubmitted(this, new MathRichEditBoxSubmission(true, source));
}
else
{
EquationSubmitted(this, new MathRichEditBoxSubmission(false, source));
}
}
public void BackSpace()
{
// if anything is selected, just delete the selection. Note: EndPosition can be before start position.
if (TextDocument.Selection.StartPosition != TextDocument.Selection.EndPosition)
{
TextDocument.Selection.SetText(Windows.UI.Text.TextSetOptions.None, "");
return;
}
// if we are at the start of the string, do nothing
if (TextDocument.Selection.StartPosition == 0)
{
return;
}
// Select the previous group.
TextDocument.Selection.EndPosition = TextDocument.Selection.StartPosition;
TextDocument.Selection.StartPosition -= 1;
// If the group contains anything complex, we want to give the user a chance to preview the deletion.
// If it's a single character, then just delete it. Otherwise do nothing until the user triggers backspace again.
var text = TextDocument.Selection.Text;
if (text.Length == 1)
{
TextDocument.Selection.SetText(Windows.UI.Text.TextSetOptions.None, "");
}
}
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
// suppress control + B to prevent bold input from being entered
if ((Window.Current.CoreWindow.GetKeyState(VirtualKey.Control) & CoreVirtualKeyStates.Down) != CoreVirtualKeyStates.Down ||
e.Key != VirtualKey.B)
{
base.OnKeyDown(e);
}
}
private string GetMathTextProperty()
{
TextDocument.GetMath(out string math);
return math;
}
private void SetMathTextProperty(string newValue)
{
bool readOnlyState = IsReadOnly;
IsReadOnly = false;
TextDocument.SetMath(newValue);
IsReadOnly = readOnlyState;
}
private void OnLosingFocus(UIElement sender, LosingFocusEventArgs args)
{
if (IsReadOnly || ContextFlyout.IsOpen)
{
return;
}
SubmitEquation(EquationSubmissionSource.FOCUS_LOST);
}
private void OnKeyUp(object sender, KeyRoutedEventArgs e)
{
if (!IsReadOnly && e.Key == VirtualKey.Enter)
{
SubmitEquation(EquationSubmissionSource.ENTER_KEY);
}
}
}
}
}

View file

@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.Common;
namespace CalculatorApp
{
namespace Controls
{
public sealed class RadixButton : Windows.UI.Xaml.Controls.RadioButton
{
public RadixButton()
{ }
internal string GetRawDisplayValue()
{
string radixContent = Content.ToString();
return LocalizationSettings.GetInstance().RemoveGroupSeparators(radixContent);
}
}
}
}

View file

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
namespace CalculatorApp
{
namespace Converters
{
/// <summary>
/// Value converter that translates true to false and vice versa.
/// </summary>
[Windows.Foundation.Metadata.WebHostHidden]
public sealed class BooleanNegationConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var boxedBool = value as bool?;
var boolValue = (boxedBool != null && boxedBool.Value);
return !boolValue;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
var boxedBool = (value as bool?);
var boolValue = (boxedBool != null && boxedBool.Value);
return !boolValue;
}
}
}
}

View file

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Windows.UI.Xaml;
namespace CalculatorApp
{
namespace Converters
{
/// <summary>
/// Value converter that translates true to <see cref="Visibility.Visible"/> and false
/// to <see cref="Visibility.Collapsed"/>.
/// </summary>
public sealed class BooleanToVisibilityConverter : Windows.UI.Xaml.Data.IValueConverter
{
public static Windows.UI.Xaml.Visibility Convert(bool visibility)
{
return visibility ? Windows.UI.Xaml.Visibility.Visible : Windows.UI.Xaml.Visibility.Collapsed;
}
public object Convert(object value, Type targetType, object parameter, string language)
{
var boxedBool = (value as bool?);
var boolValue = (boxedBool != null && boxedBool.Value);
return BooleanToVisibilityConverter.Convert(boolValue);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
var visibility = (value as Visibility?);
return (visibility != null && visibility.Value == Visibility.Visible);
}
}
/// <summary>
/// Value converter that translates false to <see cref="Visibility.Visible"/> and true
/// to <see cref="Visibility.Collapsed"/>.
/// </summary>
public sealed class BooleanToVisibilityNegationConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var boxedBool = (value as bool?);
var boolValue = (boxedBool != null && boxedBool.Value);
return BooleanToVisibilityConverter.Convert(!boolValue);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
var visibility = (value as Visibility?);
return (visibility != null && visibility.Value != Visibility.Visible);
}
}
}
}

View file

@ -0,0 +1,83 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.Common;
using System;
using Windows.UI.Xaml;
namespace CalculatorApp
{
namespace Converters
{
[Windows.UI.Xaml.Data.Bindable]
public sealed class ExpressionItemTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item)
{
DisplayExpressionToken token = (item as DisplayExpressionToken);
if (token != null)
{
Common.TokenType type = token.Type;
switch (type)
{
case TokenType.Operator:
return m_operatorTemplate;
case TokenType.Operand:
return m_operandTemplate;
case TokenType.Separator:
return m_separatorTemplate;
default:
throw new Exception("Invalid token type");
}
}
return m_separatorTemplate;
}
public Windows.UI.Xaml.DataTemplate OperatorTemplate
{
get
{
return m_operatorTemplate;
}
set
{
m_operatorTemplate = value;
}
}
public Windows.UI.Xaml.DataTemplate OperandTemplate
{
get
{
return m_operandTemplate;
}
set
{
m_operandTemplate = value;
}
}
public Windows.UI.Xaml.DataTemplate SeparatorTemplate
{
get
{
return m_separatorTemplate;
}
set
{
m_separatorTemplate = value;
}
}
private Windows.UI.Xaml.DataTemplate m_operatorTemplate;
private Windows.UI.Xaml.DataTemplate m_operandTemplate;
private Windows.UI.Xaml.DataTemplate m_separatorTemplate;
}
}
}

View file

@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
namespace CalculatorApp
{
namespace Converters
{
[Windows.Foundation.Metadata.WebHostHidden]
public sealed class ItemSizeToVisibilityConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var items = (value as int?);
var boolValue = (items != null && (items.Value == 0));
return BooleanToVisibilityConverter.Convert(boolValue);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
public sealed class ItemSizeToVisibilityNegationConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var items = (value as int?);
var boolValue = (items != null && (items.Value > 0));
return BooleanToVisibilityConverter.Convert(boolValue);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
}

View file

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.Common;
using System;
namespace CalculatorApp
{
namespace Converters
{
/// <summary>
/// Value converter that translates true to false and vice versa.
/// </summary>
[Windows.Foundation.Metadata.WebHostHidden]
public sealed class RadixToStringConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var boxedInt = (value as int?);
string convertedValue = null;
var resourceLoader = AppResourceProvider.GetInstance();
switch (boxedInt.Value)
{
case (int)RadixType.Binary:
{
convertedValue = resourceLoader.GetResourceString("Bin");
break;
}
case (int)RadixType.Octal:
{
convertedValue = resourceLoader.GetResourceString("Oct");
break;
}
case (int)RadixType.Decimal:
{
convertedValue = resourceLoader.GetResourceString("Dec");
break;
}
case (int)RadixType.Hex:
{
convertedValue = resourceLoader.GetResourceString("Hex");
break;
}
default:
break;
}
return convertedValue;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
}

View file

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Windows.UI.Xaml;
namespace CalculatorApp
{
namespace Common
{
/// <summary>
/// Value converter that translates Visible to Collapsed and vice versa
/// </summary>
[Windows.Foundation.Metadata.WebHostHidden]
public sealed class VisibilityNegationConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var boxedVisibility = (value as Visibility?);
if (boxedVisibility != null && boxedVisibility.Value == Visibility.Collapsed)
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return Convert(value, targetType, parameter, language);
}
}
}
}

View file

@ -0,0 +1,35 @@
using System;
namespace CalculatorApp.Common
{
internal class DelegateCommand<TTarget> : System.Windows.Input.ICommand
{
public delegate void CommandHandlerFunc(object obj);
public DelegateCommand(TTarget target, CommandHandlerFunc func)
{
m_weakTarget = new WeakReference(target);
m_function = func;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
object target = m_weakTarget.Target;
if (target != null && target is TTarget)
{
m_function(parameter);
}
}
private CommandHandlerFunc m_function;
private WeakReference m_weakTarget;
}
}

View file

@ -0,0 +1,133 @@
<UserControl x:Class="CalculatorApp.EquationStylePanelControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:CalculatorApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel>
<TextBlock x:Uid="LineOptionsHeading"
Margin="8,0,0,16"
FontSize="20"
FontWeight="Medium"
AutomationProperties.HeadingLevel="Level2"/>
<GridView x:Name="ColorChooser"
ItemsSource="{x:Bind AvailableColors}"
Loaded="ColorChooserLoaded"
SelectionChanged="SelectionChanged"
SingleSelectionFollowsFocus="False">
<GridView.Resources>
<Style TargetType="GridViewItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="MinHeight" Value="52"/>
<Setter Property="MinWidth" Value="52"/>
<Setter Property="Height" Value="52"/>
<Setter Property="Width" Value="52"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewItem">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="ItemContent.Margin" Value="-2,-2,-2,-2"/>
<Setter Target="ItemBorder.Margin" Value="2,2,2,2"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="ItemContent.Margin" Value="-2,-2,-2,-2"/>
<Setter Target="ItemBorder.Stroke" Value="{ThemeResource InkToolbarFlyoutItemBorderPressedThemeBrush}"/>
<Setter Target="ItemBorder.Margin" Value="2,2,2,2"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Target="ItemContent.Margin" Value="2,2,2,2"/>
<Setter Target="ItemBorder.Stroke" Value="{ThemeResource InkToolbarFlyoutItemBorderSelectedThemeBrush}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused"/>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse x:Name="ItemBorder"
Margin="6,6,6,6"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
Stroke="Transparent"
StrokeThickness="2"
UseLayoutRounding="false"/>
<ContentPresenter x:Name="ItemContent" UseLayoutRounding="false"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GridView.Resources>
<GridView.Header>
<TextBlock x:Uid="LineColorText" Margin="8,0,8,8"/>
</GridView.Header>
<GridView.ItemTemplate>
<DataTemplate x:DataType="Brush">
<Ellipse Margin="8,8,8,8"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="{x:Bind}"
StrokeThickness="0"
AutomationProperties.Name="{x:Bind local:EquationStylePanelControl.GetColorAutomationName((Brush))}"
ToolTipService.ToolTip="{x:Bind local:EquationStylePanelControl.GetColorAutomationName((Brush))}"
UseLayoutRounding="false"/>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid MaximumRowsOrColumns="7" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
<ComboBox x:Name="StyleChooserBox"
MinWidth="200"
Margin="8,0"
Foreground="{ThemeResource AppControlPageTextBaseHighColorBrush}"
Loaded="StyleChooserBox_Loaded"
SelectedItem="{x:Bind SelectedStyle}"
SelectionChanged="StyleChooserBox_SelectionChanged"
Visibility="Visible"
IsEnabled="{x:Bind EnableLineStylePicker, Mode=OneWay}">
<ComboBox.Header>
<TextBlock x:Uid="StyleChooserBoxHeading" Margin="0,0,8,8"/>
</ComboBox.Header>
<ComboBox.ItemTemplate>
<!-- Set x:DataType to be Platform::Object so that we can pass it to the x:Bind function directly since we cannot pass an enum in c++/cx -->
<DataTemplate x:DataType="x:Object">
<Grid x:Name="LineGrid"
Height="20"
MaxWidth="200"
AutomationProperties.Name="{x:Bind local:EquationStylePanelControl.GetLineAutomationName((x:Object))}">
<Line x:Name="LineItem"
VerticalAlignment="Center"
Stroke="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"
StrokeThickness="2.5"
StrokeDashArray="{x:Bind local:EquationStylePanelControl.GetLinePattern((x:Object))}"
X1="0"
X2="200"
Y1="4"
Y2="4"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</UserControl>

View file

@ -0,0 +1,320 @@
using GraphControl;
using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace CalculatorApp
{
public sealed partial class EquationStylePanelControl : UserControl
{
public EquationStylePanelControl()
{
InitializeComponent();
}
public Windows.UI.Color SelectedColor
{
get { return (Windows.UI.Color)GetValue(SelectedColorProperty); }
set { SetValue(SelectedColorProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedColorProperty =
DependencyProperty.Register(nameof(SelectedColor), typeof(Windows.UI.Color), typeof(EquationStylePanelControl), new PropertyMetadata(Windows.UI.Colors.Black, (sender, args) =>
{
var self = (EquationStylePanelControl)sender;
self.OnSelectedColorPropertyChanged((Windows.UI.Color)args.OldValue, (Windows.UI.Color)args.NewValue);
}));
public GraphControl.EquationLineStyle SelectedStyle
{
get { return (GraphControl.EquationLineStyle)GetValue(SelectedStyleProperty); }
set { SetValue(SelectedStyleProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedStyle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedStyleProperty =
DependencyProperty.Register(nameof(SelectedStyle), typeof(GraphControl.EquationLineStyle), typeof(EquationStylePanelControl), new PropertyMetadata(GraphControl.EquationLineStyle.Solid, (sender, args) =>
{
var self = (EquationStylePanelControl)sender;
self.OnSelectedStylePropertyChanged((GraphControl.EquationLineStyle)args.OldValue, (GraphControl.EquationLineStyle)args.NewValue);
}));
public int SelectedColorIndex
{
get { return (int)GetValue(SelectedColorIndexProperty); }
set { SetValue(SelectedColorIndexProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedColorIndex. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedColorIndexProperty =
DependencyProperty.Register(nameof(SelectedColorIndex), typeof(int), typeof(EquationStylePanelControl), new PropertyMetadata(default(int)));
public IList<Windows.UI.Xaml.Media.SolidColorBrush> AvailableColors
{
get { return (IList<Windows.UI.Xaml.Media.SolidColorBrush>)GetValue(AvailableColorsProperty); }
set { SetValue(AvailableColorsProperty, value); }
}
// Using a DependencyProperty as the backing store for AvailableColors. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AvailableColorsProperty =
DependencyProperty.Register(nameof(AvailableColors), typeof(IList<Windows.UI.Xaml.Media.SolidColorBrush>), typeof(EquationStylePanelControl), new PropertyMetadata(null));
public bool EnableLineStylePicker
{
get { return (bool)GetValue(EnableLineStylePickerProperty); }
set { SetValue(EnableLineStylePickerProperty, value); }
}
// Using a DependencyProperty as the backing store for EnableLineStylePicker. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EnableLineStylePickerProperty =
DependencyProperty.Register(nameof(EnableLineStylePicker), typeof(bool), typeof(EquationStylePanelControl), new PropertyMetadata(default(bool)));
public static Windows.UI.Xaml.Media.DoubleCollection GetLinePattern(object line)
{
var lineStyle = ((EquationLineStyle?)line).Value;
var linePattern = new DoubleCollection();
switch (lineStyle)
{
case EquationLineStyle.Dot:
linePattern.Append(1);
break;
case EquationLineStyle.Dash:
linePattern.Append(2);
linePattern.Append(1);
break;
default:
break;
}
return linePattern;
}
public static string GetLineAutomationName(object line)
{
var resourceLoader = AppResourceProvider.GetInstance();
var lineStyle = ((EquationLineStyle?)line).Value;
switch (lineStyle)
{
case EquationLineStyle.Dot:
return resourceLoader.GetResourceString("dotLineStyleAutomationName");
break;
case EquationLineStyle.Dash:
return resourceLoader.GetResourceString("dashLineStyleAutomationName");
break;
case EquationLineStyle.Solid:
default:
return resourceLoader.GetResourceString("solidLineStyleAutomationName");
break;
}
}
public static string GetColorAutomationName(Windows.UI.Xaml.Media.Brush brush)
{
var resourceLoader = AppResourceProvider.GetInstance();
var color = ((SolidColorBrush)brush);
var lightDictionary = (ResourceDictionary)(Application.Current.Resources.ThemeDictionaries["Light"]);
var darkDictionary = (ResourceDictionary)(Application.Current.Resources.ThemeDictionaries["Default"]);
var highContrast = (ResourceDictionary)(Application.Current.Resources.ThemeDictionaries["HighContrast"]);
if (color == (SolidColorBrush)(lightDictionary["EquationBrush1"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush1"]))
{
return resourceLoader.GetResourceString("equationColor1AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush2"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush2"]))
{
return resourceLoader.GetResourceString("equationColor2AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush3"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush3"]))
{
return resourceLoader.GetResourceString("equationColor3AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush4"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush4"]))
{
return resourceLoader.GetResourceString("equationColor4AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush5"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush5"]))
{
return resourceLoader.GetResourceString("equationColor5AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush6"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush6"]))
{
return resourceLoader.GetResourceString("equationColor6AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush7"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush7"]))
{
return resourceLoader.GetResourceString("equationColor7AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush8"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush8"]))
{
return resourceLoader.GetResourceString("equationColor8AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush9"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush9"]))
{
return resourceLoader.GetResourceString("equationColor9AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush10"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush10"]))
{
return resourceLoader.GetResourceString("equationColor10AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush11"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush11"]))
{
return resourceLoader.GetResourceString("equationColor11AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush12"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush12"]))
{
return resourceLoader.GetResourceString("equationColor12AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush13"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush13"]))
{
return resourceLoader.GetResourceString("equationColor13AutomationName");
}
else if (color == (SolidColorBrush)(darkDictionary["EquationBrush14"]))
{
return resourceLoader.GetResourceString("equationColor14WhiteAutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush14"]))
{
return resourceLoader.GetResourceString("equationColor14BlackAutomationName");
}
else if (color == (SolidColorBrush)(highContrast["EquationBrush1"]))
{
return resourceLoader.GetResourceString("equationHighContrastColor1AutomationName");
}
else if (color == (SolidColorBrush)(highContrast["EquationBrush2"]))
{
return resourceLoader.GetResourceString("equationHighContrastColor2AutomationName");
}
else if (color == (SolidColorBrush)(highContrast["EquationBrush3"]))
{
return resourceLoader.GetResourceString("equationHighContrastColor3AutomationName");
}
else
{
return resourceLoader.GetResourceString("equationHighContrastColor4AutomationName");
}
}
private void SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
var brush = (e.AddedItems[0] as SolidColorBrush);
if (brush == null)
{
SelectedColor = Colors.Black;
}
else
{
SelectedColor = brush.Color;
}
TraceLogger.GetInstance().LogGraphLineStyleChanged(LineStyleType.Color);
}
}
private void OnSelectedColorPropertyChanged(Color oldColor, Color newColor)
{
SelectColor(newColor);
}
private void ColorChooserLoaded(object sender, RoutedEventArgs e)
{
SelectColor(SelectedColor);
}
private void SelectColor(Color selectedColor)
{
for (int i = 0; i < ColorChooser.Items.Count; i++)
{
var item = ColorChooser.Items[i];
var brush = ((SolidColorBrush)item);
var gridViewItem = (ColorChooser.ContainerFromItem(brush) as GridViewItem);
if (gridViewItem == null)
{
continue;
}
if (Utilities.AreColorsEqual(brush.Color, selectedColor))
{
gridViewItem.IsSelected = true;
SelectedColorIndex = i;
return;
}
else
{
gridViewItem.IsSelected = false;
}
}
}
private void OnSelectedStylePropertyChanged(EquationLineStyle oldStyle, EquationLineStyle newStyle)
{
if (oldStyle != newStyle)
{
SelectStyle(newStyle);
TraceLogger.GetInstance().LogGraphLineStyleChanged(LineStyleType.Pattern);
}
}
private void SelectStyle(EquationLineStyle selectedStyle)
{
foreach (var item in StyleChooserBox.Items)
{
var style = ((EquationLineStyle)item);
var comboBoxItem = (StyleChooserBox.ContainerFromItem(style) as ComboBoxItem);
if (comboBoxItem != null)
{
continue;
}
if (style == selectedStyle)
{
comboBoxItem.IsSelected = true;
return;
}
else
{
comboBoxItem.IsSelected = false;
}
}
}
private void StyleChooserBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
SelectedStyle = ((EquationLineStyle)e.AddedItems[0]);
}
}
private void StyleChooserBox_Loaded(object sender, RoutedEventArgs e)
{
SelectStyle(SelectedStyle);
}
}
}

View file

@ -0,0 +1,29 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CalculatorUI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CalculatorUI")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]

View file

@ -0,0 +1,31 @@
<!--
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
developers. However, you can modify these parameters to modify the behavior of the .NET Native
optimizer.
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
To fully enable reflection for App1.MyClass and all of its public/private members
<Type Name="App1.MyClass" Dynamic="Required All"/>
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Application>
<!--
An Assembly element with Name="*Application*" applies to all assemblies in
the application package. The asterisks are not wildcards.
-->
<Assembly Name="*Application*" Dynamic="Required All" />
<!-- Add your application specific runtime directives here. -->
</Application>
</Directives>

View file

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Windows.UI.Xaml;
namespace CalculatorApp
{
public sealed class DispatcherTimerDelayer
{
public event EventHandler<object> Action;
public DispatcherTimerDelayer(TimeSpan timeSpan)
{
m_timer = new DispatcherTimer();
m_timer.Interval = timeSpan;
var interval = m_timer.Interval;
m_timer.Tick += Timer_Tick;
}
public void Start()
{
m_timer.Start();
}
public void ResetAndStart()
{
m_timer.Stop();
m_timer.Start();
}
public void Stop()
{
m_timer.Stop();
}
private void Timer_Tick(object sender, object e)
{
m_timer.Stop();
Action(this, null);
}
private DispatcherTimer m_timer;
}
}

View file

@ -0,0 +1,134 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
// Light C++/CX port of Microsoft.Toolkit.Uwp.UI.Extensions.VisualTree from the Windows Community toolkit
// Original version here:
// https://raw.githubusercontent.com/windows-toolkit/WindowsCommunityToolkit/master/Microsoft.Toolkit.Uwp.UI/Extensions/Tree/VisualTree.cs
namespace Calculator.Utils
{
/// <summary>
/// Defines a collection of extensions methods for UI.
/// </summary>
sealed class VisualTree
{
/// <summary>
/// Find descendant <see cref="Windows.UI.Xaml.FrameworkElement ^"/> control using its name.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="name">Name of the control to find</param>
/// <returns>Descendant control or null if not found.</returns>
internal static FrameworkElement FindDescendantByName(DependencyObject element, string name)
{
if (element == null || name == null || name.Length == 0)
{
return null;
}
var frameworkElement = (element as FrameworkElement);
if (frameworkElement != null && name.Equals(frameworkElement.Name))
{
return frameworkElement;
}
var childCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childCount; i++)
{
var result = FindDescendantByName(VisualTreeHelper.GetChild(element, i), name);
if (result != null)
{
return result;
}
}
return null;
}
/// <summary>
/// Find first descendant control of a specified type.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="type">Type of descendant.</param>
/// <returns>Descendant control or null if not found.</returns>
private static DependencyObject FindDescendant(DependencyObject element, Type typeName)
{
DependencyObject retValue = null;
var childrenCount = VisualTreeHelper.GetChildrenCount(element);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(element, i);
if (child.GetType() == typeName)
{
retValue = child;
break;
}
retValue = FindDescendant(child, typeName);
if (retValue != null)
{
break;
}
}
return retValue;
}
/// <summary>
/// Find visual ascendant <see cref="Windows.UI.Xaml.FrameworkElement ^"/> control using its name.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="name">Name of the control to find</param>
/// <returns>Descendant control or null if not found.</returns>
private static FrameworkElement FindAscendantByName(DependencyObject element, string name)
{
if (element == null || name == null || name.Length == 0)
{
return null;
}
var parent = VisualTreeHelper.GetParent(element);
if (parent == null)
{
return null;
}
var frameworkElement = (parent as FrameworkElement);
if (frameworkElement != null && name.Equals(frameworkElement.Name))
{
return frameworkElement;
}
return FindAscendantByName(parent, name);
}
/// <summary>
/// Find first visual ascendant control of a specified type.
/// </summary>
/// <param name="element">Child element.</param>
/// <param name="type">Type of ascendant to look for.</param>
/// <returns>Ascendant control or null if not found.</returns>
private static object FindAscendant(DependencyObject element, Type typeName)
{
var parent = VisualTreeHelper.GetParent(element);
if (parent == null)
{
return null;
}
if (parent.GetType() == typeName)
{
return parent;
}
return FindAscendant(parent, typeName);
}
}
}

View file

@ -0,0 +1,173 @@
<UserControl x:Class="CalculatorApp.HistoryList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:automation="using:CalculatorApp.Common.Automation"
xmlns:converters="using:CalculatorApp.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:CalculatorApp.ViewModel"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
AutomationProperties.AutomationId="HistoryList"
FlowDirection="LeftToRight"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<Style x:Key="BodyTextBlockMediumStyle"
BasedOn="{StaticResource BodyTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}"/>
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<Style x:Key="BodyTextBlockMediumStyle"
BasedOn="{StaticResource BodyTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}"/>
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<Style x:Key="BodyTextBlockMediumStyle"
BasedOn="{StaticResource BodyTextBlockStyle}"
TargetType="TextBlock"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<converters:ItemSizeToVisibilityNegationConverter x:Key="ItemSizeToVisibilityNegationConverter"/>
<converters:ItemSizeToVisibilityConverter x:Key="ItemSizeToVisibilityConverter"/>
<automation:NarratorNotifier x:Name="NarratorNotifier" Announcement="{x:Bind Model.HistoryAnnouncement, Mode=OneWay}"/>
<muxc:SymbolIconSource x:Key="DeleteSymbol" Symbol="Delete"/>
<muxc:SwipeItems x:Key="HistorySwipeItems" Mode="Execute">
<muxc:SwipeItem x:Uid="DeleteHistorySwipeItem"
IconSource="{StaticResource DeleteSymbol}"
Invoked="OnDeleteSwipeInvoked"/>
</muxc:SwipeItems>
<MenuFlyout x:Name="HistoryContextMenu">
<MenuFlyoutItem x:Uid="CopyHistoryMenuItem"
Click="OnCopyMenuItemClicked"
Icon="Copy"/>
<MenuFlyoutItem x:Uid="DeleteHistoryMenuItem"
Click="OnDeleteMenuItemClicked"
Icon="Delete"/>
</MenuFlyout>
<DataTemplate x:Key="HistoryItemTemplate" x:DataType="model:HistoryItemViewModel">
<muxc:SwipeControl RightItems="{StaticResource HistorySwipeItems}">
<StackPanel Margin="0,6,4,6" Background="Transparent">
<TextBlock x:Name="ExprTextBlock"
Margin="0,0,0,4"
HorizontalAlignment="Right"
Style="{ThemeResource BodyTextBlockMediumStyle}"
AutomationProperties.AutomationId="HistoryItemExpression"
AutomationProperties.Name="{x:Bind AccExpression}"
IsTextSelectionEnabled="True"
Text="{x:Bind Expression}"
TextAlignment="Right"
TextWrapping="Wrap"/>
<TextBlock x:Name="ResultTextBlock"
HorizontalAlignment="Right"
Style="{ThemeResource TitleTextBlockStyle}"
FontWeight="SemiBold"
AutomationProperties.AutomationId="HistoryItemValue"
AutomationProperties.Name="{x:Bind AccResult}"
IsTextSelectionEnabled="True"
Text="{x:Bind Result}"
TextAlignment="Right"
TextWrapping="Wrap"/>
</StackPanel>
</muxc:SwipeControl>
</DataTemplate>
<Style x:Key="HistoryItemContainerStyle"
BasedOn="{StaticResource HistoryMemoryItemContainerStyle}"
TargetType="ListViewItem">
<Setter Property="Margin" Value="0,0,0,20"/>
<Setter Property="ContextFlyout" Value="{StaticResource HistoryContextMenu}"/>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="LayoutGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="{Binding RowHeight, ElementName=HistoryList, Mode=OneWay}"/>
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="DockedLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="560"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="HistoryListRootGrid.(Grid.Row)" Value="0"/>
<Setter Target="HistoryListRootGrid.(Grid.RowSpan)" Value="2"/>
<Setter Target="HistoryListView.Padding" Value="0"/>
<Setter Target="BackgroundShade.Visibility" Value="Collapsed"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="DefaultLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"/>
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="BackgroundShade"
Grid.Row="1"
Margin="0,-1,0,0"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="{ThemeResource SystemControlChromeMediumLowAcrylicElementMediumBrush}"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="{ThemeResource HighContrastThicknessTop}"/>
<Grid x:Name="HistoryListRootGrid" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="HistoryEmpty"
x:Uid="HistoryEmpty"
Margin="16,14,24,0"
Style="{ThemeResource BaseTextBlockStyle}"
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
FontWeight="SemiLight"
TextWrapping="Wrap"
Visibility="{x:Bind Model.ItemsCount, Converter={StaticResource ItemSizeToVisibilityConverter}, Mode=OneWay}"/>
<ListView x:Name="HistoryListView"
MinHeight="60"
Padding="0,12,0,0"
HorizontalAlignment="Stretch"
AutomationProperties.AutomationId="HistoryListView"
IsItemClickEnabled="True"
ItemClick="ListView_ItemClick"
ItemContainerStyle="{StaticResource HistoryItemContainerStyle}"
ItemTemplate="{StaticResource HistoryItemTemplate}"
ItemsSource="{x:Bind Model.Items, Mode=OneWay}"
SelectionMode="None"
TabIndex="0"
Visibility="{x:Bind Model.ItemsCount, Mode=OneWay, Converter={StaticResource ItemSizeToVisibilityNegationConverter}}">
<ListView.ItemContainerTransitions>
<TransitionCollection>
<AddDeleteThemeTransition/>
<ContentThemeTransition/>
<ReorderThemeTransition/>
</TransitionCollection>
</ListView.ItemContainerTransitions>
</ListView>
<Button x:Name="ClearHistory"
x:Uid="ClearHistory"
Grid.Row="1"
Style="{StaticResource ClearAllHistoryMemoryButtonStyle}"
AutomationProperties.AutomationId="ClearHistory"
Command="{x:Bind Model.ClearCommand, Mode=OneWay}"
Content="&#xE74D;"
Visibility="{x:Bind Model.ItemsCount, Mode=OneWay, Converter={StaticResource ItemSizeToVisibilityNegationConverter}}"/>
</Grid>
</Grid>
</UserControl>

View file

@ -0,0 +1,88 @@
using CalculatorApp.Common;
using CalculatorApp.ViewModel;
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using MUXC = Microsoft.UI.Xaml.Controls;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace CalculatorApp
{
[Windows.Foundation.Metadata.WebHostHidden]
public sealed partial class HistoryList : UserControl
{
public HistoryList()
{
InitializeComponent();
HistoryEmpty.FlowDirection = LocalizationService.GetInstance().GetFlowDirection();
}
public CalculatorApp.ViewModel.HistoryViewModel Model
{
get => (CalculatorApp.ViewModel.HistoryViewModel)DataContext;
}
public void ScrollToBottom()
{
var historyItems = HistoryListView.Items;
if (historyItems.Count > 0)
{
HistoryListView.ScrollIntoView(historyItems[historyItems.Count - 1]);
}
}
public Windows.UI.Xaml.GridLength RowHeight
{
get { return (Windows.UI.Xaml.GridLength)GetValue(RowHeightProperty); }
set { SetValue(RowHeightProperty, value); }
}
// Using a DependencyProperty as the backing store for RowHeight. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RowHeightProperty =
DependencyProperty.Register(nameof(RowHeight), typeof(Windows.UI.Xaml.GridLength), typeof(HistoryList), new PropertyMetadata(default(Windows.UI.Xaml.GridLength)));
private Windows.Foundation.Rect m_visibleBounds;
private Windows.Foundation.Rect m_coreBounds;
private void ListView_ItemClick(object sender, ItemClickEventArgs e)
{
HistoryViewModel historyVM = (DataContext as HistoryViewModel);
HistoryItemViewModel clickedItem = (e.ClickedItem as HistoryItemViewModel);
// When the user clears the history list in the overlay view and presses enter, the clickedItem is nullptr
if (clickedItem != null && historyVM != null)
{
historyVM.ShowItem(clickedItem);
}
}
private void OnCopyMenuItemClicked(object sender, RoutedEventArgs e)
{
var listViewItem = HistoryContextMenu.Target;
var itemViewModel = (HistoryListView.ItemFromContainer(listViewItem) as HistoryItemViewModel);
if (itemViewModel != null)
{
CopyPasteManager.CopyToClipboard(itemViewModel.Result);
}
}
private void OnDeleteMenuItemClicked(object sender, RoutedEventArgs e)
{
var listViewItem = HistoryContextMenu.Target;
var itemViewModel = (HistoryListView.ItemFromContainer(listViewItem) as HistoryItemViewModel);
if (itemViewModel != null)
{
Model.DeleteItem(itemViewModel);
}
}
private void OnDeleteSwipeInvoked(MUXC.SwipeItem sender, MUXC.SwipeItemInvokedEventArgs e)
{
var swipedItem = (e.SwipeControl.DataContext as HistoryItemViewModel);
if (swipedItem != null)
{
Model.DeleteItem(swipedItem);
}
}
}
}

View file

@ -0,0 +1,198 @@
<Page x:Class="CalculatorApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:automation="using:CalculatorApp.Common.Automation"
xmlns:common="using:CalculatorApp.Common"
xmlns:controls="using:CalculatorApp.Controls"
xmlns:converters="using:CalculatorApp.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:CalculatorApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:vm="using:CalculatorApp.ViewModel"
x:Name="PageRoot"
Background="{ThemeResource AppChromeAcrylicHostBackdropMediumLowBrush}"
Loaded="OnPageLoaded"
mc:Ignorable="d">
<Page.Resources>
<automation:NarratorNotifier x:Name="NarratorNotifier"/>
<Style x:Name="CalculatorBaseStyle" TargetType="local:Calculator">
<Setter Property="Margin" Value="0,0,0,0"/>
</Style>
<!--<Style x:Name="UnitConverterBaseStyle" TargetType="local:UnitConverter">
<Setter Property="Visibility" Value="Collapsed"/>
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="Margin" Value="0,0,0,0"/>
</Style>-->
<Style x:Key="AboutFlyoutPresenterStyle" TargetType="FlyoutPresenter">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
</Style>
<Style x:Key="NavViewItemStyle" TargetType="muxc:NavigationViewItem">
<Setter Property="KeyTipPlacementMode" Value="Right"/>
</Style>
<Style x:Key="CategoryNameTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="20"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="OpticalMarginAlignment" Value="TrimSideBearings"/>
</Style>
<converters:BooleanToVisibilityNegationConverter x:Key="BooleanToVisibilityNegationConverter"/>
<converters:BooleanNegationConverter x:Key="BooleanNegationConverter"/>
</Page.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Mode">
<VisualState x:Name="ConverterWide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowHeight="{StaticResource AppMinWindowHeight}" MinWindowWidth="640"/>
</VisualState.StateTriggers>
</VisualState>
<VisualState x:Name="DockVisible">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowHeight="{StaticResource AppMinWindowHeight}" MinWindowWidth="560"/>
</VisualState.StateTriggers>
</VisualState>
<VisualState x:Name="MinSizeLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowHeight="{StaticResource AppMinWindowHeight}" MinWindowWidth="{StaticResource AppMinWindowWidth}"/>
</VisualState.StateTriggers>
</VisualState>
<VisualState x:Name="DefaultLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowHeight="0" MinWindowWidth="0"/>
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel Visibility="Collapsed">
<!--
These buttons are only here to serve as the target for copy/paste commands
they are not to be shown, only to have the command and shortcut assigned to them.
-->
<Button x:Name="CopyButton"
x:Uid="copyButton"
Command="{x:Bind Model.CopyCommand}"/>
<Button x:Name="PasteButton"
x:Uid="pasteButton"
Command="{x:Bind Model.PasteCommand}"/>
<Button x:Name="CopyButtonAlternate"
x:Uid="copyButtonAlternate"
Command="{x:Bind Model.CopyCommand}"/>
<Button x:Name="PasteButtonAlternate"
x:Uid="pasteButtonAlternate"
Command="{x:Bind Model.PasteCommand}"/>
</StackPanel>
<local:TitleBar Grid.Row="0"
AlwaysOnTopClick="TitleBarAlwaysOnTopButtonClick"
IsAlwaysOnTopMode="{x:Bind Model.IsAlwaysOnTop, Mode=OneWay}"/>
<Grid Grid.Row="1">
<Border x:Name="CalcHolder">
<!-- PLACEHOLDER!!!! This is where the calculator goes when it is delay loaded -->
</Border>
<Border x:Name="DateCalcHolder">
<!-- PLACEHOLDER!!!! This is where the date calculator goes when it is delay loaded -->
</Border>
<Border x:Name="GraphingCalcHolder">
<!-- PLACEHOLDER!!!! This is where the graphing calculator goes when it is delay loaded -->
</Border>
<Border x:Name="ConverterHolder">
<!-- PLACEHOLDER!!!! This is where the converter goes when it is delay loaded -->
</Border>
</Grid>
<Grid Grid.Row="1"
Height="{StaticResource HamburgerHeight}"
HorizontalAlignment="Left"
VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{StaticResource HamburgerHeightGridLength}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="Header"
Grid.Column="1"
Margin="8,-3,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource CategoryNameTextBlockStyle}"
Text="{x:Bind Model.CategoryName, Mode=OneWay}"
Visibility="{x:Bind Model.IsAlwaysOnTop, Converter={StaticResource BooleanToVisibilityNegationConverter}, Mode=OneWay}"/>
<Button x:Name="NormalAlwaysOnTopButton"
x:Uid="EnterAlwaysOnTopButton"
Grid.Column="2"
Margin="10,0,0,0"
VerticalAlignment="Center"
HorizontalContentAlignment="Center"
Style="{StaticResource SquareIconButtonStyle}"
Background="Transparent"
FontFamily="{StaticResource CalculatorFontFamily}"
AutomationProperties.AutomationId="NormalAlwaysOnTopButton"
Click="AlwaysOnTopButtonClick"
Content="&#xEE49;"
TabIndex="3"
Visibility="{x:Bind Model.DisplayNormalAlwaysOnTopOption, Mode=OneWay}">
<Button.KeyboardAccelerators>
<KeyboardAccelerator Key="Up" Modifiers="Menu"/>
</Button.KeyboardAccelerators>
</Button>
</Grid>
<muxc:NavigationView x:Name="NavView"
x:Uid="NavView"
Grid.Row="1"
CompactModeThresholdWidth="Infinity"
DataContext="{x:Bind Model}"
ExpandedModeThresholdWidth="Infinity"
IsBackButtonVisible="Collapsed"
IsPaneToggleButtonVisible="{x:Bind Model.IsAlwaysOnTop, Converter={StaticResource BooleanNegationConverter}, Mode=OneWay}"
IsSettingsVisible="False"
ItemInvoked="OnNavItemInvoked"
Loaded="OnNavLoaded"
MenuItemsSource="{x:Bind CreateUIElementsForCategories(Model.Categories), Mode=OneWay}"
OpenPaneLength="{StaticResource SplitViewOpenPaneLength}"
PaneClosed="OnNavPaneClosed"
PaneOpened="OnNavPaneOpened"
PaneOpening="OnNavPaneOpening"
SelectionChanged="OnNavSelectionChanged"
TabIndex="1"
UseSystemFocusVisuals="True"
IsEnabled="{x:Bind Model.IsAlwaysOnTop, Converter={StaticResource BooleanNegationConverter}, Mode=OneWay}"
x:Load="False">
<muxc:NavigationView.PaneFooter>
<muxc:NavigationViewItem x:Name="AboutButton"
x:Uid="AboutButton"
Style="{StaticResource NavViewItemStyle}"
KeyDown="OnAboutButtonKeyDown"
Tapped="OnAboutButtonClick">
<muxc:NavigationViewItem.Icon>
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph="&#xe946;"/>
</muxc:NavigationViewItem.Icon>
<FlyoutBase.AttachedFlyout>
<Flyout x:Name="AboutPageFlyout"
x:Uid="AboutPageFlyout"
Closed="OnAboutFlyoutClosed"
FlyoutPresenterStyle="{StaticResource AboutFlyoutPresenterStyle}"
Opened="OnAboutFlyoutOpened">
<local:AboutFlyout x:Name="AboutPage" x:Load="False"/>
</Flyout>
</FlyoutBase.AttachedFlyout>
</muxc:NavigationViewItem>
</muxc:NavigationView.PaneFooter>
</muxc:NavigationView>
</Grid>
</Page>

View file

@ -0,0 +1,584 @@
using CalculatorApp.Common;
using CalculatorApp.Common.Automation;
using CalculatorApp.Converters;
using CalculatorApp.ViewModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Navigation;
using MUXC = Microsoft.UI.Xaml.Controls;
namespace CalculatorApp
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
m_model = new ViewModel.ApplicationViewModel();
InitializeComponent();
KeyboardShortcutManager.Initialize();
Application.Current.Suspending += App_Suspending;
m_model.PropertyChanged += OnAppPropertyChanged;
m_accessibilitySettings = new AccessibilitySettings();
// CSHARP_MIGRAION: TODO: find another implementation for C#
//double sizeInInches = 0.0;
//if (SUCCEEDED(GetIntegratedDisplaySize(&sizeInInches)))
//{
// if (sizeInInches < 7.0) // If device's display size (diagonal length) is less than 7 inches then keep the calc always in Portrait mode only
// {
// DisplayInformation.AutoRotationPreferences = DisplayOrientations.Portrait | DisplayOrientations.PortraitFlipped;
// }
//}
}
public CalculatorApp.ViewModel.ApplicationViewModel Model
{
get => m_model;
}
public void UnregisterEventHandlers()
{
Window.Current.SizeChanged -= WindowSizeChanged;
m_accessibilitySettings.HighContrastChanged -= OnHighContrastChanged;
if (m_calculator != null)
{
m_calculator.UnregisterEventHandlers();
}
}
public void SetDefaultFocus()
{
if (m_calculator != null && m_calculator.Visibility == Visibility.Visible)
{
m_calculator.SetDefaultFocus();
}
if (m_dateCalculator != null && m_dateCalculator.Visibility == Visibility.Visible)
{
m_dateCalculator.SetDefaultFocus();
}
if (m_graphingCalculator != null && m_graphingCalculator.Visibility == Visibility.Visible)
{
m_graphingCalculator.SetDefaultFocus();
}
// CSHARP_MIGRATION: TODO:
//if (m_converter != null && m_converter.Visibility == Visibility.Visible)
//{
// m_converter.SetDefaultFocus();
//}
}
public void SetHeaderAutomationName()
{
ViewMode mode = m_model.Mode;
var resProvider = AppResourceProvider.GetInstance();
string name;
if (NavCategory.IsDateCalculatorViewMode(mode))
{
name = resProvider.GetResourceString("HeaderAutomationName_Date");
}
else
{
string full = string.Empty;
if (NavCategory.IsCalculatorViewMode(mode) || NavCategory.IsGraphingCalculatorViewMode(mode))
{
full = resProvider.GetResourceString("HeaderAutomationName_Calculator");
}
else if (NavCategory.IsConverterViewMode(mode))
{
full = resProvider.GetResourceString("HeaderAutomationName_Converter");
}
name = LocalizationStringUtil.GetLocalizedString(full, m_model.CategoryName);
}
AutomationProperties.SetName(Header, name);
}
public ObservableCollection<object> CreateUIElementsForCategories(IObservableVector<NavCategoryGroup> categories)
{
var menuCategories = new ObservableCollection<object>(); // CSHARP_MIGRATION: TODO: Check if ObservableCollection fits here
foreach (var group in categories)
{
menuCategories.Add(CreateNavViewHeaderFromGroup(group));
foreach (var category in group.Categories)
{
menuCategories.Add(CreateNavViewItemFromCategory(category));
}
}
return menuCategories;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
ViewMode initialMode = ViewMode.Standard;
if (e.Parameter != null)
{
string stringParameter = (e.Parameter as string);
if (!string.IsNullOrEmpty(stringParameter))
{
initialMode = (ViewMode)Convert.ToInt32(stringParameter);
}
}
else
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
if (localSettings.Values.ContainsKey(ApplicationViewModel.ModePropertyName))
{
initialMode = NavCategory.Deserialize(localSettings.Values[ApplicationViewModel.ModePropertyName]);
}
}
m_model.Initialize(initialMode);
}
private void WindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
// We don't use layout aware page's view states, we have our own
UpdateViewState();
}
private void OnAppPropertyChanged(object sender, PropertyChangedEventArgs e)
{
string propertyName = e.PropertyName;
if (propertyName == ApplicationViewModel.ModePropertyName)
{
ViewMode newValue = m_model.Mode;
ViewMode previousMode = m_model.PreviousMode;
KeyboardShortcutManager.DisableShortcuts(false);
if (newValue == ViewMode.Standard)
{
EnsureCalculator();
m_model.CalculatorViewModel.HistoryVM.AreHistoryShortcutsEnabled = true;
m_calculator.AnimateCalculator(NavCategory.IsConverterViewMode(previousMode));
m_model.CalculatorViewModel.HistoryVM.ReloadHistory(newValue);
}
else if (newValue == ViewMode.Scientific)
{
EnsureCalculator();
m_model.CalculatorViewModel.HistoryVM.AreHistoryShortcutsEnabled = true;
if (m_model.PreviousMode != ViewMode.Scientific)
{
m_calculator.AnimateCalculator(NavCategory.IsConverterViewMode(previousMode));
}
m_model.CalculatorViewModel.HistoryVM.ReloadHistory(newValue);
}
else if (newValue == ViewMode.Programmer)
{
m_model.CalculatorViewModel.HistoryVM.AreHistoryShortcutsEnabled = false;
EnsureCalculator();
if (m_model.PreviousMode != ViewMode.Programmer)
{
m_calculator.AnimateCalculator(NavCategory.IsConverterViewMode(previousMode));
}
}
else if (NavCategory.IsDateCalculatorViewMode(newValue))
{
if (m_model.CalculatorViewModel != null)
{
m_model.CalculatorViewModel.HistoryVM.AreHistoryShortcutsEnabled = false;
}
EnsureDateCalculator();
}
else if (newValue == ViewMode.Graphing)
{
EnsureGraphingCalculator();
KeyboardShortcutManager.DisableShortcuts(true);
}
else if (NavCategory.IsConverterViewMode(newValue))
{
if (m_model.CalculatorViewModel != null)
{
m_model.CalculatorViewModel.HistoryVM.AreHistoryShortcutsEnabled = false;
}
// CSHARP_MIGRATION: TODO:
//EnsureConverter();
if (!NavCategory.IsConverterViewMode(previousMode))
{
// CSHARP_MIGRATION: TODO:
//m_converter.AnimateConverter();
}
}
ShowHideControls(newValue);
UpdateViewState();
SetDefaultFocus();
}
else if (propertyName == ApplicationViewModel.CategoryNamePropertyName)
{
SetHeaderAutomationName();
AnnounceCategoryName();
}
}
private void OnNavLoaded(object sender, RoutedEventArgs e)
{
if (NavView.SelectedItem == null)
{
var menuItems = ((ObservableCollection<object>)NavView.MenuItemsSource);
var itemCount = ((int)menuItems.Count);
var flatIndex = NavCategory.GetFlatIndex(Model.Mode);
if (flatIndex >= 0 && flatIndex < itemCount)
{
NavView.SelectedItem = menuItems[flatIndex];
}
}
var acceleratorList = new List<MyVirtualKey>();
NavCategory.GetCategoryAcceleratorKeys(acceleratorList);
foreach (var accelerator in acceleratorList)
{
NavView.SetValue(Common.KeyboardShortcutManager.VirtualKeyAltChordProperty, accelerator);
}
// Special case logic for Ctrl+E accelerator for Date Calculation Mode
NavView.SetValue(Common.KeyboardShortcutManager.VirtualKeyControlChordProperty, Common.MyVirtualKey.E);
}
private void OnNavPaneOpening(MUXC.NavigationView sender, object args)
{
if (AboutButton != null)
{
FindName("AboutButton");
}
}
private void OnNavPaneOpened(MUXC.NavigationView sender, object args)
{
KeyboardShortcutManager.HonorShortcuts(false);
TraceLogger.GetInstance().LogNavBarOpened();
}
private void OnNavPaneClosed(MUXC.NavigationView sender, object args)
{
if (Model.Mode != ViewMode.Graphing)
{
KeyboardShortcutManager.HonorShortcuts(true);
}
SetDefaultFocus();
}
private void OnNavSelectionChanged(object sender, MUXC.NavigationViewSelectionChangedEventArgs e)
{
var item = (e.SelectedItemContainer as MUXC.NavigationViewItem);
if (item != null)
{
var selectedItem = ((NavCategory)item.DataContext);
Model.Mode = selectedItem.Mode;
}
}
private void OnNavItemInvoked(MUXC.NavigationView sender, MUXC.NavigationViewItemInvokedEventArgs e)
{
NavView.IsPaneOpen = false;
}
private void OnAboutButtonClick(object sender, TappedRoutedEventArgs e)
{
ShowAboutPage();
}
private void OnAboutButtonKeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Space || e.Key == Windows.System.VirtualKey.Enter)
{
ShowAboutPage();
}
}
private void OnAboutFlyoutOpened(object sender, object e)
{
// Keep Ignoring Escape till the About page flyout is opened
KeyboardShortcutManager.IgnoreEscape(false);
KeyboardShortcutManager.HonorShortcuts(false);
}
private void OnAboutFlyoutClosed(object sender, object e)
{
// Start Honoring Escape once the About page flyout is closed
KeyboardShortcutManager.HonorEscape();
KeyboardShortcutManager.HonorShortcuts(!NavView.IsPaneOpen);
}
private void AlwaysOnTopButtonClick(object sender, RoutedEventArgs e)
{
Model.ToggleAlwaysOnTop(0, 0);
}
private void TitleBarAlwaysOnTopButtonClick(object sender, RoutedEventArgs e)
{
var bounds = Window.Current.Bounds;
Model.ToggleAlwaysOnTop((float)bounds.Width, (float)bounds.Height);
}
private MUXC.NavigationViewItemHeader CreateNavViewHeaderFromGroup(NavCategoryGroup group)
{
var header = new MUXC.NavigationViewItemHeader();
header.DataContext = group;
header.Content = group.Name;
AutomationProperties.SetName(header, group.AutomationName);
AutomationProperties.SetHeadingLevel(header, Windows.UI.Xaml.Automation.Peers.AutomationHeadingLevel.Level1);
return header;
}
private MUXC.NavigationViewItem CreateNavViewItemFromCategory(NavCategory category)
{
var item = new MUXC.NavigationViewItem();
item.DataContext = category;
var icon = new FontIcon();
icon.FontFamily = (Windows.UI.Xaml.Media.FontFamily)(App.Current.Resources["CalculatorFontFamily"]);
icon.Glyph = category.Glyph;
item.Icon = icon;
item.Content = category.Name;
item.AccessKey = category.AccessKey;
item.IsEnabled = category.IsEnabled;
item.Style = (Windows.UI.Xaml.Style)(Resources["NavViewItemStyle"]);
AutomationProperties.SetName(item, category.AutomationName);
AutomationProperties.SetAutomationId(item, category.AutomationId);
return item;
}
private void ShowHideControls(ViewMode mode)
{
var isCalcViewMode = NavCategory.IsCalculatorViewMode(mode);
var isDateCalcViewMode = NavCategory.IsDateCalculatorViewMode(mode);
var isGraphingCalcViewMode = NavCategory.IsGraphingCalculatorViewMode(mode);
var isConverterViewMode = NavCategory.IsConverterViewMode(mode);
if (m_calculator != null)
{
m_calculator.Visibility = BooleanToVisibilityConverter.Convert(isCalcViewMode);
m_calculator.IsEnabled = isCalcViewMode;
}
if (m_dateCalculator != null)
{
m_dateCalculator.Visibility = BooleanToVisibilityConverter.Convert(isDateCalcViewMode);
m_dateCalculator.IsEnabled = isDateCalcViewMode;
}
if (m_graphingCalculator != null)
{
m_graphingCalculator.Visibility = BooleanToVisibilityConverter.Convert(isGraphingCalcViewMode);
m_graphingCalculator.IsEnabled = isGraphingCalcViewMode;
}
// CSHARP_MIGRATION: TODO:
//if (m_converter != null)
//{
// m_converter.Visibility = BooleanToVisibilityConverter.Convert(isConverterViewMode);
// m_converter.IsEnabled = isConverterViewMode;
//}
}
private void UpdateViewState()
{
// All layout related view states are now handled only inside individual controls (standard, scientific, programmer, date, converter)
if (NavCategory.IsConverterViewMode(m_model.Mode))
{
int modeIndex = NavCategory.GetIndexInGroup(m_model.Mode, CategoryGroupType.Converter);
m_model.ConverterViewModel.CurrentCategory = m_model.ConverterViewModel.Categories[modeIndex];
}
}
private void UpdatePanelViewState()
{
if (m_calculator != null)
{
m_calculator.UpdatePanelViewState();
}
}
private void OnHighContrastChanged(AccessibilitySettings sender, object args)
{
if (Model.IsAlwaysOnTop && ActualHeight < 394)
{
// Sets to default always-on-top size to force re-layout
ApplicationView.GetForCurrentView().TryResizeView(new Size(320, 394));
}
}
private void OnPageLoaded(object sender, RoutedEventArgs args)
{
// CSHARP_MIGRATION: TODO:
//if (!m_converter && !m_calculator && !m_dateCalculator && !m_graphingCalculator)
if (m_calculator == null && m_dateCalculator == null && m_graphingCalculator == null)
{
// We have just launched into our default mode (standard calc) so ensure calc is loaded
EnsureCalculator();
m_model.CalculatorViewModel.IsStandard = true;
}
Window.Current.SizeChanged += WindowSizeChanged;
m_accessibilitySettings.HighContrastChanged += OnHighContrastChanged;
UpdateViewState();
SetHeaderAutomationName();
SetDefaultFocus();
// Delay load things later when we get a chance.
_ = Dispatcher.RunAsync(
CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
{
if (TraceLogger.GetInstance().IsWindowIdInLog(ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread())))
{
AppLifecycleLogger.GetInstance().LaunchUIResponsive();
AppLifecycleLogger.GetInstance().LaunchVisibleComplete();
}
FindName("NavView");
}));
}
private void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
if (m_model.IsAlwaysOnTop)
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
localSettings.Values.Add(ApplicationViewModel.WidthLocalSettings, ActualWidth);
localSettings.Values.Add(ApplicationViewModel.HeightLocalSettings, ActualHeight);
}
}
private void EnsureCalculator()
{
if (m_calculator == null)
{
// delay load calculator.
m_calculator = new Calculator();
m_calculator.Name = "Calculator";
m_calculator.DataContext = m_model.CalculatorViewModel;
Binding isStandardBinding = new Binding();
isStandardBinding.Path = new PropertyPath("IsStandard");
m_calculator.SetBinding(Calculator.IsStandardProperty, isStandardBinding);
Binding isScientificBinding = new Binding();
isScientificBinding.Path = new PropertyPath("IsScientific");
m_calculator.SetBinding(Calculator.IsScientificProperty, isScientificBinding);
Binding isProgramerBinding = new Binding();
isProgramerBinding.Path = new PropertyPath("IsProgrammer");
m_calculator.SetBinding(Calculator.IsProgrammerProperty, isProgramerBinding);
Binding isAlwaysOnTopBinding = new Binding();
isAlwaysOnTopBinding.Path = new PropertyPath("IsAlwaysOnTop");
m_calculator.SetBinding(Calculator.IsAlwaysOnTopProperty, isAlwaysOnTopBinding);
m_calculator.Style = CalculatorBaseStyle;
CalcHolder.Child = m_calculator;
// Calculator's "default" state is visible, but if we get delay loaded
// when in converter, we should not be visible. This is not a problem for converter
// since its default state is hidden.
ShowHideControls(Model.Mode);
}
if (m_dateCalculator != null)
{
m_dateCalculator.CloseCalendarFlyout();
}
}
private void EnsureDateCalculator()
{
if (m_dateCalculator == null)
{
// delay loading converter
m_dateCalculator = new DateCalculator();
m_dateCalculator.Name = "dateCalculator";
m_dateCalculator.DataContext = m_model.DateCalcViewModel;
DateCalcHolder.Child = m_dateCalculator;
}
if (m_calculator != null)
{
m_calculator.CloseHistoryFlyout();
m_calculator.CloseMemoryFlyout();
}
}
private void EnsureGraphingCalculator()
{
if (m_graphingCalculator == null)
{
m_graphingCalculator = new GraphingCalculator();
m_graphingCalculator.Name = "GraphingCalculator";
m_graphingCalculator.DataContext = m_model.GraphingCalcViewModel;
GraphingCalcHolder.Child = m_graphingCalculator;
}
}
// CSHARP_MIGRATION: TODO:
//private void EnsureConverter()
//{
// if (!m_converter)
// {
// // delay loading converter
// m_converter = new CalculatorApp.UnitConverter();
// m_converter.Name = "unitConverter";
// m_converter.DataContext = m_model.ConverterViewModel;
// m_converter.Style = UnitConverterBaseStyle;
// ConverterHolder.Child = m_converter;
// }
//}
private void ShowAboutPage()
{
if (AboutPage != null)
{
FindName("AboutPage");
}
FlyoutBase.ShowAttachedFlyout(AboutButton);
}
private void AnnounceCategoryName()
{
string categoryName = AutomationProperties.GetName(Header);
NarratorAnnouncement announcement = CalculatorAnnouncement.GetCategoryNameChangedAnnouncement(categoryName);
NarratorNotifier.Announce(announcement);
}
private CalculatorApp.Calculator m_calculator;
private GraphingCalculator m_graphingCalculator;
// CSHARP_MIGRATION: TODO:
//private CalculatorApp.UnitConverter m_converter;
private CalculatorApp.DateCalculator m_dateCalculator;
private CalculatorApp.ViewModel.ApplicationViewModel m_model;
private Windows.UI.ViewManagement.AccessibilitySettings m_accessibilitySettings;
}
}

View file

@ -0,0 +1,135 @@
<UserControl x:Class="CalculatorApp.Memory"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="using:CalculatorApp.Common"
xmlns:controls="using:CalculatorApp.Controls"
xmlns:converters="using:CalculatorApp.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:CalculatorApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:CalculatorApp.ViewModel"
x:Name="MemoryList"
FlowDirection="LeftToRight"
mc:Ignorable="d">
<UserControl.Resources>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<converters:BooleanToVisibilityNegationConverter x:Key="BooleanToVisibilityNegationConverter"/>
<converters:BooleanNegationConverter x:Key="BooleanNegationConverter"/>
<MenuFlyout x:Name="MemoryContextMenu">
<MenuFlyoutItem x:Uid="ClearMemoryMenuItem" Click="OnClearMenuItemClicked">
<MenuFlyoutItem.Icon>
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph="&#xf754;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem x:Uid="MemPlusMenuItem" Click="OnMemoryAddMenuItemClicked">
<MenuFlyoutItem.Icon>
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph="&#xf757;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem x:Uid="MemMinusMenuItem" Click="OnMemorySubtractMenuItemClicked">
<MenuFlyoutItem.Icon>
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph="&#xf758;"/>
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
</MenuFlyout>
<DataTemplate x:Key="MemoryItemTemplate" x:DataType="model:MemoryItemViewModel">
<local:MemoryListItem Model="{x:Bind Mode=OneWay}"/>
</DataTemplate>
<Style x:Key="MemoryItemContainerStyle"
BasedOn="{StaticResource HistoryMemoryItemContainerStyle}"
TargetType="ListViewItem">
<Setter Property="Margin" Value="0,0,0,8"/>
<Setter Property="ContextFlyout" Value="{StaticResource MemoryContextMenu}"/>
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="{Binding RowHeight, ElementName=MemoryList, Mode=OneWay}"/>
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ErrorVisualStates">
<VisualState x:Name="NoErrorLayout"/>
<VisualState x:Name="ErrorLayout">
<VisualState.Setters>
<Setter Target="MemoryListView.IsEnabled" Value="False"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup>
<VisualState x:Name="DockedLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="560"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MemoryPanel.(Grid.Row)" Value="0"/>
<Setter Target="MemoryPanel.(Grid.RowSpan)" Value="2"/>
<Setter Target="MemoryListView.Padding" Value="0"/>
<Setter Target="BackgroundShade.Visibility" Value="Collapsed"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="DefaultLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"/>
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="BackgroundShade"
Grid.Row="1"
Margin="0,-1,0,0"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="{ThemeResource SystemControlChromeMediumLowAcrylicElementMediumBrush}"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
BorderThickness="{ThemeResource HighContrastThicknessTop}"/>
<Grid x:Name="MemoryPanel" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="MemoryPaneEmpty"
x:Uid="MemoryPaneEmpty"
Margin="16,14,24,0"
Style="{ThemeResource BaseTextBlockStyle}"
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
FontWeight="SemiLight"
TextWrapping="Wrap"
Visibility="{Binding IsMemoryEmpty, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<ListView x:Name="MemoryListView"
Padding="0,12,0,0"
HorizontalAlignment="Stretch"
IsItemClickEnabled="true"
ItemClick="MemoryListItemClick"
ItemContainerStyle="{ThemeResource MemoryItemContainerStyle}"
ItemTemplate="{ThemeResource MemoryItemTemplate}"
ItemsSource="{x:Bind Model.MemorizedNumbers, Mode=OneWay}"
SelectionMode="None"
TabIndex="0"
Visibility="{x:Bind Model.IsMemoryEmpty, Mode=OneWay, Converter={StaticResource BooleanToVisibilityNegationConverter}}">
<ListView.ItemContainerTransitions>
<TransitionCollection>
<AddDeleteThemeTransition/>
<ContentThemeTransition/>
<ReorderThemeTransition/>
</TransitionCollection>
</ListView.ItemContainerTransitions>
</ListView>
<Button x:Name="ClearMemory"
x:Uid="ClearMemory"
Grid.Row="1"
Style="{ThemeResource ClearAllHistoryMemoryButtonStyle}"
AutomationProperties.AutomationId="ClearMemory"
Command="{x:Bind Model.ClearMemoryCommand, Mode=OneWay}"
Content="&#xE74D;"
Visibility="{x:Bind Model.IsMemoryEmpty, Mode=OneWay, Converter={StaticResource BooleanToVisibilityNegationConverter}}"/>
</Grid>
</Grid>
</UserControl>

View file

@ -0,0 +1,104 @@
using CalculatorApp.Common;
using CalculatorApp.ViewModel;
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace CalculatorApp
{
public sealed partial class Memory : UserControl
{
public Memory()
{
InitializeComponent();
MemoryPaneEmpty.FlowDirection = LocalizationService.GetInstance().GetFlowDirection();
}
public CalculatorApp.ViewModel.StandardCalculatorViewModel Model
{
get { return (CalculatorApp.ViewModel.StandardCalculatorViewModel)GetValue(ModelProperty); }
set { SetValue(ModelProperty, value); }
}
// Using a DependencyProperty as the backing store for Model. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ModelProperty =
DependencyProperty.Register(nameof(Model), typeof(CalculatorApp.ViewModel.StandardCalculatorViewModel), typeof(Memory), new PropertyMetadata(default(CalculatorApp.ViewModel.StandardCalculatorViewModel)));
public GridLength RowHeight
{
get { return (GridLength)GetValue(RowHeightProperty); }
set { SetValue(RowHeightProperty, value); }
}
// Using a DependencyProperty as the backing store for RowHeight. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RowHeightProperty =
DependencyProperty.Register(nameof(RowHeight), typeof(GridLength), typeof(Memory), new PropertyMetadata(default(GridLength)));
public bool IsErrorVisualState
{
get => m_isErrorVisualState;
set
{
if (m_isErrorVisualState != value)
{
m_isErrorVisualState = value;
string newState = m_isErrorVisualState ? "ErrorLayout" : "NoErrorLayout";
VisualStateManager.GoToState(this, newState, false);
}
}
}
private Windows.Foundation.Rect m_visibleBounds;
private Windows.Foundation.Rect m_coreBounds;
private bool m_isErrorVisualState = false;
private void MemoryListItemClick(object sender, ItemClickEventArgs e)
{
MemoryItemViewModel memorySlot = ((MemoryItemViewModel)e.ClickedItem);
// In case the memory list is clicked and enter is pressed,
// On Item clicked event gets fired and e->ClickedItem is Null.
if (memorySlot != null)
{
Model.OnMemoryItemPressed(memorySlot.Position);
}
}
private void OnClearMenuItemClicked(object sender, RoutedEventArgs e)
{
var memoryItem = GetMemoryItemForCurrentFlyout();
if (memoryItem != null)
{
memoryItem.Clear();
}
}
private void OnMemoryAddMenuItemClicked(object sender, RoutedEventArgs e)
{
var memoryItem = GetMemoryItemForCurrentFlyout();
if (memoryItem != null)
{
memoryItem.MemoryAdd();
}
}
private void OnMemorySubtractMenuItemClicked(object sender, RoutedEventArgs e)
{
var memoryItem = GetMemoryItemForCurrentFlyout();
if (memoryItem != null)
{
memoryItem.MemorySubtract();
}
}
private MemoryItemViewModel GetMemoryItemForCurrentFlyout()
{
var listViewItem = MemoryContextMenu.Target;
return (MemoryListView.ItemFromContainer(listViewItem) as MemoryItemViewModel);
}
}
}

View file

@ -0,0 +1,97 @@
<UserControl x:Class="CalculatorApp.MemoryListItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
FlowDirection="LeftToRight"
mc:Ignorable="d">
<UserControl.Resources>
<muxc:FontIconSource x:Key="MemClearGlyph"
FontFamily="{StaticResource CalculatorFontFamily}"
Glyph="&#xf754;"/>
<muxc:FontIconSource x:Key="MemPlusGlyph"
FontFamily="{StaticResource CalculatorFontFamily}"
Glyph="&#xf757;"/>
<muxc:FontIconSource x:Key="MemMinusGlyph"
FontFamily="{StaticResource CalculatorFontFamily}"
Glyph="&#xf758;"/>
<muxc:SwipeItems x:Key="MemorySwipeItems" Mode="Reveal">
<muxc:SwipeItem x:Uid="ClearMemorySwipeItem"
Background="{ThemeResource SystemControlBackgroundAccentBrush}"
IconSource="{StaticResource MemClearGlyph}"
Invoked="OnClearSwipeInvoked"/>
<muxc:SwipeItem x:Uid="MemPlusSwipeItem"
Background="{ThemeResource SystemControlBackgroundAccentBrush}"
IconSource="{StaticResource MemPlusGlyph}"
Invoked="OnMemoryAddSwipeInvoked"/>
<muxc:SwipeItem x:Uid="MemMinusSwipeItem"
Background="{ThemeResource SystemControlBackgroundAccentBrush}"
IconSource="{StaticResource MemMinusGlyph}"
Invoked="OnMemorySubtractSwipeInvoked"/>
</muxc:SwipeItems>
</UserControl.Resources>
<muxc:SwipeControl RightItems="{StaticResource MemorySwipeItems}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="HoverStates">
<VisualState x:Name="MemoryButtonsVisible">
<VisualState.Setters>
<Setter Target="MemoryHoverButtons.Opacity" Value="1"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="MemoryButtonsHidden"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Margin="0,2,14,0"
HorizontalAlignment="Right"
Style="{ThemeResource TitleTextBlockStyle}"
FontWeight="SemiBold"
AutomationProperties.AutomationId="MemoryItemValue"
FlowDirection="LeftToRight"
IsTextSelectionEnabled="True"
Text="{x:Bind Model.Value, Mode=OneWay}"
TextAlignment="Right"
TextReadingOrder="DetectFromContent"
TextWrapping="Wrap"/>
<Grid x:Name="MemoryHoverButtons"
Grid.Row="1"
Margin="0,0,10,2"
HorizontalAlignment="Right"
Opacity="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button x:Uid="ClearMemoryItemButton"
Style="{StaticResource MemoryHoverButtonStyle}"
Background="{ThemeResource SystemControlBackgroundAltMediumHighBrush}"
AutomationProperties.AutomationId="MClearButton"
Click="OnClearButtonClicked"
Content="MC"/>
<Button x:Uid="MemPlusItem"
Grid.Column="1"
Margin="0"
Style="{StaticResource MemoryHoverButtonStyle}"
Background="{ThemeResource SystemControlBackgroundAltMediumHighBrush}"
AutomationProperties.AutomationId="MAddButton"
Click="OnMemoryAddButtonClicked"
Content="M+"/>
<Button x:Uid="MemMinusItem"
Grid.Column="2"
Style="{StaticResource MemoryHoverButtonStyle}"
Background="{ThemeResource SystemControlBackgroundAltMediumHighBrush}"
AutomationProperties.AutomationId="MSubButton"
Click="OnMemorySubtractButtonClicked"
Content="M-"/>
</Grid>
</Grid>
</muxc:SwipeControl>
</UserControl>

View file

@ -0,0 +1,76 @@
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace CalculatorApp
{
[Windows.Foundation.Metadata.WebHostHidden]
public sealed partial class MemoryListItem : UserControl
{
public MemoryListItem()
{
InitializeComponent();
}
public CalculatorApp.ViewModel.MemoryItemViewModel Model
{
get { return (CalculatorApp.ViewModel.MemoryItemViewModel)GetValue(ModelProperty); }
set { SetValue(ModelProperty, value); }
}
// Using a DependencyProperty as the backing store for Model. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ModelProperty =
DependencyProperty.Register(nameof(Model), typeof(CalculatorApp.ViewModel.MemoryItemViewModel), typeof(MemoryListItem), new PropertyMetadata(default(CalculatorApp.ViewModel.MemoryItemViewModel)));
protected override void OnPointerEntered(Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
base.OnPointerEntered(e);
// Only show hover buttons when the user is using mouse or pen.
if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse
|| e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Pen)
{
VisualStateManager.GoToState(this, "MemoryButtonsVisible", true);
}
}
protected override void OnPointerExited(Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
base.OnPointerExited(e);
VisualStateManager.GoToState(this, "MemoryButtonsHidden", true);
}
private void OnMemoryAddButtonClicked(object sender, RoutedEventArgs e)
{
Model.MemoryAdd();
}
private void OnClearButtonClicked(object sender, RoutedEventArgs e)
{
Model.Clear();
}
private void OnMemorySubtractButtonClicked(object sender, RoutedEventArgs e)
{
Model.MemorySubtract();
}
private void OnClearSwipeInvoked(Microsoft.UI.Xaml.Controls.SwipeItem sender, Microsoft.UI.Xaml.Controls.SwipeItemInvokedEventArgs e)
{
Model.Clear();
}
private void OnMemoryAddSwipeInvoked(Microsoft.UI.Xaml.Controls.SwipeItem sender, Microsoft.UI.Xaml.Controls.SwipeItemInvokedEventArgs e)
{
Model.MemoryAdd();
}
private void OnMemorySubtractSwipeInvoked(Microsoft.UI.Xaml.Controls.SwipeItem sender, Microsoft.UI.Xaml.Controls.SwipeItemInvokedEventArgs e)
{
Model.MemorySubtract();
}
}
}

View file

@ -0,0 +1,120 @@
<UserControl x:Class="CalculatorApp.NumberPad"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="using:CalculatorApp.Common"
xmlns:controls="using:CalculatorApp.Controls"
xmlns:converters="using:CalculatorApp.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:CalculatorApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="ControlRoot"
d:DesignHeight="315"
d:DesignWidth="235"
mc:Ignorable="d">
<Grid x:Name="Root">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ErrorVisualStates">
<VisualState x:Name="NoErrorLayout"/>
<VisualState x:Name="ErrorLayout">
<VisualState.Setters>
<Setter Target="DecimalSeparatorButton.IsEnabled" Value="false"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<controls:CalculatorButton x:Name="Num0Button"
x:Uid="num0Button"
Grid.Row="3"
Grid.Column="1"
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
AutomationProperties.AutomationId="num0Button"
ButtonId="Zero"/>
<controls:CalculatorButton x:Name="Num1Button"
x:Uid="num1Button"
Grid.Row="2"
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
AutomationProperties.AutomationId="num1Button"
ButtonId="One"/>
<controls:CalculatorButton x:Name="Num2Button"
x:Uid="num2Button"
Grid.Row="2"
Grid.Column="1"
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
AutomationProperties.AutomationId="num2Button"
ButtonId="Two"/>
<controls:CalculatorButton x:Name="Num3Button"
x:Uid="num3Button"
Grid.Row="2"
Grid.Column="2"
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
AutomationProperties.AutomationId="num3Button"
ButtonId="Three"/>
<controls:CalculatorButton x:Name="Num4Button"
x:Uid="num4Button"
Grid.Row="1"
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
AutomationProperties.AutomationId="num4Button"
ButtonId="Four"/>
<controls:CalculatorButton x:Name="Num5Button"
x:Uid="num5Button"
Grid.Row="1"
Grid.Column="1"
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
AutomationProperties.AutomationId="num5Button"
ButtonId="Five"/>
<controls:CalculatorButton x:Name="Num6Button"
x:Uid="num6Button"
Grid.Row="1"
Grid.Column="2"
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
AutomationProperties.AutomationId="num6Button"
ButtonId="Six"/>
<controls:CalculatorButton x:Name="Num7Button"
x:Uid="num7Button"
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
AutomationProperties.AutomationId="num7Button"
ButtonId="Seven"/>
<controls:CalculatorButton x:Name="Num8Button"
x:Uid="num8Button"
Grid.Column="1"
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
AutomationProperties.AutomationId="num8Button"
ButtonId="Eight"/>
<controls:CalculatorButton x:Name="Num9Button"
x:Uid="num9Button"
Grid.Column="2"
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
AutomationProperties.AutomationId="num9Button"
ButtonId="Nine"/>
<!--
This is the only button in all of the app that should ever have a explicit reference to KeyboardShortcutManager in Xaml
this is needed because we need to have at least 1 reference from Xaml so the right metadata is generated for the
KeyboardShortcutManager class, otherwise the Xaml will stop parsing and the app won't boot therefore:
DO NOT REMOVE the common:KeyboardShortcutManager.Character from this element, it's value will be overwritten by the
string coming from the RESW file
-->
<controls:CalculatorButton x:Name="DecimalSeparatorButton"
x:Uid="decimalSeparatorButton"
Grid.Row="3"
Grid.Column="2"
Style="{Binding ElementName=ControlRoot, Path=ButtonStyle}"
common:KeyboardShortcutManager.Character="."
AutomationProperties.AutomationId="decimalSeparatorButton"
ButtonId="Decimal"
IsEnabled="{Binding IsDecimalEnabled}"/>
</Grid>
</UserControl>

View file

@ -0,0 +1,102 @@
using CalculatorApp.Common;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace CalculatorApp
{
public sealed partial class NumberPad : UserControl
{
public NumberPad()
{
m_isErrorVisualState = false;
InitializeComponent();
var localizationSettings = LocalizationSettings.GetInstance();
DecimalSeparatorButton.Content = localizationSettings.GetDecimalSeparator();
Num0Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('0');
Num1Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('1');
Num2Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('2');
Num3Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('3');
Num4Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('4');
Num5Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('5');
Num6Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('6');
Num7Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('7');
Num8Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('8');
Num9Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('9');
}
public Windows.UI.Xaml.Style ButtonStyle
{
get { return (Windows.UI.Xaml.Style)GetValue(ButtonStyleProperty); }
set { SetValue(ButtonStyleProperty, value); }
}
// Using a DependencyProperty as the backing store for ButtonStyle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ButtonStyleProperty =
DependencyProperty.Register(nameof(ButtonStyle), typeof(Windows.UI.Xaml.Style), typeof(NumberPad), new PropertyMetadata(default(Windows.UI.Xaml.Style)));
public CalculatorApp.Common.NumberBase CurrentRadixType
{
get { return (CalculatorApp.Common.NumberBase)GetValue(CurrentRadixTypeProperty); }
set { SetValue(CurrentRadixTypeProperty, value); }
}
// Using a DependencyProperty as the backing store for CurrentRadixType. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CurrentRadixTypeProperty =
DependencyProperty.Register(nameof(CurrentRadixType), typeof(CalculatorApp.Common.NumberBase), typeof(NumberPad), new PropertyMetadata(CalculatorApp.Common.NumberBase.DecBase, (sender, args) =>
{
var self = (NumberPad)sender;
self.OnCurrentRadixTypePropertyChanged((NumberBase)args.OldValue, (NumberBase)args.NewValue);
}));
public bool IsErrorVisualState
{
get { return m_isErrorVisualState; }
set
{
if (m_isErrorVisualState != value)
{
m_isErrorVisualState = value;
string newState = m_isErrorVisualState ? "ErrorLayout" : "NoErrorLayout";
VisualStateManager.GoToState(this, newState, false);
}
}
}
private void OnCurrentRadixTypePropertyChanged(NumberBase oldValue, NumberBase newValue)
{
Num0Button.IsEnabled = true;
Num1Button.IsEnabled = true;
Num2Button.IsEnabled = true;
Num3Button.IsEnabled = true;
Num4Button.IsEnabled = true;
Num5Button.IsEnabled = true;
Num6Button.IsEnabled = true;
Num7Button.IsEnabled = true;
Num8Button.IsEnabled = true;
Num9Button.IsEnabled = true;
if (newValue == NumberBase.BinBase)
{
Num2Button.IsEnabled = false;
Num3Button.IsEnabled = false;
Num4Button.IsEnabled = false;
Num5Button.IsEnabled = false;
Num6Button.IsEnabled = false;
Num7Button.IsEnabled = false;
Num8Button.IsEnabled = false;
Num9Button.IsEnabled = false;
}
else if (newValue == NumberBase.OctBase)
{
Num8Button.IsEnabled = false;
Num9Button.IsEnabled = false;
}
}
private bool m_isErrorVisualState;
}
}

View file

@ -0,0 +1,35 @@
<UserControl x:Class="CalculatorApp.OperatorsPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:CalculatorApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="315"
d:DesignWidth="235"
UseLayoutRounding="False"
mc:Ignorable="d">
<Grid>
<local:CalculatorStandardOperators x:Name="StandardOperators"
TabIndex="17"
IsEnabled="{x:Bind Model.IsStandard, Mode=OneWay}"
x:Load="{x:Bind Model.IsStandard, Mode=OneWay}"/>
<local:CalculatorScientificOperators x:Name="ScientificOperators"
TabIndex="16"
Visibility="{x:Bind Model.IsScientific, Mode=OneWay}"
IsEnabled="{x:Bind Model.IsScientific, Mode=OneWay}"
x:Load="False"/>
<local:CalculatorProgrammerBitFlipPanel x:Name="BitFlipPanel"
Visibility="{x:Bind Model.IsBinaryBitFlippingEnabled, Mode=OneWay}"
IsEnabled="{x:Bind Model.IsBinaryBitFlippingEnabled, Mode=OneWay}"
x:Load="False"/>
<local:CalculatorProgrammerRadixOperators x:Name="ProgrammerRadixOperators"
TabIndex="16"
Visibility="{x:Bind Model.AreProgrammerRadixOperatorsVisible, Mode=OneWay}"
IsEnabled="{x:Bind Model.IsProgrammer, Mode=OneWay}"
x:Load="False"/>
</Grid>
</UserControl>

View file

@ -0,0 +1,99 @@
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace CalculatorApp
{
[Windows.Foundation.Metadata.WebHostHidden]
public sealed partial class OperatorsPanel : UserControl
{
public CalculatorApp.ViewModel.StandardCalculatorViewModel Model
{
get => (CalculatorApp.ViewModel.StandardCalculatorViewModel)DataContext;
}
public OperatorsPanel()
{
InitializeComponent();
}
public bool IsBitFlipChecked
{
get { return (bool)GetValue(IsBitFlipCheckedProperty); }
set { SetValue(IsBitFlipCheckedProperty, value); }
}
// Using a DependencyProperty as the backing store for IsBitFlipChecked. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsBitFlipCheckedProperty =
DependencyProperty.Register(nameof(IsBitFlipChecked), typeof(bool), typeof(OperatorsPanel), new PropertyMetadata(default(bool), (sender, args) =>
{
var self = (OperatorsPanel)sender;
self.OnIsBitFlipCheckedPropertyChanged((bool)args.OldValue, (bool)args.NewValue);
}));
public bool IsErrorVisualState
{
get { return (bool)GetValue(IsErrorVisualStateProperty); }
set { SetValue(IsErrorVisualStateProperty, value); }
}
// Using a DependencyProperty as the backing store for IsErrorVisualState. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsErrorVisualStateProperty =
DependencyProperty.Register(nameof(IsErrorVisualState), typeof(bool), typeof(OperatorsPanel), new PropertyMetadata(default(bool), (sender, args) =>
{
var self = (OperatorsPanel)sender;
self.OnIsErrorVisualStatePropertyChanged((bool)args.OldValue, (bool)args.NewValue);
}));
void OnIsBitFlipCheckedPropertyChanged(bool oldValue, bool newValue)
{
if (newValue)
{
EnsureProgrammerBitFlipPanel();
}
}
private void OnIsErrorVisualStatePropertyChanged(bool oldValue, bool newValue)
{
if (Model.IsStandard)
{
StandardOperators.IsErrorVisualState = newValue;
}
else if (Model.IsScientific)
{
ScientificOperators.IsErrorVisualState = newValue;
}
else if (Model.IsProgrammer)
{
ProgrammerRadixOperators.IsErrorVisualState = newValue;
}
}
public void EnsureScientificOps()
{
if (ScientificOperators == null)
{
FindName("ScientificOperators");
}
}
public void EnsureProgrammerRadixOps()
{
if (ProgrammerRadixOperators == null)
{
FindName("ProgrammerRadixOperators");
}
ProgrammerRadixOperators.checkDefaultBitShift();
}
private void EnsureProgrammerBitFlipPanel()
{
if (BitFlipPanel == null)
{
this.FindName("BitFlipPanel");
}
}
}
}

View file

@ -0,0 +1,145 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
/* The AspectRatioTrigger class is a custom trigger for use with a VisualState. The trigger is designed to fire when the
height/width of the source FrameworkElement is greater than a specified threshold. In order to be a flexible class, it
exposes a NumeratorAspect property that can be either Height or Width. The property chosen will be the numerator when
calculating the ratio between the two properties. Additionally, users can configure whether the ratio must be strictly
greater than the threshold, or if equal should be considered acceptable for the state to trigger. */
using System;
using Windows.Foundation;
using Windows.UI.Xaml;
namespace CalculatorApp.Views.StateTriggers
{
public enum Aspect
{
Height,
Width
};
public sealed class AspectRatioTrigger : Windows.UI.Xaml.StateTriggerBase
{
public AspectRatioTrigger()
{
SetActive(false);
}
/* The source for which this class will respond to size changed events. */
public FrameworkElement Source
{
get { return (FrameworkElement)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
// Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register(nameof(Source), typeof(FrameworkElement), typeof(AspectRatioTrigger), new PropertyMetadata(default(FrameworkElement), (sender, args) =>
{
var self = (AspectRatioTrigger)sender;
self.OnSourcePropertyChanged((FrameworkElement)args.OldValue, (FrameworkElement)args.NewValue);
}));
/* Either Height or Width. The property will determine which aspect is used as the numerator when calculating
the aspect ratio. */
public Aspect NumeratorAspect
{
get { return (Aspect)GetValue(NumeratorAspectProperty); }
set { SetValue(NumeratorAspectProperty, value); }
}
// Using a DependencyProperty as the backing store for NumeratorAspect This enables animation, styling, binding, etc...
public static readonly DependencyProperty NumeratorAspectProperty =
DependencyProperty.Register(nameof(NumeratorAspect), typeof(Aspect), typeof(AspectRatioTrigger), new PropertyMetadata(default(Aspect)));
/* The threshold that will cause the trigger to fire when the aspect ratio exceeds this value. */
public double Threshold
{
get { return (double)GetValue(ThresholdProperty); }
set { SetValue(ThresholdProperty, value); }
}
// Using a DependencyProperty as the backing store for Threshold. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ThresholdProperty =
DependencyProperty.Register(nameof(Threshold), typeof(double), typeof(AspectRatioTrigger), new PropertyMetadata(0.0));
/* If true, the trigger will fire if the aspect ratio is greater than or equal to the threshold. */
public bool ActiveIfEqual
{
get { return (bool)GetValue(ActiveIfEqualProperty); }
set { SetValue(ActiveIfEqualProperty, value); }
}
// Using a DependencyProperty as the backing store for ActiveEqual. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ActiveIfEqualProperty =
DependencyProperty.Register(nameof(ActiveIfEqual), typeof(bool), typeof(AspectRatioTrigger), new PropertyMetadata(false));
~AspectRatioTrigger()
{
UnregisterSizeChanged(Source);
}
private void OnSourcePropertyChanged(FrameworkElement oldValue, FrameworkElement newValue)
{
UnregisterSizeChanged(oldValue);
RegisterSizeChanged(newValue);
}
private void RegisterSizeChanged(FrameworkElement element)
{
if (element == null)
{
return;
}
if (element != Source)
{
UnregisterSizeChanged(Source);
}
element.SizeChanged += OnSizeChanged;
}
private void UnregisterSizeChanged(FrameworkElement element)
{
if (element != null)
{
element.SizeChanged -= OnSizeChanged;
}
}
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateIsActive(e.NewSize);
}
private void UpdateIsActive(Size sourceSize)
{
double numerator, denominator;
if (NumeratorAspect == Aspect.Height)
{
numerator = sourceSize.Height;
denominator = sourceSize.Width;
}
else
{
numerator = sourceSize.Width;
denominator = sourceSize.Height;
}
bool isActive = false;
if (denominator > 0)
{
double ratio = numerator / denominator;
double threshold = Math.Abs(Threshold);
isActive = ((ratio > threshold) || (ActiveIfEqual && (ratio == threshold)));
}
SetActive(isActive);
}
}
}

View file

@ -0,0 +1,117 @@
<UserControl x:Class="CalculatorApp.CalculatorProgrammerDisplayPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="using:CalculatorApp.Common"
xmlns:controls="using:CalculatorApp.Controls"
xmlns:converters="using:CalculatorApp.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:CalculatorApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Margin="3,0,0,0"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
<UserControl.Resources>
<converters:BooleanNegationConverter x:Key="BooleanNegationConverter"/>
</UserControl.Resources>
<Grid x:Name="ProgrammerDisplay">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" MaxWidth="160"/>
<ColumnDefinition Width="0.01*"/>
<ColumnDefinition Width="1*" MaxWidth="80"/>
<ColumnDefinition Width="1*" MaxWidth="80"/>
<ColumnDefinition Width="1*" MaxWidth="80"/>
<ColumnDefinition Width="1*" MaxWidth="80"/>
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Layouts">
<VisualState x:Name="MinSizeLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowHeight="{StaticResource AppMinWindowHeight}" MinWindowWidth="{StaticResource AppMinWindowWidth}"/>
</VisualState.StateTriggers>
</VisualState>
<VisualState x:Name="DefaultLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowHeight="0" MinWindowWidth="0"/>
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ErrorVisualStates">
<VisualState x:Name="NoErrorLayout"/>
<VisualState x:Name="ErrorLayout">
<VisualState.Setters>
<Setter Target="QwordButton.IsEnabled" Value="False"/>
<Setter Target="DwordButton.IsEnabled" Value="False"/>
<Setter Target="WordButton.IsEnabled" Value="False"/>
<Setter Target="ByteButton.IsEnabled" Value="False"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid x:Uid="InputModeSelectionGroup"
Grid.Column="0"
AutomationProperties.HeadingLevel="Level1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MaxWidth="80"/>
<ColumnDefinition Width="1*" MaxWidth="80"/>
</Grid.ColumnDefinitions>
<RadioButton x:Name="FullKeypad"
x:Uid="fullKeypad"
Style="{StaticResource ProgKeypadRadioButtonStyle}"
AutomationProperties.AutomationId="fullKeypad"
Content="&#xe75f;"
IsChecked="{x:Bind Model.IsBitFlipChecked, Converter={StaticResource BooleanNegationConverter}, Mode=TwoWay}"/>
<RadioButton x:Name="BitFlip"
x:Uid="bitFlip"
Grid.Column="1"
Style="{StaticResource ProgKeypadRadioButtonStyle}"
AutomationProperties.AutomationId="bitFlip"
Content="&#xf7d0;"
IsChecked="{x:Bind Model.IsBitFlipChecked, Mode=TwoWay}"/>
</Grid>
<Button x:Name="QwordButton"
x:Uid="qwordButton"
Grid.Column="0"
Grid.ColumnSpan="7"
Style="{StaticResource ProgWordSizeButtonStyle}"
AutomationProperties.AutomationId="qwordButton"
Command="{x:Bind BitLengthButtonPressed, Mode=OneTime}"
CommandParameter="0"
Content="QWORD"/>
<Button x:Name="DwordButton"
x:Uid="dwordButton"
Grid.Column="0"
Grid.ColumnSpan="7"
Style="{StaticResource ProgWordSizeButtonStyle}"
AutomationProperties.AutomationId="dwordButton"
Command="{x:Bind BitLengthButtonPressed, Mode=OneTime}"
CommandParameter="1"
Content="DWORD"
Visibility="Collapsed"/>
<Button x:Name="WordButton"
x:Uid="wordButton"
Grid.Column="0"
Grid.ColumnSpan="7"
Style="{StaticResource ProgWordSizeButtonStyle}"
AutomationProperties.AutomationId="wordButton"
Command="{x:Bind BitLengthButtonPressed, Mode=OneTime}"
CommandParameter="2"
Content="WORD"
Visibility="Collapsed"/>
<Button x:Name="ByteButton"
x:Uid="byteButton"
Grid.Column="0"
Grid.ColumnSpan="7"
Style="{StaticResource ProgWordSizeButtonStyle}"
AutomationProperties.AutomationId="byteButton"
Command="{x:Bind BitLengthButtonPressed, Mode=OneTime}"
CommandParameter="3"
Content="BYTE"
Visibility="Collapsed"/>
</Grid>
</UserControl>

View file

@ -0,0 +1,97 @@
using System.Diagnostics;
using System.Windows.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace CalculatorApp
{
[Windows.Foundation.Metadata.WebHostHidden]
public sealed partial class CalculatorProgrammerDisplayPanel : UserControl
{
public ICommand BitLengthButtonPressed
{
get
{
if (donotuse_BitLengthButtonPressed == null)
{
donotuse_BitLengthButtonPressed =
new Common.DelegateCommand<CalculatorProgrammerDisplayPanel>(this, OnBitLengthButtonPressed);
}
return donotuse_BitLengthButtonPressed;
}
}
private ICommand donotuse_BitLengthButtonPressed;
public ViewModel.StandardCalculatorViewModel Model
{
get
{
Debug.Assert(DataContext as ViewModel.StandardCalculatorViewModel != null, "static_cast result must NOT be null");
return DataContext as ViewModel.StandardCalculatorViewModel;
}
}
public bool IsErrorVisualState
{
get
{
return m_isErrorVisualState;
}
set
{
if (m_isErrorVisualState != value)
{
m_isErrorVisualState = value;
string newState = m_isErrorVisualState ? "ErrorLayout" : "NoErrorLayout";
VisualStateManager.GoToState(this, newState, false);
}
}
}
public CalculatorProgrammerDisplayPanel()
{
m_isErrorVisualState = false;
InitializeComponent();
}
private void OnBitLengthButtonPressed(object parameter)
{
string buttonId = parameter.ToString();
QwordButton.Visibility = Visibility.Collapsed;
DwordButton.Visibility = Visibility.Collapsed;
WordButton.Visibility = Visibility.Collapsed;
ByteButton.Visibility = Visibility.Collapsed;
if (buttonId == "0")
{
Model.ValueBitLength = Common.BitLength.BitLengthDWord;
DwordButton.Visibility = Visibility.Visible;
DwordButton.Focus(FocusState.Programmatic);
}
else if (buttonId == "1")
{
Model.ValueBitLength = Common.BitLength.BitLengthWord;
WordButton.Visibility = Visibility.Visible;
WordButton.Focus(FocusState.Programmatic);
}
else if (buttonId == "2")
{
Model.ValueBitLength = Common.BitLength.BitLengthByte;
ByteButton.Visibility = Visibility.Visible;
ByteButton.Focus(FocusState.Programmatic);
}
else if (buttonId == "3")
{
Model.ValueBitLength = Common.BitLength.BitLengthQWord;
QwordButton.Visibility = Visibility.Visible;
QwordButton.Focus(FocusState.Programmatic);
}
}
private bool m_isErrorVisualState;
}
}

View file

@ -0,0 +1,115 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Windows.Foundation;
using Windows.UI.Xaml;
namespace CalculatorApp.Views.StateTriggers
{
public sealed class ControlSizeTrigger : Windows.UI.Xaml.StateTriggerBase
{
public ControlSizeTrigger()
{
SetActive(false);
}
public FrameworkElement Source
{
get { return (FrameworkElement)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
// Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register(nameof(Source), typeof(FrameworkElement), typeof(ControlSizeTrigger), new PropertyMetadata(default(FrameworkElement), (sender, args) =>
{
var self = (ControlSizeTrigger)sender;
self.OnSourcePropertyChanged((FrameworkElement)args.OldValue, (FrameworkElement)args.NewValue);
}));
public double MinHeight
{
get { return (double)GetValue(MinHeightProperty); }
set { SetValue(MinHeightProperty, value); }
}
// Using a DependencyProperty as the backing store for MinHeight. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MinHeightProperty =
DependencyProperty.Register(nameof(MinHeight), typeof(double), typeof(ControlSizeTrigger), new PropertyMetadata(-1));
public double MinWidth
{
get { return (double)GetValue(MinWidthProperty); }
set { SetValue(MinWidthProperty, value); }
}
// Using a DependencyProperty as the backing store for MinWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MinWidthProperty =
DependencyProperty.Register(nameof(MinWidth), typeof(double), typeof(ControlSizeTrigger), new PropertyMetadata(-1));
~ControlSizeTrigger()
{
// CSHARP_MIGRATION: TODO:
// finalization will happen on a finalizer's thread.
// to prevent crashing the entire app, switch to UI thread to do unregistering work
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
UnregisterSizeChanged(Source);
})
.AsTask()
.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
}
private void OnSourcePropertyChanged(FrameworkElement oldValue, FrameworkElement newValue)
{
UnregisterSizeChanged(oldValue);
RegisterSizeChanged(newValue);
}
private void RegisterSizeChanged(FrameworkElement element)
{
if (element == null)
{
return;
}
if (element != Source)
{
UnregisterSizeChanged(Source);
}
element.SizeChanged += OnSizeChanged;
UpdateIsActive(element.RenderSize);
}
private void UnregisterSizeChanged(FrameworkElement element)
{
if (element != null)
{
element.SizeChanged -= OnSizeChanged;
}
}
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateIsActive(e.NewSize);
}
private void UpdateIsActive(Size sourceSize)
{
if (MinHeight >= 0)
{
SetActive(sourceSize.Height >= MinHeight && (MinWidth < 0 || sourceSize.Width >= MinWidth));
}
else
{
SetActive(MinWidth >= 0 && sourceSize.Width >= MinWidth);
}
}
}
}

View file

@ -0,0 +1,107 @@
<UserControl x:Class="CalculatorApp.SupplementaryResults"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="using:CalculatorApp.Common"
xmlns:controls="using:CalculatorApp.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:designdata="using:CalculatorApp.DesignData"
xmlns:local="using:CalculatorApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:CalculatorApp.ViewModel"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
<UserControl.Resources>
<DataTemplate x:Name="SupplementaryValueTemplate" x:DataType="vm:SupplementaryResult">
<StackPanel Margin="0" Orientation="Horizontal">
<TextBlock Margin="0,0,4,0"
Padding="0"
VerticalAlignment="Bottom"
Style="{ThemeResource BaseTextBlockStyle}"
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
AutomationProperties.AutomationId="SupplementaryResultValue"
IsTextScaleFactorEnabled="False"
Text="{x:Bind Value}"/>
<TextBlock Margin="0,0,16,0"
Padding="0"
VerticalAlignment="Bottom"
Style="{ThemeResource BodyTextBlockStyle}"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
AutomationProperties.AutomationId="SupplementaryResultUnit"
IsTextScaleFactorEnabled="False"
Text="{x:Bind Unit.Abbreviation}"/>
</StackPanel>
</DataTemplate>
<local:DelighterUnitToStyleConverter x:Key="DelighterUnitStyleConverter"/>
<DataTemplate x:Name="DelighterValueTemplate" x:DataType="vm:SupplementaryResult">
<StackPanel Margin="0" Orientation="Horizontal">
<TextBlock VerticalAlignment="Bottom"
Style="{Binding Unit, Converter={StaticResource DelighterUnitStyleConverter}, Mode=OneTime}"
AutomationProperties.AutomationId="DelighterResultGlyph"/>
<TextBlock Margin="-2,0,4,0"
Padding="0"
VerticalAlignment="Bottom"
Style="{ThemeResource BaseTextBlockStyle}"
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
AutomationProperties.AutomationId="DelighterResultValue"
IsTextScaleFactorEnabled="False"
Text="{x:Bind Value}"/>
<TextBlock Margin="0"
Padding="0"
VerticalAlignment="Bottom"
Style="{ThemeResource BodyTextBlockStyle}"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
AutomationProperties.AutomationId="DelighterResultUnit"
IsTextScaleFactorEnabled="False"
Text="{x:Bind Unit.Abbreviation}"/>
</StackPanel>
</DataTemplate>
<local:SupplementaryResultDataTemplateSelector x:Key="ResultTemplateSelector"
DelighterTemplate="{StaticResource DelighterValueTemplate}"
RegularTemplate="{StaticResource SupplementaryValueTemplate}"/>
<Style x:Key="SupplementaryValuesStyle" TargetType="controls:SupplementaryItemsControl">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:SupplementaryItemsControl">
<ItemsPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerTransitions">
<Setter.Value>
<TransitionCollection/>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<local:SupplementaryResultNoOverflowStackPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<StackPanel>
<TextBlock x:Uid="SupplementaryResultsHeader"
Margin="0,0,0,-6"
HorizontalAlignment="Left"
Style="{ThemeResource CaptionTextBlockStyle}"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
IsTextScaleFactorEnabled="False"
Text="Also equal to"/>
<controls:SupplementaryItemsControl x:Name="SupplementaryValues"
MinHeight="27"
HorizontalAlignment="Left"
Style="{ThemeResource SupplementaryValuesStyle}"
IsTextScaleFactorEnabled="False"
ItemTemplateSelector="{StaticResource ResultTemplateSelector}"
ItemsSource="{x:Bind Results, Mode=OneWay}"/>
</StackPanel>
</UserControl>

View file

@ -0,0 +1,115 @@
using CalculatorApp.ViewModel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace CalculatorApp
{
public sealed class DelighterUnitToStyleConverter : Windows.UI.Xaml.Data.IValueConverter
{
public DelighterUnitToStyleConverter()
{
m_delighters = new Windows.UI.Xaml.ResourceDictionary();
m_delighters.Source = new Uri(@"ms-appx:///Views/DelighterUnitStyles.xaml");
}
public object Convert(object value, Type targetType, object parameter, string language)
{
Unit unit = (Unit)value;
Debug.Assert(unit.IsModelUnitWhimsical());
if (!unit.IsModelUnitWhimsical())
{
return null;
}
string key = $"Unit_{unit.ModelUnitID()}";
return (Style)m_delighters[key];
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
// We never use convert back, only one way binding supported
Debug.Assert(false);
return null;
}
private Windows.UI.Xaml.ResourceDictionary m_delighters;
}
public sealed class SupplementaryResultDataTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
{
public SupplementaryResultDataTemplateSelector()
{ }
public Windows.UI.Xaml.DataTemplate RegularTemplate
{
get => m_regularTemplate;
set => m_regularTemplate = value;
}
public Windows.UI.Xaml.DataTemplate DelighterTemplate
{
get => m_delighterTemplate;
set => m_delighterTemplate = value;
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
SupplementaryResult result = (SupplementaryResult)item;
if (result.IsWhimsical())
{
return DelighterTemplate;
}
else
{
return RegularTemplate;
}
}
private Windows.UI.Xaml.DataTemplate m_regularTemplate;
private Windows.UI.Xaml.DataTemplate m_delighterTemplate;
}
public sealed class SupplementaryResultNoOverflowStackPanel : CalculatorApp.Controls.HorizontalNoOverflowStackPanel
{
protected override bool ShouldPrioritizeLastItem()
{
if (Children.Count == 0)
{
return false;
}
var lastChild = Children[Children.Count - 1] as FrameworkElement;
if (lastChild == null)
{
return false;
}
var suppResult = lastChild.DataContext as SupplementaryResult;
return suppResult == null ? false : suppResult.IsWhimsical();
}
}
[Windows.Foundation.Metadata.WebHostHidden]
public sealed partial class SupplementaryResults : UserControl
{
public SupplementaryResults()
{
InitializeComponent();
}
public IEnumerable<ViewModel.SupplementaryResult> Results
{
get { return (IEnumerable<ViewModel.SupplementaryResult>)GetValue(ResultsProperty); }
set { SetValue(ResultsProperty, value); }
}
// Using a DependencyProperty as the backing store for Results. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ResultsProperty =
DependencyProperty.Register(nameof(Results), typeof(IEnumerable<ViewModel.SupplementaryResult>), typeof(SupplementaryResult), new PropertyMetadata(null));
}
}

View file

@ -0,0 +1,60 @@
<UserControl x:Class="CalculatorApp.TitleBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="LayoutRoot"
Height="32"
HorizontalAlignment="Stretch">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="WindowFocusStates">
<VisualState x:Name="WindowFocused"/>
<VisualState x:Name="WindowNotFocused">
<VisualState.Setters>
<Setter Target="AppName.Foreground" Value="{ThemeResource SystemControlForegroundChromeDisabledLowBrush}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="AOTStates">
<VisualState x:Name="AOTNormalState"/>
<VisualState x:Name="AOTMiniState">
<VisualState.Setters>
<Setter Target="AppName.Visibility" Value="Collapsed"/>
<Setter Target="ExitAlwaysOnTopButton.Visibility" Value="Visible"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid x:Name="BackgroundElement" Background="Transparent">
<TextBlock x:Name="AppName"
x:Uid="AppName"
Margin="12,0,12,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="{ThemeResource TitleBarForegroundBaseHighBrush}"
FontSize="12"
TextTrimming="CharacterEllipsis"/>
</Grid>
<Button x:Name="ExitAlwaysOnTopButton"
x:Uid="ExitAlwaysOnTopButton"
Width="46"
Height="Auto"
HorizontalAlignment="Left"
HorizontalContentAlignment="Center"
Style="{ThemeResource CommandBarFlyoutEllipsisButtonStyle}"
Background="Transparent"
FontFamily="{StaticResource CalculatorFontFamily}"
FontSize="14"
FontWeight="Thin"
AutomationProperties.AutomationId="ExitAlwaysOnTopButton"
Click="AlwaysOnTopButton_Click"
Content="&#xEE47;"
Visibility="Collapsed"
x:Load="False">
<Button.KeyboardAccelerators>
<KeyboardAccelerator Key="Down" Modifiers="Menu"/>
</Button.KeyboardAccelerators>
</Button>
</Grid>
</UserControl>

View file

@ -0,0 +1,209 @@
using System;
using Windows.ApplicationModel.Core;
using Windows.System.Profile;
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace CalculatorApp
{
public sealed partial class TitleBar : UserControl
{
public TitleBar()
{
m_coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
m_uiSettings = new UISettings();
m_accessibilitySettings = new AccessibilitySettings();
InitializeComponent();
m_coreTitleBar.ExtendViewIntoTitleBar = true;
Window.Current.SetTitleBar(BackgroundElement);
Loaded += OnLoaded;
Unloaded += OnUnloaded;
#if IS_STORE_BUILD
AppName.Text = AppResourceProvider.GetInstance().GetResourceString("AppName");
#else
AppName.Text = AppResourceProvider.GetInstance().GetResourceString("DevAppName");
#endif
}
public bool IsAlwaysOnTopMode
{
get { return (bool)GetValue(IsAlwaysOnTopModeProperty); }
set { SetValue(IsAlwaysOnTopModeProperty, value); }
}
// Using a DependencyProperty as the backing store for IsAlwaysOnTopMode. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsAlwaysOnTopModeProperty =
DependencyProperty.Register(nameof(IsAlwaysOnTopMode), typeof(bool), typeof(TitleBar), new PropertyMetadata(default(bool), (sender, args) =>
{
var self = (TitleBar)sender;
self.OnIsAlwaysOnTopModePropertyChanged((bool)args.OldValue, (bool)args.NewValue);
}));
public event Windows.UI.Xaml.RoutedEventHandler AlwaysOnTopClick;
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Register events
m_coreTitleBar.IsVisibleChanged += CoreTitleBarIsVisibleChanged;
m_coreTitleBar.LayoutMetricsChanged += CoreTitleBarLayoutMetricsChanged;
m_uiSettings.ColorValuesChanged += ColorValuesChanged;
m_accessibilitySettings.HighContrastChanged += OnHighContrastChanged;
Window.Current.Activated += OnWindowActivated;
// Set properties
SetTitleBarControlColors();
SetTitleBarHeightAndPadding();
// As of Windows 10 1903: when an app runs on a PC (without Tablet mode activated)
// properties of CoreApplicationViewTitleBar aren't initialized during the first seconds after launch.
var forceDisplay = AnalyticsInfo.VersionInfo.DeviceFamily == "Windows.Desktop"
&& UIViewSettings.GetForCurrentView().UserInteractionMode == UserInteractionMode.Mouse;
SetTitleBarVisibility(forceDisplay);
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
// Unregister events
m_coreTitleBar.LayoutMetricsChanged -= CoreTitleBarLayoutMetricsChanged;
m_coreTitleBar.IsVisibleChanged -= CoreTitleBarIsVisibleChanged;
m_uiSettings.ColorValuesChanged -= ColorValuesChanged;
m_accessibilitySettings.HighContrastChanged -= OnHighContrastChanged;
Window.Current.Activated -= OnWindowActivated;
}
private void CoreTitleBarIsVisibleChanged(CoreApplicationViewTitleBar cTitleBar, object args)
{
SetTitleBarVisibility(false);
}
private void CoreTitleBarLayoutMetricsChanged(CoreApplicationViewTitleBar cTitleBar, object args)
{
SetTitleBarHeightAndPadding();
}
private void SetTitleBarVisibility(bool forceDisplay)
{
LayoutRoot.Visibility =
forceDisplay || m_coreTitleBar.IsVisible || IsAlwaysOnTopMode ? Visibility.Visible : Visibility.Collapsed;
}
private void SetTitleBarHeightAndPadding()
{
if (m_coreTitleBar.Height == 0)
{
// The titlebar isn't init
return;
}
double leftAddition = 0;
double rightAddition = 0;
if (FlowDirection == FlowDirection.LeftToRight)
{
leftAddition = m_coreTitleBar.SystemOverlayLeftInset;
rightAddition = m_coreTitleBar.SystemOverlayRightInset;
}
else
{
leftAddition = m_coreTitleBar.SystemOverlayRightInset;
leftAddition = m_coreTitleBar.SystemOverlayLeftInset;
}
LayoutRoot.Padding = new Thickness(leftAddition, 0, rightAddition, 0);
LayoutRoot.Height = m_coreTitleBar.Height;
}
private void ColorValuesChanged(Windows.UI.ViewManagement.UISettings sender, object e)
{
_ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() => { SetTitleBarControlColors(); }));
}
private void SetTitleBarControlColors()
{
var applicationView = ApplicationView.GetForCurrentView();
if (applicationView == null)
{
return;
}
var applicationTitleBar = applicationView.TitleBar;
if (applicationTitleBar == null)
{
return;
}
if (m_accessibilitySettings.HighContrast)
{
// Reset to use default colors.
applicationTitleBar.ButtonBackgroundColor = null;
applicationTitleBar.ButtonForegroundColor = null;
applicationTitleBar.ButtonInactiveBackgroundColor = null;
applicationTitleBar.ButtonInactiveForegroundColor = null;
applicationTitleBar.ButtonHoverBackgroundColor = null;
applicationTitleBar.ButtonHoverForegroundColor = null;
applicationTitleBar.ButtonPressedBackgroundColor = null;
applicationTitleBar.ButtonPressedForegroundColor = null;
}
else
{
Color bgColor = Colors.Transparent;
Color fgColor = ((SolidColorBrush)Application.Current.Resources["SystemControlPageTextBaseHighBrush"]).Color;
Color inactivefgColor =
((SolidColorBrush)Application.Current.Resources["SystemControlForegroundChromeDisabledLowBrush"]).Color;
Color hoverbgColor = ((SolidColorBrush)Application.Current.Resources["SystemControlBackgroundListLowBrush"]).Color;
Color hoverfgColor = ((SolidColorBrush)Application.Current.Resources["SystemControlForegroundBaseHighBrush"]).Color;
Color pressedbgColor = ((SolidColorBrush)Application.Current.Resources["SystemControlBackgroundListMediumBrush"]).Color;
Color pressedfgCoolor = ((SolidColorBrush)Application.Current.Resources["SystemControlForegroundBaseHighBrush"]).Color;
applicationTitleBar.ButtonBackgroundColor = bgColor;
applicationTitleBar.ButtonForegroundColor = fgColor;
applicationTitleBar.ButtonInactiveBackgroundColor = bgColor;
applicationTitleBar.ButtonInactiveForegroundColor = inactivefgColor;
applicationTitleBar.ButtonHoverBackgroundColor = hoverbgColor;
applicationTitleBar.ButtonHoverForegroundColor = hoverfgColor;
applicationTitleBar.ButtonPressedBackgroundColor = pressedbgColor;
applicationTitleBar.ButtonPressedForegroundColor = pressedfgCoolor;
}
}
private void OnHighContrastChanged(Windows.UI.ViewManagement.AccessibilitySettings sender, object args)
{
_ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
{
SetTitleBarControlColors();
SetTitleBarVisibility(false);
}));
}
private void OnWindowActivated(object sender, WindowActivatedEventArgs e)
{
VisualStateManager.GoToState(
this, e.WindowActivationState == CoreWindowActivationState.Deactivated ? WindowNotFocused.Name : WindowFocused.Name, false);
}
private void OnIsAlwaysOnTopModePropertyChanged(bool oldValue, bool newValue)
{
SetTitleBarVisibility(false);
VisualStateManager.GoToState(this, newValue ? "AOTMiniState" : "AOTNormalState", false);
}
private void AlwaysOnTopButton_Click(object sender, RoutedEventArgs e)
{
AlwaysOnTopClick(this, e);
}
private Windows.ApplicationModel.Core.CoreApplicationViewTitleBar m_coreTitleBar;
private Windows.UI.ViewManagement.UISettings m_uiSettings;
private Windows.UI.ViewManagement.AccessibilitySettings m_accessibilitySettings;
}
}

View file

@ -0,0 +1,190 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.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()
{
var that = this;
TaskCompletionSource<object> tsource = new TaskCompletionSource<object>();
_ = m_coreDispatcher.RunAsync(CoreDispatcherPriority.Low, new DispatchedHandler(() =>
{
KeyboardShortcutManager.OnWindowClosed(that.m_viewId);
Window.Current.Content = null;
that.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());
that.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)
{
object retval;
if (m_runtimeServicesMap.TryGetValue(serviceId.Name, out retval))
{
return retval;
}
else
{
return null;
}
}
private Windows.UI.Core.CoreWindow m_currentWindow;
private Windows.UI.Core.CoreDispatcher m_coreDispatcher;
private Windows.UI.Xaml.Controls.Frame m_frame;
private int m_viewId;
private WeakReference m_parent;
private Dictionary<string, object> m_runtimeServicesMap = new Dictionary<string, object>();
private List<Action> m_onWindowClosingHandlers = new List<Action>();
}
}