CustomJournalStateInternal IJournalState.GetJournalState(JournalReason journalReason) { if (journalReason != JournalReason.NewContentNavigation) { return null; } FramePersistState state = new FramePersistState(); // Save a JournalEntry for the current content. state.JournalEntry = _navigationService.MakeJournalEntry(JournalReason.NewContentNavigation); // The current Content may be null or may not want to be journaled (=> JournalEntry=null). // But we still need to save and then restore the NS GUID - there may be other JEs keyed // by this GUID value. // i. There is a somewhat similar case in ApplicationProxyInternal._GetSaveHistoryBytesDelegate(). state.NavSvcGuid = _navigationService.GuidId; state.JournalOwnership = _journalOwnership; if (_ownJournalScope != null) { Debug.Assert(_journalOwnership == JournalOwnership.OwnsJournal); // No need to make a copy here because this Frame object will be discarded. // (Supposedly the parent container is navigating away.) state.Journal = _ownJournalScope.Journal; } return state; }
/// <summary> /// <see cref="IJournalState.GetJournalState"/> /// </summary> CustomJournalStateInternal IJournalState.GetJournalState(JournalReason journalReason) { int cp = -1; LogicalDirection cpDirection = LogicalDirection.Forward; TextPointer contentPosition = ContentPosition as TextPointer; if (contentPosition != null) { cp = contentPosition.Offset; cpDirection = contentPosition.LogicalDirection; } return new JournalState(cp, cpDirection, Zoom); }
private CustomJournalStateInternal GetRootViewerState(JournalReason journalReason) { if (_navigatorHostImpl != null && !(_bp is Visual)) { Visual v = _navigatorHostImpl.FindRootViewer(); IJournalState ijs = v as IJournalState; if (ijs != null) { return ijs.GetJournalState(journalReason); } } return null; }
/// <summary> /// Makes the appropriate kind of journal entry for the current Content and its state. /// For certain types of content, no journal entry is created (null is returned). /// </summary> internal JournalEntry MakeJournalEntry(JournalReason journalReason) { if (_bp == null) { return null; } Debug.Assert(_contentId != 0 && (_journalEntryGroupState == null || _journalEntryGroupState.ContentId == _contentId)); if (_journalEntryGroupState == null) // First journal entry created for the current Content? { _journalEntryGroupState = new JournalEntryGroupState(_guidId, _contentId); } JournalEntry journalEntry; bool keepAlive = IsContentKeepAlive(); PageFunctionBase pfBase = _bp as PageFunctionBase; if (pfBase != null) { if (keepAlive) { journalEntry = new JournalEntryPageFunctionKeepAlive(_journalEntryGroupState, pfBase); } else { // // If the PageFunction is navigated from xaml Uri, or navigated from an instance of // PageFunction type, but that PageFunctin type is implemented from xaml file, // we should always get the BaseUri DP value for the root PageFunction element. // // If the code navigates to pure #fragment, the root element should be ready, // if the BaseUri for that root element is set, we should still use JournalEntryPageFunctionUri. // if the BaseUri for that root element is not set, that pagefunction class is not // implemented in xaml file, JournalEntryPageFunctionType is used for journaling. // Navigation service has its own way to get to the element marked by the pure fragment. // Uri baseUri = pfBase.GetValue(BaseUriHelper.BaseUriProperty) as Uri; if (baseUri != null) { Invariant.Assert(baseUri.IsAbsoluteUri == true, "BaseUri for root element should be absolute."); Uri markupUri; // // Set correct uri when creating instance of JournalEntryPageFunctionUri // // This markupUri is used to create instance of PageFunction from baml stream. // fragment in original Source doesn't affect the resource loading, and it will // be set in the JournalEntry.Source for further navigation handling. So the logic // of setting markupUri for JEPFUri can be simplified as below: // // If _currentCleanSource is set and it is not a pure fragment uri, take whatever // value of _currentSource, which should always be an absolute Uri for the page. // // For all other cases, take whatever value of BaseUri in root element. // if (_currentCleanSource != null && BindUriHelper.StartWithFragment(_currentCleanSource) == false ) { markupUri = _currentSource; } else { markupUri = baseUri; } journalEntry = new JournalEntryPageFunctionUri(_journalEntryGroupState, pfBase, markupUri); } else { journalEntry = new JournalEntryPageFunctionType(_journalEntryGroupState, pfBase); } } journalEntry.Source = _currentCleanSource; // This could be #fragment. } else { if (keepAlive) { journalEntry = new JournalEntryKeepAlive(_journalEntryGroupState, _currentCleanSource, _bp); } else { journalEntry = new JournalEntryUri(_journalEntryGroupState, _currentCleanSource); } } // _customContentStateToSave can be preset by AddBackEntry() or FireNavigating(). // If not, try the IProvideCustomContentState callback. CustomContentState ccs = _customContentStateToSave; if (ccs == null) { IProvideCustomContentState pccs = _bp as IProvideCustomContentState; if (pccs != null) { ccs = pccs.GetContentState(); } } if (ccs != null) { // Make sure the object is serializable Type type = ccs.GetType(); if (!type.IsSerializable) { throw new SystemException(SR.Get(SRID.CustomContentStateMustBeSerializable, type)); } journalEntry.CustomContentState = ccs; } // Info: CustomContentState for the current page in child frames is saved in // DataStreams.SaveState(). (This requires the IProvideCustomContentState to be implemented.) // Root Viewer journaling if (_rootViewerStateToSave != null) // state saved in advance? { journalEntry.RootViewerState = _rootViewerStateToSave; _rootViewerStateToSave = null; } else { journalEntry.RootViewerState = GetRootViewerState(journalReason); } // Set the friendly Name of this JournalEntry, it will be used to display // in the drop-down list on the Back/Forward buttons // Journal entries aren't recycled when going back\forward. A new JournalEntry is always created, so // we need to set the name each time // string name = null; if (journalEntry.CustomContentState != null) { name = journalEntry.CustomContentState.JournalEntryName; } if (string.IsNullOrEmpty(name)) { DependencyObject dependencyObject = _bp as DependencyObject; if (dependencyObject != null) { name = (string)dependencyObject.GetValue(JournalEntry.NameProperty); if (String.IsNullOrEmpty(name) && dependencyObject is Page) { name = (dependencyObject as Page).Title; } } if (!String.IsNullOrEmpty(name)) { if (_currentSource != null) { string fragment = BindUriHelper.GetFragment(_currentSource); if (!string.IsNullOrEmpty(fragment)) { name = name + "#" + fragment; } } } else { // Page.WindowTitle is just a shortcut to Window.Title. // The window title is used as a journal entry name only for a top-level container. NavigationWindow navWin = JournalScope == null ? null : JournalScope.NavigatorHost as NavigationWindow; if (navWin != null && this == navWin.NavigationService && !String.IsNullOrEmpty(navWin.Title)) { if (CurrentSource != null) { name = String.Format(CultureInfo.CurrentCulture, "{0} ({1})", navWin.Title, JournalEntry.GetDisplayName(_currentSource, SiteOfOriginContainer.SiteOfOrigin)); } else { name = navWin.Title; } } else { // if not title was set we use the uri if it is available. if (CurrentSource != null) { name = JournalEntry.GetDisplayName(_currentSource, SiteOfOriginContainer.SiteOfOrigin); } else { name = SR.Get(SRID.Untitled); } } } } journalEntry.Name = name; if (journalReason == JournalReason.NewContentNavigation) { journalEntry.SaveState(_bp); } return journalEntry; }
private JournalEntry UpdateJournal( NavigationMode navigationMode, JournalReason journalReason, JournalEntry destinationJournalEntry) { Debug.Assert(navigationMode == NavigationMode.New || navigationMode == NavigationMode.Back || navigationMode == NavigationMode.Forward, "The journal should not be updated on Refresh."); // The point of this assert is that there should be no destinationJournalEntry for // navigationMode=New, but it is always required for Back/Fwd. Debug.Assert(destinationJournalEntry == null ^ (navigationMode == NavigationMode.Back || navigationMode == NavigationMode.Forward)); JournalEntry journalEntry = null; if (!_doNotJournalCurrentContent) { journalEntry = MakeJournalEntry(journalReason); } if (journalEntry == null) { _doNotJournalCurrentContent = false; // This case will be true when we have navigated to null and then gone back. We cannot add null to the journal // but we still need to commit the back navigation to the journal so the journal state stays sane. if ((navigationMode == NavigationMode.Back || navigationMode == NavigationMode.Forward) && JournalScope != null) { JournalScope.Journal.CommitJournalNavigation(destinationJournalEntry); } // There's no need to do anything here for a New navigation. return null; } // EnsureJournal() should be called no earlier than here. Only the second navigation in a // NavigationService really requires a journal. // In particular, a child Frame should not be forced to create its own journal when it // is being re-navigated by DataStreams.Load(), because it doesn't yet have access to the // parent JournalNavigationScope. JournalNavigationScope journalScope = EnsureJournal(); if (journalScope == null) { return null; } PageFunctionBase pfBase = _bp as PageFunctionBase; if (pfBase != null) { // PageFunctions that don't show UI don't get navigated to in the journal // We still need to add it to the journal since we need to resume this when its child finishes // This codepath is not executed if this pagefunction finished without launching a child. // That case is handled in HandleFinish if (navigationMode == NavigationMode.New && pfBase.Content == null) { journalEntry.EntryType = JournalEntryType.UiLess; } } journalScope.Journal.UpdateCurrentEntry(journalEntry); if (journalEntry.IsNavigable()) { CallUpdateTravelLog(navigationMode == NavigationMode.New); } if (navigationMode == NavigationMode.New) { journalScope.Journal.RecordNewNavigation(); } else // Back or Forward { journalScope.Journal.CommitJournalNavigation(destinationJournalEntry); } _customContentStateToSave = null; // not needed anymore return journalEntry; }
/// <summary> /// <see cref="IJournalState.GetJournalState"/> /// </summary> CustomJournalStateInternal IJournalState.GetJournalState(JournalReason journalReason) { int cp = -1; LogicalDirection cpDirection = LogicalDirection.Forward; IFlowDocumentViewer viewer = CurrentViewer; if (viewer != null) { TextPointer contentPosition = viewer.ContentPosition as TextPointer; if (contentPosition != null) { cp = contentPosition.Offset; cpDirection = contentPosition.LogicalDirection; } } return new JournalState(cp, cpDirection, Zoom, ViewingMode); }