private void OnNavigationFailed(NavigationFailedEventArgs e) { NavigationFailed?.Invoke(this, e); }
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 (_tokenSource != null) { _tokenSource.Cancel(); _tokenSource = null; } // push previous source onto the history stack (only for new navigation types) if (oldValue != null && navigationType == NavigationType.New) { _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 || !_contentCache.TryGetValue(newValueNoFragment, out newContent)) { var localTokenSource = new CancellationTokenSource(); _tokenSource = localTokenSource; // load the content (asynchronous!) var scheduler = TaskScheduler.FromCurrentSynchronizationContext(); var task = ContentLoader.LoadContentAsync(newValue, _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 _contentCache[newValueNoFragment] = newContent; } SetContent(newValue, navigationType, newContent, false); } } finally { // clear global tokenSource to avoid a Cancel on a disposed object if (_tokenSource == localTokenSource) { _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); }