diff --git a/Samples/CortanaVoiceCommand/cs/AdventureWorks/App.xaml.cs b/Samples/CortanaVoiceCommand/cs/AdventureWorks/App.xaml.cs index 766ab00c4d..498ae4c928 100644 --- a/Samples/CortanaVoiceCommand/cs/AdventureWorks/App.xaml.cs +++ b/Samples/CortanaVoiceCommand/cs/AdventureWorks/App.xaml.cs @@ -46,6 +46,7 @@ public App() /// public static NavigationService NavigationService { get; private set; } + private RootFrameNavigationHelper rootFrameNavigationHelper; /// /// Invoked when the application is launched normally by the end user. Other entry points @@ -65,6 +66,9 @@ protected async override void OnLaunched(LaunchActivatedEventArgs e) rootFrame = new Frame(); App.NavigationService = new NavigationService(rootFrame); + // Use the RootFrameNavigationHelper to respond to keyboard and mouse shortcuts. + this.rootFrameNavigationHelper = new RootFrameNavigationHelper(rootFrame); + rootFrame.NavigationFailed += OnNavigationFailed; // Place the frame in the current Window diff --git a/Samples/CortanaVoiceCommand/cs/AdventureWorks/Common/NavigationHelper.cs b/Samples/CortanaVoiceCommand/cs/AdventureWorks/Common/NavigationHelper.cs index bc9600414f..65d53a18b6 100644 --- a/Samples/CortanaVoiceCommand/cs/AdventureWorks/Common/NavigationHelper.cs +++ b/Samples/CortanaVoiceCommand/cs/AdventureWorks/Common/NavigationHelper.cs @@ -13,31 +13,29 @@ namespace AdventureWorks.Common { /// - /// NavigationManager aids in navigation between pages. It provides commands used to - /// navigate back and forward as well as registers for standard mouse and keyboard - /// shortcuts used to go back and forward. In addition it integrates SuspensionManger - /// to handle process lifetime management and state management when navigating between - /// pages. + /// NavigationHelper aids in navigation between pages. It manages + /// the backstack and integrates SuspensionManager to handle process + /// lifetime management and state management when navigating between pages. /// /// - /// To make use of NavigationManager, follow these two steps or + /// To make use of NavigationHelper, follow these two steps or /// start with a BasicPage or any other Page item template other than BlankPage. /// - /// 1) Create an instance of the NaivgationHelper somewhere such as in the + /// 1) Create an instance of the NavigationHelper somewhere such as in the /// constructor for the page and register a callback for the LoadState and /// SaveState events. /// /// public MyPage() /// { /// this.InitializeComponent(); - /// var navigationHelper = new NavigationHelper(this); + /// this.navigationHelper = new NavigationHelper(this); /// this.navigationHelper.LoadState += navigationHelper_LoadState; /// this.navigationHelper.SaveState += navigationHelper_SaveState; /// } /// - /// private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e) + /// private void navigationHelper_LoadState(object sender, LoadStateEventArgs e) /// { } - /// private async void navigationHelper_SaveState(object sender, LoadStateEventArgs e) + /// private void navigationHelper_SaveState(object sender, LoadStateEventArgs e) /// { } /// /// @@ -65,153 +63,183 @@ public class NavigationHelper : DependencyObject /// /// Initializes a new instance of the class. /// - /// A reference to the current page used for navigation. - /// This reference allows for frame manipulation and to ensure that keyboard - /// navigation requests only occur when the page is occupying the entire window. + /// A reference to the current page used for navigation. + /// This reference allows for frame manipulation. public NavigationHelper(Page page) { this.Page = page; - - // When this page is part of the visual tree make two changes: - // 1) Map application view state to visual state for the page - // 2) Handle keyboard and mouse navigation requests - this.Page.Loaded += (sender, e) => - { - // Keyboard and mouse navigation only apply when occupying the entire window - if (this.Page.ActualHeight == Window.Current.Bounds.Height && - this.Page.ActualWidth == Window.Current.Bounds.Width) - { - SystemNavigationManager systemNavigationManager = SystemNavigationManager.GetForCurrentView(); - systemNavigationManager.AppViewBackButtonVisibility = - this.Frame.CanGoBack ? AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed; - systemNavigationManager.BackRequested += SystemNavigationManager_BackRequested; - - // Listen to the window directly so focus isn't required - Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated += - CoreDispatcher_AcceleratorKeyActivated; - Window.Current.CoreWindow.PointerPressed += - this.CoreWindow_PointerPressed; - } - }; - - // Undo the same changes when the page is no longer visible - this.Page.Unloaded += (sender, e) => - { - SystemNavigationManager.GetForCurrentView().BackRequested -= SystemNavigationManager_BackRequested; - - Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated -= - CoreDispatcher_AcceleratorKeyActivated; - Window.Current.CoreWindow.PointerPressed -= - this.CoreWindow_PointerPressed; - }; } - private void SystemNavigationManager_BackRequested(object sender, BackRequestedEventArgs e) - { - if (!e.Handled && this.CanGoBack()) - { - e.Handled = true; - this.GoBack(); - } - } + #region Process lifetime management - #region Navigation support + private String _pageKey; - RelayCommand _goBackCommand; - RelayCommand _goForwardCommand; + /// + /// Handle this event to populate the page using content passed + /// during navigation as well as any state that was saved by + /// the SaveState event handler. + /// + public event LoadStateEventHandler LoadState; + /// + /// Handle this event to save state that can be used by + /// the LoadState event handler. Save the state in case + /// the application is suspended or the page is discarded + /// from the navigation cache. + /// + public event SaveStateEventHandler SaveState; /// - /// used to bind to the back Button's Command property - /// for navigating to the most recent item in back navigation history, if a Frame - /// manages its own navigation history. - /// - /// The is set up to use the virtual method - /// as the Execute Action and for CanExecute. + /// Invoked when this page is about to be displayed in a Frame. + /// This method calls , where all page specific + /// navigation and process lifetime management logic should be placed. /// - public RelayCommand GoBackCommand + /// Event data that describes how this page was reached. The Parameter + /// property provides the group to be displayed. + public void OnNavigatedTo(NavigationEventArgs e) { - get + var frameState = SuspensionManager.SessionStateForFrame(this.Frame); + this._pageKey = "Page-" + this.Frame.BackStackDepth; + + if (e.NavigationMode == NavigationMode.New) { - if (_goBackCommand == null) + // Clear existing state for forward navigation when adding a new page to the + // navigation stack + var nextPageKey = this._pageKey; + int nextPageIndex = this.Frame.BackStackDepth; + while (frameState.Remove(nextPageKey)) { - _goBackCommand = new RelayCommand( - () => this.GoBack(), - () => this.CanGoBack()); + nextPageIndex++; + nextPageKey = "Page-" + nextPageIndex; + } + + // Pass the navigation parameter to the new page + if (this.LoadState != null) + { + this.LoadState(this, new LoadStateEventArgs(e.Parameter, null)); } - return _goBackCommand; } - set + else { - _goBackCommand = value; + // Pass the navigation parameter and preserved page state to the page, using + // the same strategy for loading suspended state and recreating pages discarded + // from cache + if (this.LoadState != null) + { + this.LoadState(this, new LoadStateEventArgs(e.Parameter, (Dictionary)frameState[this._pageKey])); + } } } + /// - /// used for navigating to the most recent item in - /// the forward navigation history, if a Frame manages its own navigation history. - /// - /// The is set up to use the virtual method - /// as the Execute Action and for CanExecute. + /// Invoked when this page will no longer be displayed in a Frame. + /// This method calls , where all page specific + /// navigation and process lifetime management logic should be placed. /// - public RelayCommand GoForwardCommand + /// Event data that describes how this page was reached. The Parameter + /// property provides the group to be displayed. + public void OnNavigatedFrom(NavigationEventArgs e) { - get + var frameState = SuspensionManager.SessionStateForFrame(this.Frame); + var pageState = new Dictionary(); + if (this.SaveState != null) { - if (_goForwardCommand == null) - { - _goForwardCommand = new RelayCommand( - () => this.GoForward(), - () => this.CanGoForward()); - } - return _goForwardCommand; + this.SaveState(this, new SaveStateEventArgs(pageState)); } + frameState[_pageKey] = pageState; } + #endregion + } + + /// + /// RootFrameNavigationHelper registers for standard mouse and keyboard + /// shortcuts used to go back and forward. There should be only one + /// RootFrameNavigationHelper per view, and it should be associated with the + /// root frame. + /// + /// + /// To make use of RootFrameNavigationHelper, create an instance of the + /// RootNavigationHelper such as in the constructor of your root page. + /// + /// public MyRootPage() + /// { + /// this.InitializeComponent(); + /// this.rootNavigationHelper = new RootNavigationHelper(MyFrame); + /// } + /// + /// + [Windows.Foundation.Metadata.WebHostHidden] + public class RootFrameNavigationHelper + { + private Frame Frame { get; set; } + SystemNavigationManager systemNavigationManager; + /// - /// Virtual method used by the property - /// to determine if the can go back. + /// Initializes a new instance of the class. /// - /// - /// true if the has at least one entry - /// in the back navigation history. - /// - public virtual bool CanGoBack() + /// A reference to the top-level frame. + /// This reference allows for frame manipulation and to register navigation handlers. + public RootFrameNavigationHelper(Frame rootFrame) { - return this.Frame != null && this.Frame.CanGoBack; + this.Frame = rootFrame; + + // Handle keyboard and mouse navigation requests + this.systemNavigationManager = SystemNavigationManager.GetForCurrentView(); + systemNavigationManager.BackRequested += SystemNavigationManager_BackRequested; + UpdateBackButton(); + + // Listen to the window directly so we will respond to hotkeys regardless + // of which element has focus. + Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated += + CoreDispatcher_AcceleratorKeyActivated; + Window.Current.CoreWindow.PointerPressed += + this.CoreWindow_PointerPressed; + + // Update the Back button whenever a navigation occurs. + this.Frame.Navigated += (s, e) => UpdateBackButton(); } - /// - /// Virtual method used by the property - /// to determine if the can go forward. - /// - /// - /// true if the has at least one entry - /// in the forward navigation history. - /// - public virtual bool CanGoForward() + + private bool TryGoBack() { - return this.Frame != null && this.Frame.CanGoForward; + bool navigated = false; + if (this.Frame.CanGoBack) + { + this.Frame.GoBack(); + navigated = true; + } + return navigated; } - /// - /// Virtual method used by the property - /// to invoke the method. - /// - public virtual void GoBack() + private bool TryGoForward() { - if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack(); + bool navigated = false; + if (this.Frame.CanGoForward) + { + this.Frame.GoForward(); + navigated = true; + } + return navigated; } - /// - /// Virtual method used by the property - /// to invoke the method. - /// - public virtual void GoForward() + + + private void SystemNavigationManager_BackRequested(object sender, BackRequestedEventArgs e) { - if (this.Frame != null && this.Frame.CanGoForward) this.Frame.GoForward(); + if (!e.Handled) + { + e.Handled = TryGoBack(); + } } + private void UpdateBackButton() + { + systemNavigationManager.AppViewBackButtonVisibility = + this.Frame.CanGoBack ? AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed; + } + /// - /// Invoked on every keystroke, including system keys such as Alt key combinations, when - /// this page is active and occupies the entire window. Used to detect keyboard navigation - /// between pages even when the page itself doesn't have focus. + /// Invoked on every keystroke, including system keys such as Alt key combinations. + /// Used to detect keyboard navigation between pages even when the page itself + /// doesn't have focus. /// /// Instance that triggered the event. /// Event data describing the conditions that led to the event. @@ -239,23 +267,21 @@ private void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher sender, (virtualKey == VirtualKey.Left && onlyAlt)) { // When the previous key or Alt+Left are pressed navigate back - e.Handled = true; - this.GoBackCommand.Execute(null); + e.Handled = TryGoBack(); } else if (((int)virtualKey == 167 && noModifiers) || (virtualKey == VirtualKey.Right && onlyAlt)) { // When the next key or Alt+Right are pressed navigate forward - e.Handled = true; - this.GoForwardCommand.Execute(null); + e.Handled = TryGoForward(); } } } /// - /// Invoked on every mouse click, touch screen tap, or equivalent interaction when this - /// page is active and occupies the entire window. Used to detect browser-style next and - /// previous mouse button clicks to navigate between pages. + /// Invoked on every mouse click, touch screen tap, or equivalent interaction. + /// Used to detect browser-style next and previous mouse button clicks + /// to navigate between pages. /// /// Instance that triggered the event. /// Event data describing the conditions that led to the event. @@ -275,92 +301,10 @@ private void CoreWindow_PointerPressed(CoreWindow sender, if (backPressed ^ forwardPressed) { e.Handled = true; - if (backPressed) this.GoBackCommand.Execute(null); - if (forwardPressed) this.GoForwardCommand.Execute(null); - } - } - - #endregion - - #region Process lifetime management - - private String _pageKey; - - /// - /// Register this event on the current page to populate the page - /// with content passed during navigation as well as any saved - /// state provided when recreating a page from a prior session. - /// - public event LoadStateEventHandler LoadState; - /// - /// Register this event on the current page to preserve - /// state associated with the current page in case the - /// application is suspended or the page is discarded from - /// the navigaqtion cache. - /// - public event SaveStateEventHandler SaveState; - - /// - /// Invoked when this page is about to be displayed in a Frame. - /// This method calls , where all page specific - /// navigation and process lifetime management logic should be placed. - /// - /// Event data that describes how this page was reached. The Parameter - /// property provides the group to be displayed. - public void OnNavigatedTo(NavigationEventArgs e) - { - var frameState = SuspensionManager.SessionStateForFrame(this.Frame); - this._pageKey = "Page-" + this.Frame.BackStackDepth; - - if (e.NavigationMode == NavigationMode.New) - { - // Clear existing state for forward navigation when adding a new page to the - // navigation stack - var nextPageKey = this._pageKey; - int nextPageIndex = this.Frame.BackStackDepth; - while (frameState.Remove(nextPageKey)) - { - nextPageIndex++; - nextPageKey = "Page-" + nextPageIndex; - } - - // Pass the navigation parameter to the new page - if (this.LoadState != null) - { - this.LoadState(this, new LoadStateEventArgs(e.Parameter, null)); - } - } - else - { - // Pass the navigation parameter and preserved page state to the page, using - // the same strategy for loading suspended state and recreating pages discarded - // from cache - if (this.LoadState != null) - { - this.LoadState(this, new LoadStateEventArgs(e.Parameter, (Dictionary)frameState[this._pageKey])); - } - } - } - - /// - /// Invoked when this page will no longer be displayed in a Frame. - /// This method calls , where all page specific - /// navigation and process lifetime management logic should be placed. - /// - /// Event data that describes how this page was reached. The Parameter - /// property provides the group to be displayed. - public void OnNavigatedFrom(NavigationEventArgs e) - { - var frameState = SuspensionManager.SessionStateForFrame(this.Frame); - var pageState = new Dictionary(); - if (this.SaveState != null) - { - this.SaveState(this, new SaveStateEventArgs(pageState)); + if (backPressed) this.TryGoBack(); + if (forwardPressed) this.TryGoForward(); } - frameState[_pageKey] = pageState; } - - #endregion } /// diff --git a/Samples/FolderEnumeration/cs/Package.appxmanifest b/Samples/FolderEnumeration/cs/Package.appxmanifest index 2142a291e3..e815e80330 100644 --- a/Samples/FolderEnumeration/cs/Package.appxmanifest +++ b/Samples/FolderEnumeration/cs/Package.appxmanifest @@ -21,7 +21,7 @@ - + diff --git a/Samples/TouchKeyboard/cpp/Package.appxmanifest b/Samples/TouchKeyboard/cpp/Package.appxmanifest index 7d6c1e4b9d..5649847e2f 100644 --- a/Samples/TouchKeyboard/cpp/Package.appxmanifest +++ b/Samples/TouchKeyboard/cpp/Package.appxmanifest @@ -20,7 +20,7 @@ - + diff --git a/Samples/TouchKeyboard/cs/Package.appxmanifest b/Samples/TouchKeyboard/cs/Package.appxmanifest index f797a21833..b4c44e2366 100644 --- a/Samples/TouchKeyboard/cs/Package.appxmanifest +++ b/Samples/TouchKeyboard/cs/Package.appxmanifest @@ -21,7 +21,7 @@ - + diff --git a/Samples/XamlUIBasics/cs/AppUIBasics/Common/NavigationHelper.cs b/Samples/XamlUIBasics/cs/AppUIBasics/Common/NavigationHelper.cs index 3c993950f9..6f62e07180 100644 --- a/Samples/XamlUIBasics/cs/AppUIBasics/Common/NavigationHelper.cs +++ b/Samples/XamlUIBasics/cs/AppUIBasics/Common/NavigationHelper.cs @@ -13,31 +13,29 @@ namespace AppUIBasics.Common { /// - /// NavigationManager aids in navigation between pages. It provides commands used to - /// navigate back and forward as well as registers for standard mouse and keyboard - /// shortcuts used to go back and forward. In addition it integrates SuspensionManger - /// to handle process lifetime management and state management when navigating between - /// pages. + /// NavigationHelper aids in navigation between pages. It manages + /// the backstack and integrates SuspensionManager to handle process + /// lifetime management and state management when navigating between pages. /// /// - /// To make use of NavigationManager, follow these two steps or + /// To make use of NavigationHelper, follow these two steps or /// start with a BasicPage or any other Page item template other than BlankPage. /// - /// 1) Create an instance of the NaivgationHelper somewhere such as in the + /// 1) Create an instance of the NavigationHelper somewhere such as in the /// constructor for the page and register a callback for the LoadState and /// SaveState events. /// /// public MyPage() /// { /// this.InitializeComponent(); - /// var navigationHelper = new NavigationHelper(this); + /// this.navigationHelper = new NavigationHelper(this); /// this.navigationHelper.LoadState += navigationHelper_LoadState; /// this.navigationHelper.SaveState += navigationHelper_SaveState; /// } /// - /// private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e) + /// private void navigationHelper_LoadState(object sender, LoadStateEventArgs e) /// { } - /// private async void navigationHelper_SaveState(object sender, LoadStateEventArgs e) + /// private void navigationHelper_SaveState(object sender, LoadStateEventArgs e) /// { } /// /// @@ -65,153 +63,183 @@ public class NavigationHelper : DependencyObject /// /// Initializes a new instance of the class. /// - /// A reference to the current page used for navigation. - /// This reference allows for frame manipulation and to ensure that keyboard - /// navigation requests only occur when the page is occupying the entire window. + /// A reference to the current page used for navigation. + /// This reference allows for frame manipulation. public NavigationHelper(Page page) { this.Page = page; - - // When this page is part of the visual tree make two changes: - // 1) Map application view state to visual state for the page - // 2) Handle keyboard and mouse navigation requests - this.Page.Loaded += (sender, e) => - { - // Keyboard and mouse navigation only apply when occupying the entire window - if (this.Page.ActualHeight == Window.Current.Bounds.Height && - this.Page.ActualWidth == Window.Current.Bounds.Width) - { - SystemNavigationManager systemNavigationManager = SystemNavigationManager.GetForCurrentView(); - systemNavigationManager.AppViewBackButtonVisibility = - this.Frame.CanGoBack ? AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed; - systemNavigationManager.BackRequested += SystemNavigationManager_BackRequested; - - // Listen to the window directly so focus isn't required - Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated += - CoreDispatcher_AcceleratorKeyActivated; - Window.Current.CoreWindow.PointerPressed += - this.CoreWindow_PointerPressed; - } - }; - - // Undo the same changes when the page is no longer visible - this.Page.Unloaded += (sender, e) => - { - SystemNavigationManager.GetForCurrentView().BackRequested -= SystemNavigationManager_BackRequested; - - Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated -= - CoreDispatcher_AcceleratorKeyActivated; - Window.Current.CoreWindow.PointerPressed -= - this.CoreWindow_PointerPressed; - }; } - private void SystemNavigationManager_BackRequested(object sender, BackRequestedEventArgs e) - { - if (!e.Handled && this.CanGoBack()) - { - e.Handled = true; - this.GoBack(); - } - } + #region Process lifetime management - #region Navigation support + private String _pageKey; - RelayCommand _goBackCommand; - RelayCommand _goForwardCommand; + /// + /// Handle this event to populate the page using content passed + /// during navigation as well as any state that was saved by + /// the SaveState event handler. + /// + public event LoadStateEventHandler LoadState; + /// + /// Handle this event to save state that can be used by + /// the LoadState event handler. Save the state in case + /// the application is suspended or the page is discarded + /// from the navigation cache. + /// + public event SaveStateEventHandler SaveState; /// - /// used to bind to the back Button's Command property - /// for navigating to the most recent item in back navigation history, if a Frame - /// manages its own navigation history. - /// - /// The is set up to use the virtual method - /// as the Execute Action and for CanExecute. + /// Invoked when this page is about to be displayed in a Frame. + /// This method calls , where all page specific + /// navigation and process lifetime management logic should be placed. /// - public RelayCommand GoBackCommand + /// Event data that describes how this page was reached. The Parameter + /// property provides the group to be displayed. + public void OnNavigatedTo(NavigationEventArgs e) { - get + var frameState = SuspensionManager.SessionStateForFrame(this.Frame); + this._pageKey = "Page-" + this.Frame.BackStackDepth; + + if (e.NavigationMode == NavigationMode.New) { - if (_goBackCommand == null) + // Clear existing state for forward navigation when adding a new page to the + // navigation stack + var nextPageKey = this._pageKey; + int nextPageIndex = this.Frame.BackStackDepth; + while (frameState.Remove(nextPageKey)) { - _goBackCommand = new RelayCommand( - () => this.GoBack(), - () => this.CanGoBack()); + nextPageIndex++; + nextPageKey = "Page-" + nextPageIndex; + } + + // Pass the navigation parameter to the new page + if (this.LoadState != null) + { + this.LoadState(this, new LoadStateEventArgs(e.Parameter, null)); } - return _goBackCommand; } - set + else { - _goBackCommand = value; + // Pass the navigation parameter and preserved page state to the page, using + // the same strategy for loading suspended state and recreating pages discarded + // from cache + if (this.LoadState != null) + { + this.LoadState(this, new LoadStateEventArgs(e.Parameter, (Dictionary)frameState[this._pageKey])); + } } } + /// - /// used for navigating to the most recent item in - /// the forward navigation history, if a Frame manages its own navigation history. - /// - /// The is set up to use the virtual method - /// as the Execute Action and for CanExecute. + /// Invoked when this page will no longer be displayed in a Frame. + /// This method calls , where all page specific + /// navigation and process lifetime management logic should be placed. /// - public RelayCommand GoForwardCommand + /// Event data that describes how this page was reached. The Parameter + /// property provides the group to be displayed. + public void OnNavigatedFrom(NavigationEventArgs e) { - get + var frameState = SuspensionManager.SessionStateForFrame(this.Frame); + var pageState = new Dictionary(); + if (this.SaveState != null) { - if (_goForwardCommand == null) - { - _goForwardCommand = new RelayCommand( - () => this.GoForward(), - () => this.CanGoForward()); - } - return _goForwardCommand; + this.SaveState(this, new SaveStateEventArgs(pageState)); } + frameState[_pageKey] = pageState; } + #endregion + } + + /// + /// RootFrameNavigationHelper registers for standard mouse and keyboard + /// shortcuts used to go back and forward. There should be only one + /// RootFrameNavigationHelper per view, and it should be associated with the + /// root frame. + /// + /// + /// To make use of RootFrameNavigationHelper, create an instance of the + /// RootNavigationHelper such as in the constructor of your root page. + /// + /// public MyRootPage() + /// { + /// this.InitializeComponent(); + /// this.rootNavigationHelper = new RootNavigationHelper(MyFrame); + /// } + /// + /// + [Windows.Foundation.Metadata.WebHostHidden] + public class RootFrameNavigationHelper + { + private Frame Frame { get; set; } + SystemNavigationManager systemNavigationManager; + /// - /// Virtual method used by the property - /// to determine if the can go back. + /// Initializes a new instance of the class. /// - /// - /// true if the has at least one entry - /// in the back navigation history. - /// - public virtual bool CanGoBack() + /// A reference to the top-level frame. + /// This reference allows for frame manipulation and to register navigation handlers. + public RootFrameNavigationHelper(Frame rootFrame) { - return this.Frame != null && this.Frame.CanGoBack; + this.Frame = rootFrame; + + // Handle keyboard and mouse navigation requests + this.systemNavigationManager = SystemNavigationManager.GetForCurrentView(); + systemNavigationManager.BackRequested += SystemNavigationManager_BackRequested; + UpdateBackButton(); + + // Listen to the window directly so we will respond to hotkeys regardless + // of which element has focus. + Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated += + CoreDispatcher_AcceleratorKeyActivated; + Window.Current.CoreWindow.PointerPressed += + this.CoreWindow_PointerPressed; + + // Update the Back button whenever a navigation occurs. + this.Frame.Navigated += (s, e) => UpdateBackButton(); } - /// - /// Virtual method used by the property - /// to determine if the can go forward. - /// - /// - /// true if the has at least one entry - /// in the forward navigation history. - /// - public virtual bool CanGoForward() + + private bool TryGoBack() { - return this.Frame != null && this.Frame.CanGoForward; + bool navigated = false; + if (this.Frame.CanGoBack) + { + this.Frame.GoBack(); + navigated = true; + } + return navigated; } - /// - /// Virtual method used by the property - /// to invoke the method. - /// - public virtual void GoBack() + private bool TryGoForward() { - if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack(); + bool navigated = false; + if (this.Frame.CanGoForward) + { + this.Frame.GoForward(); + navigated = true; + } + return navigated; } - /// - /// Virtual method used by the property - /// to invoke the method. - /// - public virtual void GoForward() + + + private void SystemNavigationManager_BackRequested(object sender, BackRequestedEventArgs e) { - if (this.Frame != null && this.Frame.CanGoForward) this.Frame.GoForward(); + if (!e.Handled) + { + e.Handled = TryGoBack(); + } } + private void UpdateBackButton() + { + systemNavigationManager.AppViewBackButtonVisibility = + this.Frame.CanGoBack ? AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed; + } + /// - /// Invoked on every keystroke, including system keys such as Alt key combinations, when - /// this page is active and occupies the entire window. Used to detect keyboard navigation - /// between pages even when the page itself doesn't have focus. + /// Invoked on every keystroke, including system keys such as Alt key combinations. + /// Used to detect keyboard navigation between pages even when the page itself + /// doesn't have focus. /// /// Instance that triggered the event. /// Event data describing the conditions that led to the event. @@ -239,23 +267,21 @@ private void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher sender, (virtualKey == VirtualKey.Left && onlyAlt)) { // When the previous key or Alt+Left are pressed navigate back - e.Handled = true; - this.GoBackCommand.Execute(null); + e.Handled = TryGoBack(); } else if (((int)virtualKey == 167 && noModifiers) || (virtualKey == VirtualKey.Right && onlyAlt)) { // When the next key or Alt+Right are pressed navigate forward - e.Handled = true; - this.GoForwardCommand.Execute(null); + e.Handled = TryGoForward(); } } } /// - /// Invoked on every mouse click, touch screen tap, or equivalent interaction when this - /// page is active and occupies the entire window. Used to detect browser-style next and - /// previous mouse button clicks to navigate between pages. + /// Invoked on every mouse click, touch screen tap, or equivalent interaction. + /// Used to detect browser-style next and previous mouse button clicks + /// to navigate between pages. /// /// Instance that triggered the event. /// Event data describing the conditions that led to the event. @@ -275,92 +301,10 @@ private void CoreWindow_PointerPressed(CoreWindow sender, if (backPressed ^ forwardPressed) { e.Handled = true; - if (backPressed) this.GoBackCommand.Execute(null); - if (forwardPressed) this.GoForwardCommand.Execute(null); - } - } - - #endregion - - #region Process lifetime management - - private String _pageKey; - - /// - /// Register this event on the current page to populate the page - /// with content passed during navigation as well as any saved - /// state provided when recreating a page from a prior session. - /// - public event LoadStateEventHandler LoadState; - /// - /// Register this event on the current page to preserve - /// state associated with the current page in case the - /// application is suspended or the page is discarded from - /// the navigaqtion cache. - /// - public event SaveStateEventHandler SaveState; - - /// - /// Invoked when this page is about to be displayed in a Frame. - /// This method calls , where all page specific - /// navigation and process lifetime management logic should be placed. - /// - /// Event data that describes how this page was reached. The Parameter - /// property provides the group to be displayed. - public void OnNavigatedTo(NavigationEventArgs e) - { - var frameState = SuspensionManager.SessionStateForFrame(this.Frame); - this._pageKey = "Page-" + this.Frame.BackStackDepth; - - if (e.NavigationMode == NavigationMode.New) - { - // Clear existing state for forward navigation when adding a new page to the - // navigation stack - var nextPageKey = this._pageKey; - int nextPageIndex = this.Frame.BackStackDepth; - while (frameState.Remove(nextPageKey)) - { - nextPageIndex++; - nextPageKey = "Page-" + nextPageIndex; - } - - // Pass the navigation parameter to the new page - if (this.LoadState != null) - { - this.LoadState(this, new LoadStateEventArgs(e.Parameter, null)); - } - } - else - { - // Pass the navigation parameter and preserved page state to the page, using - // the same strategy for loading suspended state and recreating pages discarded - // from cache - if (this.LoadState != null) - { - this.LoadState(this, new LoadStateEventArgs(e.Parameter, (Dictionary)frameState[this._pageKey])); - } - } - } - - /// - /// Invoked when this page will no longer be displayed in a Frame. - /// This method calls , where all page specific - /// navigation and process lifetime management logic should be placed. - /// - /// Event data that describes how this page was reached. The Parameter - /// property provides the group to be displayed. - public void OnNavigatedFrom(NavigationEventArgs e) - { - var frameState = SuspensionManager.SessionStateForFrame(this.Frame); - var pageState = new Dictionary(); - if (this.SaveState != null) - { - this.SaveState(this, new SaveStateEventArgs(pageState)); + if (backPressed) this.TryGoBack(); + if (forwardPressed) this.TryGoForward(); } - frameState[_pageKey] = pageState; } - - #endregion } /// diff --git a/Samples/XamlUIBasics/cs/AppUIBasics/Navigation/NavigationRootPage.xaml.cs b/Samples/XamlUIBasics/cs/AppUIBasics/Navigation/NavigationRootPage.xaml.cs index d62958ba39..ca4b3c5942 100644 --- a/Samples/XamlUIBasics/cs/AppUIBasics/Navigation/NavigationRootPage.xaml.cs +++ b/Samples/XamlUIBasics/cs/AppUIBasics/Navigation/NavigationRootPage.xaml.cs @@ -7,6 +7,7 @@ // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. // //********************************************************* +using AppUIBasics.Common; using AppUIBasics.Data; using System; using System.Collections.Generic; @@ -44,38 +45,20 @@ public IEnumerable Groups public event EventHandler GroupsLoaded; - //public static CommandBar TopCommandBar - //{ - // get { return Current.topCommandBar; } - //} - public static SplitView RootSplitView { get { return Current.rootSplitView; } } + private RootFrameNavigationHelper rootFrameNavigationHelper; + public NavigationRootPage() { this.InitializeComponent(); - + this.rootFrameNavigationHelper = new RootFrameNavigationHelper(rootFrame); LoadGroups(); Current = this; RootFrame = rootFrame; - - //Loaded += NavigationRootPage_Loaded; - - //Use the hardware back button instead of showing the back button in the page - if (ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) - { - Windows.Phone.UI.Input.HardwareButtons.BackPressed += (s, e) => - { - if (rootFrame.CanGoBack) - { - rootFrame.GoBack(); - e.Handled = true; - } - }; - } } private async void LoadGroups() @@ -85,17 +68,6 @@ private async void LoadGroups() GroupsLoaded(this, new EventArgs()); } - //async void NavigationRootPage_Loaded(object sender, RoutedEventArgs e) - //{ - // this.DataContext = Groups; - //} - - - private void AppBar_Closed(object sender, object e) - { - //this.navControl.HideSecondLevelNav(); - } - private void ControlGroupItems_ItemClick(object sender, ItemClickEventArgs e) { foreach (var item in groupsItemControl.Items)