private async Task<bool> NavigateCore( Type sourcePageType, object parameter, NavigationMode navigationMode) { _isNavigating = true; this.CanNavigate = false; this.CanGoBack = false; this.CanGoForward = false; this.IsHitTestVisible = false; // Make sure we run on UI thread if (!Dispatcher.HasThreadAccess) { Task<bool> navigateCoreTask = null; await Dispatcher.RunAsync( CoreDispatcherPriority.High, () => navigateCoreTask = NavigateCore(sourcePageType, parameter, navigationMode)); return await navigateCoreTask; } try { await _waitForApplyTemplateTaskSource.Task; await this.WaitForLoadedAsync(); AlternativePage currentPage = null; #region OnNavigatingFrom part if (_currentPagePresenter != null) { currentPage = (AlternativePage)_currentPagePresenter.Content; var cancelArgs = new AlternativeNavigatingCancelEventArgs( navigationMode, sourcePageType); await this.OnNavigating(cancelArgs); if (!cancelArgs.Cancel) { await currentPage.OnNavigatingFromInternal(cancelArgs); } if (cancelArgs.Cancel) { return false; } } #endregion #region Initializing new page instance part var je = new JournalEntry { SourcePageType = sourcePageType, Parameter = parameter }; AlternativePage newPage; ContentPresenter newPagePresenter; if (_preloadedPageCache.ContainsKey(je)) { newPagePresenter = _preloadedPageCache[je]; newPage = (AlternativePage)newPagePresenter.Content; _preloadedPageCache.Remove(je); } else { newPage = _frameCache.Get(je.SourcePageType); if (newPage == null) { throw new InvalidOperationException( "Pages used in AlternativeFrame need to be of AlternativePage type."); } newPage.Frame = this; newPagePresenter = new ContentPresenter { Style = PagePresenterStyle }; newPagePresenter.Content = newPage; _pagePresentersPanel.Children.Add(newPagePresenter); } newPagePresenter.Opacity = 0.005; await UnloadAllPreloaded(); #endregion #region OnNavigatingTo part var args = new AlternativeNavigationEventArgs( newPage.Content, navigationMode, je.Parameter, je.SourcePageType); await newPage.OnNavigatingToInternal(args); #endregion #region Journal Bookeeping part switch (navigationMode) { case NavigationMode.New: this.ForwardStack.Clear(); if (this.CurrentJournalEntry != null) { this.BackStack.Push(this.CurrentJournalEntry); } break; case NavigationMode.Forward: this.ForwardStack.Pop(); if (this.CurrentJournalEntry != null) { this.BackStack.Push(this.CurrentJournalEntry); } break; case NavigationMode.Back: this.BackStack.Pop(); if (this.CurrentJournalEntry != null) { this.ForwardStack.Push(this.CurrentJournalEntry); } break; } this.CurrentJournalEntry = je; #endregion #region OnNavigated~() calls await this.OnNavigated(args); if (currentPage != null) { await currentPage.OnNavigatedFromInternal(args); } await newPage.OnNavigatedToInternal(args); #endregion #region Transition part await newPagePresenter.WaitForLoadedAsync(); await newPagePresenter.WaitForNonZeroSizeAsync(); if (this.ShouldWaitForImagesToLoad == true && newPage.ShouldWaitForImagesToLoad != false || newPage.ShouldWaitForImagesToLoad == true && this.ShouldWaitForImagesToLoad != false) { await newPage.WaitForImagesToLoad(WaitForImagesToLoadTimeout); } newPagePresenter.Opacity = 1.0; if (navigationMode == NavigationMode.Back) { await TransitionBackward( currentPage, newPage, _currentPagePresenter, newPagePresenter); } else { await TransitionForward( currentPage, newPage, _currentPagePresenter, newPagePresenter); } if (_currentPagePresenter != null) { _pagePresentersPanel.Children.Remove(_currentPagePresenter); _frameCache.Store(currentPage); } _currentPagePresenter = newPagePresenter; #endregion return true; } finally { this.IsHitTestVisible = true; _isNavigating = false; this.CanNavigate = true; this.CanGoBack = this.BackStack.Count > 0; this.CanGoForward = this.ForwardStack.Count > 0; //DC.TraceLocalized(GetNavigationState()); } }
/// <summary> /// Unloads the preloaded page of a given type and parameter. /// </summary> /// <remarks> /// A page might have been preloaded in the anticipation of the user navigating to it, /// then a state change might invalidate or reduce the possibility of a navigation request and /// it might be worth unloading the preloaded page to release resources that it consumed. /// The preloaded page will be released or cached depending on its NavigationCacheMode property. /// </remarks> /// <param name="sourcePageType">Type of the source page.</param> /// <param name="parameter">The parameter.</param> /// <returns></returns> public async Task UnloadPreloaded(Type sourcePageType, object parameter) { var je = new JournalEntry { SourcePageType = sourcePageType, Parameter = parameter }; if (!_preloadedPageCache.ContainsKey(je)) { return; } var cp = _preloadedPageCache[je]; var page = (AlternativePage)cp.Content; await page.UnloadPreloadedInternal(); _frameCache.Store(page); _pagePresentersPanel.Children.Remove(cp); _preloadedPageCache.Remove(je); }
private void AppendEntryToNavigationStateString(StringBuilder sb, JournalEntry journalEntry) { var pageTypeString = journalEntry.SourcePageType.AssemblyQualifiedName; sb.AppendFormat(",{0},{1}", pageTypeString.Length, pageTypeString); if (journalEntry.Parameter == null) { sb.Append(",0"); return; } var valueString = journalEntry.Parameter.ToString(); if (journalEntry.Parameter is byte) { AddParameterToNavigationStateString(sb, 1, valueString); return; } if (journalEntry.Parameter is Int16) { AddParameterToNavigationStateString(sb, 2, valueString); return; } if (journalEntry.Parameter is UInt16) { AddParameterToNavigationStateString(sb, 3, valueString); return; } if (journalEntry.Parameter is Int32) { AddParameterToNavigationStateString(sb, 4, valueString); return; } if (journalEntry.Parameter is UInt32) { AddParameterToNavigationStateString(sb, 5, valueString); return; } if (journalEntry.Parameter is Int64) { AddParameterToNavigationStateString(sb, 6, valueString); return; } if (journalEntry.Parameter is UInt64) { AddParameterToNavigationStateString(sb, 7, valueString); return; } if (journalEntry.Parameter is Single) { AddParameterToNavigationStateString(sb, 8, valueString); return; } if (journalEntry.Parameter is Double) { AddParameterToNavigationStateString(sb, 9, valueString); return; } if (journalEntry.Parameter is Char) { AddParameterToNavigationStateString(sb, 10, valueString); return; } if (journalEntry.Parameter is Boolean) { AddParameterToNavigationStateString(sb, 11, valueString); return; } if (journalEntry.Parameter is String) { AddParameterToNavigationStateString(sb, 12, valueString); } }
/// <summary> /// Preloads a page of the specified source page type. /// </summary> /// <remarks> /// Allows to preload a page before user navigates to it, so if it does get navigated to - shows up quickly. /// If another page gets navigated to - the preloaded page will be released or cached depending on its NavigationCacheMode property. /// </remarks> /// <param name="sourcePageType">Type of the source page.</param> /// <param name="parameter">The parameter.</param> /// <returns></returns> public async Task<bool> Preload(Type sourcePageType, object parameter) { var je = new JournalEntry { SourcePageType = sourcePageType, Parameter = parameter }; if (_preloadedPageCache.ContainsKey(je)) { return true; } var cp = new ContentPresenter { Style = PagePresenterStyle }; var newPage = _frameCache.Get(sourcePageType); Debug.Assert(newPage != null, "Pages used in AlternativeFrame need to be of AlternativePage type."); if (newPage == null) { return false; } newPage.Frame = this; cp.Content = newPage; cp.Opacity = 0.005; Canvas.SetZIndex(cp, int.MinValue); _pagePresentersPanel.Children.Insert(0, cp); _preloadedPageCache.Add(je, cp); await newPage.PreloadInternal(parameter); cp.Opacity = 0; return true; }
public async Task<bool> Navigate(Type sourcePageType, object parameter) { if (_isNavigating) { throw new InvalidOperationException("Navigation already in progress."); } _isNavigating = true; this.CanNavigate = false; this.CanGoBack = false; try { await this.WaitForLoadedAsync(); AlternativePage currentPage = null; if (_currentPagePresenter != null) { currentPage = (AlternativePage)_currentPagePresenter.Content; var cancelArgs = new AlternativeNavigatingCancelEventArgs( NavigationMode.New, sourcePageType); await currentPage.OnNavigatingFromInternal(cancelArgs); if (cancelArgs.Cancel) { return false; } } var je = new JournalEntry {Type = sourcePageType, Parameter = parameter}; AlternativePage newPage; ContentPresenter newPagePresenter; if (_preloadedPageCache.ContainsKey(je)) { newPagePresenter = _preloadedPageCache[je]; newPage = (AlternativePage)newPagePresenter.Content; _preloadedPageCache.Remove(je); } else { newPage = (AlternativePage)Activator.CreateInstance(je.Type); newPage.Frame = this; newPagePresenter = new ContentPresenter {Style = PagePresenterStyle}; newPagePresenter.Content = newPage; _pagePresentersPanel.Children.Add(newPagePresenter); } newPagePresenter.Opacity = 0.005; // TODO: await? UnloadPreloadedPages(); var args = new AlternativeNavigationEventArgs( newPage.Content, NavigationMode.New, je.Parameter, je.Type); await newPage.OnNavigatingToInternal(args); await newPagePresenter.WaitForLoadedAsync(); await newPagePresenter.WaitForNonZeroSizeAsync(); if (this.ShouldWaitForImagesToLoad == true && newPage.ShouldWaitForImagesToLoad != false || newPage.ShouldWaitForImagesToLoad == true && this.ShouldWaitForImagesToLoad != false) { await newPage.WaitForImagesToLoad(); } newPagePresenter.Opacity = 1.0; if (this.PageTransition != null) { await this.PageTransition.TransitionForward(_currentPagePresenter, newPagePresenter); } this.BackStack.Push(je); if (currentPage != null) { await currentPage.OnNavigatedFromInternal(args); _pagePresentersPanel.Children.Remove(_currentPagePresenter); } _currentPagePresenter = newPagePresenter; await newPage.OnNavigatedToInternal(args); return true; } finally { _isNavigating = false; this.CanNavigate = true; this.CanGoBack = this.BackStack.Count > 1; } }
// Allows to preload a page before user navigates to it, so if it does get navigated to - it is quick. public async Task Preload(Type sourcePageType, object parameter) { var je = new JournalEntry {Type = sourcePageType, Parameter = parameter}; if (_preloadedPageCache.ContainsKey(je)) { return; } var cp = new ContentPresenter {Style = PagePresenterStyle}; var newPage = (AlternativePage)Activator.CreateInstance(sourcePageType); newPage.Frame = this; cp.Content = newPage; cp.Opacity = 0.005; Canvas.SetZIndex(cp, int.MinValue); _pagePresentersPanel.Children.Insert(0, cp); _preloadedPageCache.Add(je, cp); await newPage.PreloadInternal(parameter); }
private void AppendEntryToNavigationStateString(StringBuilder sb, JournalEntry journalEntry) { var pageTypeString = journalEntry.SourcePageType.AssemblyQualifiedName; sb.AppendFormat(",{0},{1}", pageTypeString.Length, pageTypeString); if (journalEntry.Parameter == null) { sb.Append(",0"); return; } var valueString = journalEntry.Parameter.ToString(); if (journalEntry.Parameter is byte) { AddParameterToNavigationStateString(sb, 1, valueString); return; } if (journalEntry.Parameter is Int16) { AddParameterToNavigationStateString(sb, 2, valueString); return; } if (journalEntry.Parameter is UInt16) { AddParameterToNavigationStateString(sb, 3, valueString); return; } if (journalEntry.Parameter is Int32) { AddParameterToNavigationStateString(sb, 4, valueString); return; } if (journalEntry.Parameter is UInt32) { AddParameterToNavigationStateString(sb, 5, valueString); return; } if (journalEntry.Parameter is Int64) { AddParameterToNavigationStateString(sb, 6, valueString); return; } if (journalEntry.Parameter is UInt64) { AddParameterToNavigationStateString(sb, 7, valueString); return; } if (journalEntry.Parameter is Single) { AddParameterToNavigationStateString(sb, 8, valueString); return; } if (journalEntry.Parameter is Double) { AddParameterToNavigationStateString(sb, 9, valueString); return; } if (journalEntry.Parameter is Char) { AddParameterToNavigationStateString(sb, 10, valueString); return; } if (journalEntry.Parameter is Boolean) { AddParameterToNavigationStateString(sb, 11, valueString); return; } if (journalEntry.Parameter is String) { AddParameterToNavigationStateString(sb, 12, valueString); return; } if (journalEntry.Parameter is Guid) { AddParameterToNavigationStateString(sb, 16, valueString); } }
private async Task <bool> NavigateCoreAsync( Type sourcePageType, object parameter, NavigationMode navigationMode) { _isNavigating = true; this.CanNavigate = false; this.CanGoBack = false; this.CanGoForward = false; this.IsHitTestVisible = false; // Make sure we run on UI thread if (!Dispatcher.HasThreadAccess) { Task <bool> navigateCoreTask = null; await Dispatcher.RunAsync( CoreDispatcherPriority.High, () => navigateCoreTask = this.NavigateCoreAsync(sourcePageType, parameter, navigationMode)); return(await navigateCoreTask); } try { await _waitForApplyTemplateTaskSource.Task; await this.WaitForLoadedAsync(); AlternativePage currentPage = null; #region OnNavigatingFrom part if (_currentPagePresenter != null) { currentPage = (AlternativePage)_currentPagePresenter.Content; var cancelArgs = new AlternativeNavigatingCancelEventArgs( navigationMode, sourcePageType); await this.OnNavigatingAsync(cancelArgs); if (!cancelArgs.Cancel) { await currentPage.OnNavigatingFromInternalAsync(cancelArgs); } if (cancelArgs.Cancel) { return(false); } } #endregion #region Initializing new page instance part var je = new JournalEntry { SourcePageType = sourcePageType, Parameter = parameter }; AlternativePage newPage; ContentPresenter newPagePresenter; if (_preloadedPageCache.ContainsKey(je)) { newPagePresenter = _preloadedPageCache[je]; newPage = (AlternativePage)newPagePresenter.Content; _preloadedPageCache.Remove(je); } else { newPage = _frameCache.Get(je.SourcePageType); if (newPage == null) { throw new InvalidOperationException( "Pages used in AlternativeFrame need to be of AlternativePage type."); } newPage.Frame = this; newPagePresenter = new ContentPresenter { Style = PagePresenterStyle }; newPagePresenter.Content = newPage; _pagePresentersPanel.Children.Add(newPagePresenter); } newPagePresenter.Opacity = 0.005; await UnloadAllPreloadedAsync(); #endregion #region OnNavigatingTo part var args = new AlternativeNavigationEventArgs( newPage.Content, navigationMode, je.Parameter, je.SourcePageType); await newPage.OnNavigatingToInternalAsync(args); #endregion #region Journal Bookeeping part switch (navigationMode) { case NavigationMode.New: this.ForwardStack.Clear(); if (this.CurrentJournalEntry != null) { this.BackStack.Push(this.CurrentJournalEntry); } break; case NavigationMode.Forward: this.ForwardStack.Pop(); if (this.CurrentJournalEntry != null) { this.BackStack.Push(this.CurrentJournalEntry); } break; case NavigationMode.Back: this.BackStack.Pop(); if (this.CurrentJournalEntry != null) { this.ForwardStack.Push(this.CurrentJournalEntry); } break; } this.CurrentJournalEntry = je; #endregion #region OnNavigatedAsync~() calls this.UpdateCans(); if (currentPage != null) { await currentPage.OnNavigatedFromInternalAsync(args); } await this.OnNavigatedAsync(args); await newPage.OnNavigatedToInternalAsync(args); #endregion #region Transition part await newPagePresenter.WaitForLoadedAsync(); await newPagePresenter.WaitForNonZeroSizeAsync(); if (this.ShouldWaitForImagesToLoad == true && newPage.ShouldWaitForImagesToLoad != false || newPage.ShouldWaitForImagesToLoad == true && this.ShouldWaitForImagesToLoad != false) { await newPage.WaitForImagesToLoadAsync(WaitForImagesToLoadTimeout); } newPagePresenter.Opacity = 1.0; if (navigationMode == NavigationMode.Back) { await this.TransitionBackwardAsync( currentPage, newPage, _currentPagePresenter, newPagePresenter); } else { await this.TransitionForwardAsync( currentPage, newPage, _currentPagePresenter, newPagePresenter); } if (_currentPagePresenter != null) { _pagePresentersPanel.Children.Remove(_currentPagePresenter); _frameCache.Store(currentPage); } _currentPagePresenter = newPagePresenter; #endregion return(true); } finally { this.IsHitTestVisible = true; _isNavigating = false; this.UpdateCans(); //DC.TraceLocalized(GetNavigationState()); } }