private void OnSelectedSourceChanged(Uri oldValue, Uri newValue) { // Uri "Page1.xaml#111" and "Page1#222" points to the same page, but with a different fragment // Must remove the fragment to avoid believing we are on different pages. Uri oldValueNoFragment = NavigationHelper.RemoveFragment(oldValue); Uri newValueNoFragment = NavigationHelper.RemoveFragment(newValue); if (!this.isSelecting) { // if old and new are equal, don't do anything if (newValueNoFragment != null && newValueNoFragment.Equals(oldValueNoFragment)) { return; } UpdateSelection(); } // raise SelectedSourceChanged event var handler = this.SelectedSourceChanged; if (handler != null) { handler(this, new SourceEventArgs(newValue)); } }
private void OnSourceChanged(Uri oldValue, Uri newValue) { // if resetting source or old source equals new, don't do anything if (this.isResetSource || newValue != null && newValue.Equals(oldValue)) { return; } // handle fragment navigation string newFragment = null; var oldValueNoFragment = NavigationHelper.RemoveFragment(oldValue); var newValueNoFragment = NavigationHelper.RemoveFragment(newValue, out newFragment); if (newValueNoFragment != null && newValueNoFragment.Equals(oldValueNoFragment)) { // fragment navigation var args = new FragmentNavigationEventArgs { Fragment = newFragment }; OnFragmentNavigation(this.Content as IContent, args); } else { var navType = this.isNavigatingHistory ? NavigationType.Back : NavigationType.New; // only invoke CanNavigate for new navigation if (!this.isNavigatingHistory && !CanNavigate(oldValue, newValue, navType)) { return; } Navigate(oldValue, newValue, navType); } }
private void UpdateSelection() { LinkGroup selectedGroup = null; Link selectedLink = null; Uri sourceNoFragment = NavigationHelper.RemoveFragment(this.SelectedSource); if (this.LinkGroups != null) { // find the current select group and link based on the selected source var linkInfo = (from g in this.LinkGroups from l in g.Links where l.Source == sourceNoFragment select new { Group = g, Link = l }).FirstOrDefault(); if (linkInfo != null) { selectedGroup = linkInfo.Group; selectedLink = linkInfo.Link; } else { // could not find link and group based on selected source, fall back to selected link group selectedGroup = this.SelectedLinkGroup; // if selected group doesn't exist in available groups, select first group if (!this.LinkGroups.Any(g => g == selectedGroup)) { selectedGroup = this.LinkGroups.FirstOrDefault(); } } } ReadOnlyLinkGroupCollection groups = null; if (selectedGroup != null) { // ensure group itself maintains the selected link selectedGroup.SelectedLink = selectedLink; // find the collection this group belongs to var groupKey = GetGroupKey(selectedGroup); this.groupMap.TryGetValue(groupKey, out groups); } this.isSelecting = true; // update selection SetValue(VisibleLinkGroupsPropertyKey, groups); SetCurrentValue(SelectedLinkGroupProperty, selectedGroup); SetCurrentValue(SelectedLinkProperty, selectedLink); this.isSelecting = false; }
private void SetContent(Uri newSource, NavigationType navigationType, object newContent, bool contentIsError) { var oldContent = this.Content as IContent; // assign content this.Content = newContent; // do not raise navigated event when error if (!contentIsError) { var args = new NavigationEventArgs { Frame = this, Source = newSource, Content = newContent, NavigationType = navigationType }; OnNavigated(oldContent, newContent as IContent, args); } // set IsLoadingContent to false SetValue(IsLoadingContentPropertyKey, false); if (!contentIsError) { // and raise optional fragment navigation events string fragment; NavigationHelper.RemoveFragment(newSource, out fragment); if (fragment != null) { // fragment navigation var fragmentArgs = new FragmentNavigationEventArgs { Fragment = fragment }; OnFragmentNavigation(newContent as IContent, fragmentArgs); } } }
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); }