Refactor NavigationHelper

This commit is contained in:
Geoffroy BONNEVILLE
2021-06-14 19:38:48 +02:00
parent e917bd249f
commit 77b5927d46

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Windows.Foundation.Metadata;
using Windows.System; using Windows.System;
using Windows.UI.Core; using Windows.UI.Core;
using Windows.UI.Xaml; using Windows.UI.Xaml;
@@ -53,11 +54,11 @@ namespace ModernKeePass.Common
/// } /// }
/// </code> /// </code>
/// </example> /// </example>
[Windows.Foundation.Metadata.WebHostHidden] [WebHostHidden]
public class NavigationHelper : DependencyObject public class NavigationHelper : DependencyObject
{ {
private Page Page { get; set; } private Page Page { get; set; }
private Frame Frame { get { return this.Page.Frame; } } private Frame Frame => Page.Frame;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NavigationHelper"/> class. /// Initializes a new instance of the <see cref="NavigationHelper"/> class.
@@ -67,31 +68,31 @@ namespace ModernKeePass.Common
/// navigation requests only occur when the page is occupying the entire window.</param> /// navigation requests only occur when the page is occupying the entire window.</param>
public NavigationHelper(Page page) public NavigationHelper(Page page)
{ {
this.Page = page; Page = page;
// When this page is part of the visual tree make two changes: // When this page is part of the visual tree make two changes:
// 1) Map application view state to visual state for the page // 1) Map application view state to visual state for the page
// 2) Handle hardware navigation requests // 2) Handle hardware navigation requests
this.Page.Loaded += (sender, e) => Page.Loaded += (sender, e) =>
{ {
#if WINDOWS_PHONE_APP #if WINDOWS_PHONE_APP
Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed; Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
#else #else
// Keyboard and mouse navigation only apply when occupying the entire window // Keyboard and mouse navigation only apply when occupying the entire window
if (Page.ActualHeight == Window.Current.Bounds.Height && if (Page.ActualHeight.Equals(Window.Current.Bounds.Height) &&
Page.ActualWidth == Window.Current.Bounds.Width) Page.ActualWidth.Equals(Window.Current.Bounds.Width))
{ {
// Listen to the window directly so focus isn't required // Listen to the window directly so focus isn't required
Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated += Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated +=
CoreDispatcher_AcceleratorKeyActivated; CoreDispatcher_AcceleratorKeyActivated;
Window.Current.CoreWindow.PointerPressed += Window.Current.CoreWindow.PointerPressed +=
this.CoreWindow_PointerPressed; CoreWindow_PointerPressed;
} }
#endif #endif
}; };
// Undo the same changes when the page is no longer visible // Undo the same changes when the page is no longer visible
this.Page.Unloaded += (sender, e) => Page.Unloaded += (sender, e) =>
{ {
#if WINDOWS_PHONE_APP #if WINDOWS_PHONE_APP
Windows.Phone.UI.Input.HardwareButtons.BackPressed -= HardwareButtons_BackPressed; Windows.Phone.UI.Input.HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
@@ -99,15 +100,15 @@ namespace ModernKeePass.Common
Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated -= Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated -=
CoreDispatcher_AcceleratorKeyActivated; CoreDispatcher_AcceleratorKeyActivated;
Window.Current.CoreWindow.PointerPressed -= Window.Current.CoreWindow.PointerPressed -=
this.CoreWindow_PointerPressed; CoreWindow_PointerPressed;
#endif #endif
}; };
} }
#region Navigation support #region Navigation support
RelayCommand _goBackCommand; private RelayCommand _goBackCommand;
RelayCommand _goForwardCommand; private RelayCommand _goForwardCommand;
/// <summary> /// <summary>
/// <see cref="RelayCommand"/> used to bind to the back Button's Command property /// <see cref="RelayCommand"/> used to bind to the back Button's Command property
@@ -121,13 +122,7 @@ namespace ModernKeePass.Common
{ {
get get
{ {
if (_goBackCommand == null) return _goBackCommand ?? (_goBackCommand = new RelayCommand(GoBack, CanGoBack));
{
_goBackCommand = new RelayCommand(
() => this.GoBack(),
() => this.CanGoBack());
}
return _goBackCommand;
} }
set set
{ {
@@ -141,19 +136,7 @@ namespace ModernKeePass.Common
/// The <see cref="RelayCommand"/> is set up to use the virtual method <see cref="GoForward"/> /// The <see cref="RelayCommand"/> is set up to use the virtual method <see cref="GoForward"/>
/// as the Execute Action and <see cref="CanGoForward"/> for CanExecute. /// as the Execute Action and <see cref="CanGoForward"/> for CanExecute.
/// </summary> /// </summary>
public RelayCommand GoForwardCommand public RelayCommand GoForwardCommand => _goForwardCommand ?? (_goForwardCommand = new RelayCommand(GoForward, CanGoForward));
{
get
{
if (_goForwardCommand == null)
{
_goForwardCommand = new RelayCommand(
() => this.GoForward(),
() => this.CanGoForward());
}
return _goForwardCommand;
}
}
/// <summary> /// <summary>
/// Virtual method used by the <see cref="GoBackCommand"/> property /// Virtual method used by the <see cref="GoBackCommand"/> property
@@ -165,7 +148,7 @@ namespace ModernKeePass.Common
/// </returns> /// </returns>
public virtual bool CanGoBack() public virtual bool CanGoBack()
{ {
return this.Frame != null && this.Frame.CanGoBack; return Frame != null && Frame.CanGoBack;
} }
/// <summary> /// <summary>
/// Virtual method used by the <see cref="GoForwardCommand"/> property /// Virtual method used by the <see cref="GoForwardCommand"/> property
@@ -177,7 +160,7 @@ namespace ModernKeePass.Common
/// </returns> /// </returns>
public virtual bool CanGoForward() public virtual bool CanGoForward()
{ {
return this.Frame != null && this.Frame.CanGoForward; return Frame != null && Frame.CanGoForward;
} }
/// <summary> /// <summary>
@@ -186,7 +169,7 @@ namespace ModernKeePass.Common
/// </summary> /// </summary>
public virtual void GoBack() public virtual void GoBack()
{ {
if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack(); if (Frame != null && Frame.CanGoBack) Frame.GoBack();
} }
/// <summary> /// <summary>
/// Virtual method used by the <see cref="GoForwardCommand"/> property /// Virtual method used by the <see cref="GoForwardCommand"/> property
@@ -194,7 +177,7 @@ namespace ModernKeePass.Common
/// </summary> /// </summary>
public virtual void GoForward() public virtual void GoForward()
{ {
if (this.Frame != null && this.Frame.CanGoForward) this.Frame.GoForward(); if (Frame != null && Frame.CanGoForward) Frame.GoForward();
} }
#if WINDOWS_PHONE_APP #if WINDOWS_PHONE_APP
@@ -232,26 +215,26 @@ namespace ModernKeePass.Common
(int)virtualKey == 166 || (int)virtualKey == 167)) (int)virtualKey == 166 || (int)virtualKey == 167))
{ {
var coreWindow = Window.Current.CoreWindow; var coreWindow = Window.Current.CoreWindow;
var downState = CoreVirtualKeyStates.Down; const CoreVirtualKeyStates downState = CoreVirtualKeyStates.Down;
bool menuKey = (coreWindow.GetKeyState(VirtualKey.Menu) & downState) == downState; var menuKey = (coreWindow.GetKeyState(VirtualKey.Menu) & downState) == downState;
bool controlKey = (coreWindow.GetKeyState(VirtualKey.Control) & downState) == downState; var controlKey = (coreWindow.GetKeyState(VirtualKey.Control) & downState) == downState;
bool shiftKey = (coreWindow.GetKeyState(VirtualKey.Shift) & downState) == downState; var shiftKey = (coreWindow.GetKeyState(VirtualKey.Shift) & downState) == downState;
bool noModifiers = !menuKey && !controlKey && !shiftKey; var noModifiers = !menuKey && !controlKey && !shiftKey;
bool onlyAlt = menuKey && !controlKey && !shiftKey; var onlyAlt = menuKey && !controlKey && !shiftKey;
if (((int)virtualKey == 166 && noModifiers) || if ((int)virtualKey == 166 && noModifiers ||
(virtualKey == VirtualKey.Left && onlyAlt)) virtualKey == VirtualKey.Left && onlyAlt)
{ {
// When the previous key or Alt+Left are pressed navigate back // When the previous key or Alt+Left are pressed navigate back
e.Handled = true; e.Handled = true;
this.GoBackCommand.Execute(null); GoBackCommand.Execute(null);
} }
else if (((int)virtualKey == 167 && noModifiers) || else if ((int)virtualKey == 167 && noModifiers ||
(virtualKey == VirtualKey.Right && onlyAlt)) virtualKey == VirtualKey.Right && onlyAlt)
{ {
// When the next key or Alt+Right are pressed navigate forward // When the next key or Alt+Right are pressed navigate forward
e.Handled = true; e.Handled = true;
this.GoForwardCommand.Execute(null); GoForwardCommand.Execute(null);
} }
} }
} }
@@ -272,14 +255,14 @@ namespace ModernKeePass.Common
if (properties.IsLeftButtonPressed || properties.IsRightButtonPressed || if (properties.IsLeftButtonPressed || properties.IsRightButtonPressed ||
properties.IsMiddleButtonPressed) return; properties.IsMiddleButtonPressed) return;
// If back or foward are pressed (but not both) navigate appropriately // If back or forward are pressed (but not both) navigate appropriately
bool backPressed = properties.IsXButton1Pressed; var backPressed = properties.IsXButton1Pressed;
bool forwardPressed = properties.IsXButton2Pressed; var forwardPressed = properties.IsXButton2Pressed;
if (backPressed ^ forwardPressed) if (backPressed ^ forwardPressed)
{ {
e.Handled = true; e.Handled = true;
if (backPressed) this.GoBackCommand.Execute(null); if (backPressed) GoBackCommand.Execute(null);
if (forwardPressed) this.GoForwardCommand.Execute(null); if (forwardPressed) GoForwardCommand.Execute(null);
} }
} }
#endif #endif
@@ -288,7 +271,7 @@ namespace ModernKeePass.Common
#region Process lifetime management #region Process lifetime management
private String _pageKey; private string _pageKey;
/// <summary> /// <summary>
/// Register this event on the current page to populate the page /// Register this event on the current page to populate the page
@@ -300,7 +283,7 @@ namespace ModernKeePass.Common
/// Register this event on the current page to preserve /// Register this event on the current page to preserve
/// state associated with the current page in case the /// state associated with the current page in case the
/// application is suspended or the page is discarded from /// application is suspended or the page is discarded from
/// the navigaqtion cache. /// the navigation cache.
/// </summary> /// </summary>
public event SaveStateEventHandler SaveState; public event SaveStateEventHandler SaveState;
@@ -313,15 +296,15 @@ namespace ModernKeePass.Common
/// property provides the group to be displayed.</param> /// property provides the group to be displayed.</param>
public void OnNavigatedTo(NavigationEventArgs e) public void OnNavigatedTo(NavigationEventArgs e)
{ {
var frameState = SuspensionManager.SessionStateForFrame(this.Frame); var frameState = SuspensionManager.SessionStateForFrame(Frame);
this._pageKey = "Page-" + this.Frame.BackStackDepth; _pageKey = "Page-" + Frame.BackStackDepth;
if (e.NavigationMode == NavigationMode.New) if (e.NavigationMode == NavigationMode.New)
{ {
// Clear existing state for forward navigation when adding a new page to the // Clear existing state for forward navigation when adding a new page to the
// navigation stack // navigation stack
var nextPageKey = this._pageKey; var nextPageKey = _pageKey;
int nextPageIndex = this.Frame.BackStackDepth; var nextPageIndex = Frame.BackStackDepth;
while (frameState.Remove(nextPageKey)) while (frameState.Remove(nextPageKey))
{ {
nextPageIndex++; nextPageIndex++;
@@ -329,20 +312,14 @@ namespace ModernKeePass.Common
} }
// Pass the navigation parameter to the new page // Pass the navigation parameter to the new page
if (this.LoadState != null) LoadState?.Invoke(this, new LoadStateEventArgs(e.Parameter, null));
{
this.LoadState(this, new LoadStateEventArgs(e.Parameter, null));
}
} }
else else
{ {
// Pass the navigation parameter and preserved page state to the page, using // Pass the navigation parameter and preserved page state to the page, using
// the same strategy for loading suspended state and recreating pages discarded // the same strategy for loading suspended state and recreating pages discarded
// from cache // from cache
if (this.LoadState != null) LoadState?.Invoke(this, new LoadStateEventArgs(e.Parameter, (Dictionary<string, object>)frameState[_pageKey]));
{
this.LoadState(this, new LoadStateEventArgs(e.Parameter, (Dictionary<String, Object>)frameState[this._pageKey]));
}
} }
} }
@@ -355,12 +332,9 @@ namespace ModernKeePass.Common
/// property provides the group to be displayed.</param> /// property provides the group to be displayed.</param>
public void OnNavigatedFrom(NavigationEventArgs e) public void OnNavigatedFrom(NavigationEventArgs e)
{ {
var frameState = SuspensionManager.SessionStateForFrame(this.Frame); var frameState = SuspensionManager.SessionStateForFrame(Frame);
var pageState = new Dictionary<String, Object>(); var pageState = new Dictionary<string, object>();
if (this.SaveState != null) SaveState?.Invoke(this, new SaveStateEventArgs(pageState));
{
this.SaveState(this, new SaveStateEventArgs(pageState));
}
frameState[_pageKey] = pageState; frameState[_pageKey] = pageState;
} }
@@ -382,32 +356,31 @@ namespace ModernKeePass.Common
public class LoadStateEventArgs : EventArgs public class LoadStateEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// The parameter value passed to <see cref="Frame.Navigate(Type, Object)"/> /// The parameter value passed to <see cref="Frame.Navigate(Type, object)"/>
/// when this page was initially requested. /// when this page was initially requested.
/// </summary> /// </summary>
public Object NavigationParameter { get; private set; } public object NavigationParameter { get; private set; }
/// <summary> /// <summary>
/// A dictionary of state preserved by this page during an earlier /// A dictionary of state preserved by this page during an earlier
/// session. This will be null the first time a page is visited. /// session. This will be null the first time a page is visited.
/// </summary> /// </summary>
public Dictionary<string, Object> PageState { get; private set; } public Dictionary<string, object> PageState { get; private set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LoadStateEventArgs"/> class. /// Initializes a new instance of the <see cref="LoadStateEventArgs"/> class.
/// </summary> /// </summary>
/// <param name="navigationParameter"> /// <param name="navigationParameter">
/// The parameter value passed to <see cref="Frame.Navigate(Type, Object)"/> /// The parameter value passed to <see cref="Frame.Navigate(Type, object)"/>
/// when this page was initially requested. /// when this page was initially requested.
/// </param> /// </param>
/// <param name="pageState"> /// <param name="pageState">
/// A dictionary of state preserved by this page during an earlier /// A dictionary of state preserved by this page during an earlier
/// session. This will be null the first time a page is visited. /// session. This will be null the first time a page is visited.
/// </param> /// </param>
public LoadStateEventArgs(Object navigationParameter, Dictionary<string, Object> pageState) public LoadStateEventArgs(object navigationParameter, Dictionary<string, object> pageState)
: base()
{ {
this.NavigationParameter = navigationParameter; NavigationParameter = navigationParameter;
this.PageState = pageState; PageState = pageState;
} }
} }
/// <summary> /// <summary>
@@ -418,16 +391,15 @@ namespace ModernKeePass.Common
/// <summary> /// <summary>
/// An empty dictionary to be populated with serializable state. /// An empty dictionary to be populated with serializable state.
/// </summary> /// </summary>
public Dictionary<string, Object> PageState { get; private set; } public Dictionary<string, object> PageState { get; private set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SaveStateEventArgs"/> class. /// Initializes a new instance of the <see cref="SaveStateEventArgs"/> class.
/// </summary> /// </summary>
/// <param name="pageState">An empty dictionary to be populated with serializable state.</param> /// <param name="pageState">An empty dictionary to be populated with serializable state.</param>
public SaveStateEventArgs(Dictionary<string, Object> pageState) public SaveStateEventArgs(Dictionary<string, object> pageState)
: base()
{ {
this.PageState = pageState; PageState = pageState;
} }
} }
} }