private void OnGoToPage(object target, ExecutedRoutedEventArgs e) { var newValue = NavigationHelper.ToUri(e.Parameter); SetCurrentValue(SourceProperty, newValue); }
private void Navigate(Uri oldValue, Uri newValue, NavigationType navigationType) { Debug.WriteLine("Navigating from '{0}' to '{1}'", oldValue, newValue); // set IsLoadingContent state SetValue(IsLoadingContentPropertyKey, true); // cancel previous load content task (if any) // note: no need for thread synchronization, this code always executes on the UI thread if (this.tokenSource != null) { this.tokenSource.Cancel(); this.tokenSource = null; } // push previous source onto the history stack (only for new navigation types) if (oldValue != null && navigationType == NavigationType.New) { this.history.Push(oldValue); } object newContent = null; if (newValue != null) { // content is cached on uri without fragment var newValueNoFragment = NavigationHelper.RemoveFragment(newValue); if (navigationType == NavigationType.Refresh || !this.contentCache.TryGetValue(newValueNoFragment, out newContent)) { var localTokenSource = new CancellationTokenSource(); this.tokenSource = localTokenSource; // load the content (asynchronous!) var scheduler = TaskScheduler.FromCurrentSynchronizationContext(); var task = this.ContentLoader.LoadContentAsync(newValue, this.tokenSource.Token); task.ContinueWith(t => { try { if (t.IsCanceled || localTokenSource.IsCancellationRequested) { Debug.WriteLine("Cancelled navigation to '{0}'", newValue); } else if (t.IsFaulted) { // raise failed event var failedArgs = new NavigationFailedEventArgs { Frame = this, Source = newValue, Error = t.Exception.InnerException, Handled = false }; OnNavigationFailed(failedArgs); // if not handled, show error as content newContent = failedArgs.Handled ? null : failedArgs.Error; SetContent(newValue, navigationType, newContent, true); } else { newContent = t.Result; if (ShouldKeepContentAlive(newContent)) { // keep the new content in memory this.contentCache[newValueNoFragment] = newContent; } SetContent(newValue, navigationType, newContent, false); } } finally { // clear global tokenSource to avoid a Cancel on a disposed object if (this.tokenSource == localTokenSource) { this.tokenSource = null; } // and dispose of the local tokensource localTokenSource.Dispose(); } }, scheduler); return; } } // newValue is null or newContent was found in the cache SetContent(newValue, navigationType, newContent, false); }