JournalNavigationScope.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / MS / Internal / AppModel / JournalNavigationScope.cs / 1 / JournalNavigationScope.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//      JournalNavigationScope is the entity that owns a Journal and handles or dispatches journaling- 
//      related operations in a tree of navigators sharing the same journal.
//      NavigationWindow aggregates a JournalNavigationScope instance, as it always needs to have a 
//      journal. So does Frame but only when its JournalOwnership=OwnsJournal.
//      JournalNavigationScope is not a standalone class. It delegate certain operations to its
//      "navigator host" via the IJournalNavigationScopeHost interface or directly to the host's
//      NavigationService. 
//
// History: 
//  11/14/05: ChangoV       Created; parts factored out of NavigationWindow. 
//
//--------------------------------------------------------------------------- 

using System;
using System.Collections;
using System.Security; 
using System.Diagnostics;
 
using System.Windows; 
using System.Windows.Navigation;
using MS.Internal.KnownBoxes; 


namespace MS.Internal.AppModel
{ 
    internal class JournalNavigationScope: DependencyObject, INavigator
    { 
        internal JournalNavigationScope(IJournalNavigationScopeHost host) 
        {
            _host = host; 
            _rootNavSvc = host.NavigationService;
        }

        #region DependencyProperties 
        // These properties are declared here, but actual values are set on NavigationWindow and Frame.
        // See OnBackForwardStateChange(). 
 
        // CanGoBack & CanGoForward DPs
 
        private static readonly DependencyPropertyKey CanGoBackPropertyKey =
            DependencyProperty.RegisterReadOnly(
                    "CanGoBack", typeof(bool), typeof(JournalNavigationScope),
                    new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        internal static readonly DependencyProperty CanGoBackProperty = 
            CanGoBackPropertyKey.DependencyProperty; 

        private static readonly DependencyPropertyKey CanGoForwardPropertyKey = 
            DependencyProperty.RegisterReadOnly(
                    "CanGoForward", typeof(bool), typeof(JournalNavigationScope),
                    new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
 
        internal static readonly DependencyProperty CanGoForwardProperty =
            CanGoForwardPropertyKey.DependencyProperty; 
 
        // BackStack & ForwardStack DPs
 
        private static readonly DependencyPropertyKey BackStackPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "BackStack", typeof(IEnumerable), typeof(JournalNavigationScope),
                        new FrameworkPropertyMetadata((IEnumerable)null)); 

        internal static readonly DependencyProperty BackStackProperty = 
                BackStackPropertyKey.DependencyProperty; 

        private static readonly DependencyPropertyKey ForwardStackPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "ForwardStack", typeof(IEnumerable), typeof(JournalNavigationScope),
                        new FrameworkPropertyMetadata((IEnumerable)null));
 
        internal static readonly DependencyProperty ForwardStackProperty =
                ForwardStackPropertyKey.DependencyProperty; 
 
        #endregion DependencyProperties
 
        #region INavigatorBase Members

        public Uri Source
        { 
            get { return _host.Source; }
            set { _host.Source = value; } 
        } 
        public Uri CurrentSource
        { 
            get { return _host.CurrentSource; }
        }
        public object Content
        { 
            get { return _host.Content; }
            set { _host.Content = value; } 
        } 

        public bool Navigate(Uri source) 
        {
            return _host.Navigate(source);
        }
        public bool Navigate(Uri source, object extraData) 
        {
            return _host.Navigate(source, extraData); 
        } 
        public bool Navigate(object content)
        { 
            return _host.Navigate(content);
        }
        public bool Navigate(object content, object extraData)
        { 
            return _host.Navigate(content, extraData);
        } 
 
        public void StopLoading()
        { 
            _host.StopLoading();
        }

        public void Refresh() 
        {
            _host.Refresh(); 
        } 

        public event NavigatingCancelEventHandler Navigating 
        {
            add { _host.Navigating += value; }
            remove { _host.Navigating -= value; }
        } 
        public event NavigationProgressEventHandler NavigationProgress
        { 
            add { _host.NavigationProgress += value; } 
            remove { _host.NavigationProgress -= value; }
        } 
        public event NavigationFailedEventHandler NavigationFailed
        {
            add { _host.NavigationFailed += value; }
            remove { _host.NavigationFailed -= value; } 
        }
        public event NavigatedEventHandler Navigated 
        { 
            add { _host.Navigated += value; }
            remove { _host.Navigated -= value; } 
        }
        public event LoadCompletedEventHandler LoadCompleted
        {
            add { _host.LoadCompleted += value; } 
            remove { _host.LoadCompleted -= value; }
        } 
        public event NavigationStoppedEventHandler NavigationStopped 
        {
            add { _host.NavigationStopped += value; } 
            remove { _host.NavigationStopped -= value; }
        }
        public event FragmentNavigationEventHandler FragmentNavigation
        { 
            add { _host.FragmentNavigation += value; }
            remove { _host.FragmentNavigation -= value; } 
        } 

        #endregion INavigatorBase 

        #region INavigator Members
        //
        // Because the INavigator methods of NavigationWindow and Frame simply forward here, 
        // _host.VerifyContextAndObjectState() should be called at every entry point.
 
        public bool CanGoForward 
        {
            get 
            {
                _host.VerifyContextAndObjectState();
                return _journal != null && !InAppShutdown && _journal.CanGoForward;
            } 
        }
        public bool CanGoBack 
        { 
            get
            { 
                _host.VerifyContextAndObjectState();
                return _journal != null && !InAppShutdown && _journal.CanGoBack;
            }
        } 

        /// 
        /// Critical - calls RBW.GoForwardOverride, which is critical. 
        /// Safe: We validate that you can only go back within your application.
        /// Note: SecurityTreatAsSafe is needed here because the method is effectively internal 
        ///   (INavigator is internal). It says 'public' because C# requires methods implementing
        ///   interfaces to be public.
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        public void GoForward()
        { 
            // CanGoForward checks the calling thread and InAppShutdown as well 
            if (CanGoForward == false)
                throw new InvalidOperationException(SR.Get(SRID.NoForwardEntry)); 

            if (!_host.GoForwardOverride())
            {
                JournalEntry je = Journal.BeginForwardNavigation(); 
                // If je is null it indicates that we are going going "forward" to the currently
                // displayed page which has no journal entry. The comment in BeginForwardNavigation 
                // explains how this can happen. 
                if (je == null)
                { 
                    _rootNavSvc.StopLoading();
                    return;
                }
                NavigateToEntry(je); 
                // NavigateToEntry() should call AbortJournalNavigation() if navigation is canceled.
            } 
        } 

        /// 
        /// Critical - calls RBW.GoBackOverride, which is critical.
        /// Safe: We validate that you can only go back within your application.
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        public void GoBack()
        { 
            // CanGoBack checks the calling thread and InAppShutdown as well 
            if (CanGoBack == false)
                throw new InvalidOperationException(SR.Get(SRID.NoBackEntry)); 

            if (!_host.GoBackOverride())
            {
                JournalEntry je = Journal.BeginBackNavigation(); 
                if (je == null) // See comment in GoForwardInternal().
                { 
                    _rootNavSvc.StopLoading(); 
                    return;
                } 
                NavigateToEntry(je);
                // NavigateToEntry() should call Journal.AbortJournalNavigation() if navigation is canceled.
            }
        } 

        public void AddBackEntry(CustomContentState state) 
        { 
            _host.VerifyContextAndObjectState();
            _rootNavSvc.AddBackEntry(state); 
        }

        public JournalEntry RemoveBackEntry()
        { 
            _host.VerifyContextAndObjectState();
            return _journal == null ? null : _journal.RemoveBackEntry(); 
        } 

        public System.Collections.IEnumerable BackStack 
        {
            get
            {
                _host.VerifyContextAndObjectState(); 
                return Journal.BackStack;
            } 
        } 

        public System.Collections.IEnumerable ForwardStack 
        {
            get
            {
                _host.VerifyContextAndObjectState(); 
                return Journal.ForwardStack;
            } 
        } 

        JournalNavigationScope INavigator.GetJournal(bool create) 
        {
            return this;
        }
 
        #endregion INavigator
 
        //----------------------------------------------------- 
        //
        //  Internal Methods 
        //
        //-----------------------------------------------------
        #region Internal Methods
 
        /// 
        /// The Journal instance needs to be lazily-created to allow restoring a deserialized journal 
        /// from the TravelLog or from a child Frame's journaled state (Frame.FramePersistState). 
        /// Call this method to make the back stack and forward stack objects available and to allow
        /// anyone to register journal change event handlers. 
        /// 
        internal void EnsureJournal()
        {
           // The getter lazily creates Journal and notifies the host. 
           Journal journal = Journal;
           Debug.Assert(journal != null); 
        } 

        internal bool CanInvokeJournalEntry(int entryId) 
        {
            // _journal could be null for .deploy apps since the main (second) app is created after a delay
            // (the first app is created to show the progress UI and the main app is created when bits are ready)
            if (_journal == null) 
                return false;
 
            int realIndex = _journal.FindIndexForEntryWithId(entryId); 
            if (realIndex == -1)
                return false; 

            JournalEntry entry = _journal[realIndex];
            // Journal.IsNavigable() will apply the filter, which is normally IsEntryNavigable().
            return _journal.IsNavigable(entry); 
        }
 
        ///  
        /// Critical:  causes a navigate
        /// TreatAsSafe:  but only navigates to an existing entry in our journal, which is limited to the app. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal bool NavigateToEntry(int index)
        { 
            JournalEntry entry = Journal[index];
            return NavigateToEntry(entry); 
        } 

        internal bool NavigateToEntry(JournalEntry entry) 
        {
            if (entry == null)
            {
                Debug.Fail("Tried to navigate to a null JournalEntry."); 
                return false;
            } 
            if (!Journal.IsNavigable(entry)) 
            {
                Debug.Fail("Tried to navigate to a non-navigable journal entry."); 
                return false;
            }

            NavigationService navigationService = _rootNavSvc.FindTarget(entry.NavigationServiceId); 
            Debug.Assert(navigationService != null, "NavigationService cannot be null for journal navigations");
 
            NavigationMode mode = Journal.GetNavigationMode(entry); 
            bool navigated = false;
            try 
            {
                navigated = entry.Navigate(navigationService.INavigatorHost, mode);
            }
            finally 
            {
                if (!navigated) 
                { 
                    AbortJournalNavigation();
                } 
            }
            return navigated;
        }
 
        internal void AbortJournalNavigation()
        { 
            if (_journal != null) 
            {
                _journal.AbortJournalNavigation(); 
            }
        }

        internal INavigatorBase FindTarget(string name) 
        {
            return _rootNavSvc.FindTarget(name); 
        } 

        internal static void ClearDPValues(DependencyObject navigator) 
        {
            navigator.SetValue(CanGoBackPropertyKey, BooleanBoxes.FalseBox);
            navigator.SetValue(CanGoForwardPropertyKey, BooleanBoxes.FalseBox);
 
            navigator.SetValue(BackStackPropertyKey, null);
            navigator.SetValue(ForwardStackPropertyKey, null); 
        } 

#if DEBUG 
        /// 
        /// DO NOT USE - Public debug method to test the journal state for PageFunctions
        /// 
        internal string PrintJournal() 
        {
            Journal journal = Journal; 
            String s = ""; 
            for (int i = 0; i < journal.TotalCount; i++)
            { 
                if (journal[i].IsNavigable())
                {
                    s += "o"  ;
                } 
                else
                { 
                    switch (journal[i].EntryType) 
                    {
                        case JournalEntryType.Navigable: 
                            s += "o";
                            break;
                        case JournalEntryType.UiLess:
                            s += "u"; 
                            break;
                        default: 
                            Invariant.Assert(false, "Invalid JournalEntryType: " + journal[i].EntryType); 
                            break;
                    } 
                }
            }
            return s;
        } 
#endif
        #endregion 
 
        //------------------------------------------------------
        // 
        //  Internal Properties
        //
        //-----------------------------------------------------
        #region Internal Properties 

        ///  
        /// The Journal instance needs to be lazily-created to allow restoring a deserialized journal 
        /// from the TravelLog or from a child Frame's journaled state (Frame.FramePersistState).
        /// The getter triggers the Journal creation and notifes the host. 
        /// 
        /// 
        #if DEBUG
        // to prevent creating the Journal instance prematurely while debugging 
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        #endif 
        internal Journal Journal 
        {
            get 
            {
                if (_journal == null)
                {
                    Journal = new Journal(); 
                }
                return _journal; 
            } 
            // Used by the getter; also by RootBrowserWindow and Frame to install a deserialized Journal.
            set 
            {
                Debug.Assert(_journal == null && value != null,
                    "The Journal should be set only once and never removed."); // see bug 1367999
                _journal = value; 
                _journal.Filter = new JournalEntryFilter(this.IsEntryNavigable);
                _journal.BackForwardStateChange += new EventHandler(OnBackForwardStateChange); 
 
                DependencyObject navigator = (DependencyObject)_host;
                navigator.SetValue(BackStackPropertyKey, _journal.BackStack); 
                navigator.SetValue(ForwardStackPropertyKey, _journal.ForwardStack);

                _host.OnJournalAvailable();
            } 
        }
 
        internal NavigationService RootNavigationService 
        {
            get { return _rootNavSvc; } 
        }

        internal INavigatorBase NavigatorHost
        { 
            get { return _host; }
        } 
 
        #endregion Internal Properties
 
        //------------------------------------------------------
        //
        //  Private Methods
        // 
        //------------------------------------------------------
        #region Private Methods 
 
        private void OnBackForwardStateChange(object sender, EventArgs e)
        { 
            Debug.Assert(sender == _journal);

            // Update CanGoBack and CanGoForward on the host navigator, only if actually changed.
            DependencyObject navigator = (DependencyObject)_host; 
            bool canGoBackFwdChanged = false;
            bool newState = _journal.CanGoBack; 
            if (newState != (bool)navigator.GetValue(CanGoBackProperty)) 
            {
                navigator.SetValue(CanGoBackPropertyKey, BooleanBoxes.Box(newState)); 
                canGoBackFwdChanged = true;
            }
            newState = _journal.CanGoForward;
            if (newState != (bool)navigator.GetValue(CanGoForwardProperty)) 
            {
                navigator.SetValue(CanGoForwardPropertyKey, BooleanBoxes.Box(newState)); 
                canGoBackFwdChanged = true; 
            }
 
            if (canGoBackFwdChanged)
            {
                System.Windows.Input.CommandManager.InvalidateRequerySuggested();
            } 
        }
 
        ///  
        /// This is the filter callback for Journal. To keep a single code path and to avoid
        /// inconsistent results, use Journal.IsNavigable() instead of this method. 
        /// 
        private bool IsEntryNavigable(JournalEntry entry)
        {
            if (entry == null || !entry.IsNavigable()) 
                return false;
            // If the entry is associated with a child frame, the frame has to be currently available. 
            // For a given journal entry group, only the "exit" entry is made visible. Effectively, 
            // this collapses all fragment-navigation and CustomContentState-navigation entries for
            // a page (other than the current one) to a single entry. That's what IE does. 
            NavigationService ns = _rootNavSvc.FindTarget(entry.NavigationServiceId);
            return ns != null
                && (ns.ContentId == entry.ContentId || entry.JEGroupState.GroupExitEntry == entry);
        } 

        private bool InAppShutdown 
        { 
            get { return System.Windows.Application.IsShuttingDown; }
        } 

        #endregion

        //----------------------------------------------------- 
        //
        //  Private Fields 
        // 
        //------------------------------------------------------
 
        #region Private Fields

        private IJournalNavigationScopeHost _host;
        private NavigationService _rootNavSvc; // == _host.NavigationService 
        private Journal _journal; // lazily-created; see Journal property
 
        #endregion Private Fields 
    };
 

    /// 
    /// The interface through which JournalNavigationScope talks back to its navigator host.
    ///  
    internal interface IJournalNavigationScopeHost: INavigatorBase
    { 
        NavigationService NavigationService { get; } 

        void VerifyContextAndObjectState(); 

        void OnJournalAvailable();

        ///  
        /// Allows the navigator host to do its own handling of GoBack. Currently used by
        /// RootBrowserWindow to do the TravelLog integration. 
        ///  
        ///  True to cancel the normal handling of GoBack 
        bool GoBackOverride(); 
        bool GoForwardOverride();
    };
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//      JournalNavigationScope is the entity that owns a Journal and handles or dispatches journaling- 
//      related operations in a tree of navigators sharing the same journal.
//      NavigationWindow aggregates a JournalNavigationScope instance, as it always needs to have a 
//      journal. So does Frame but only when its JournalOwnership=OwnsJournal.
//      JournalNavigationScope is not a standalone class. It delegate certain operations to its
//      "navigator host" via the IJournalNavigationScopeHost interface or directly to the host's
//      NavigationService. 
//
// History: 
//  11/14/05: ChangoV       Created; parts factored out of NavigationWindow. 
//
//--------------------------------------------------------------------------- 

using System;
using System.Collections;
using System.Security; 
using System.Diagnostics;
 
using System.Windows; 
using System.Windows.Navigation;
using MS.Internal.KnownBoxes; 


namespace MS.Internal.AppModel
{ 
    internal class JournalNavigationScope: DependencyObject, INavigator
    { 
        internal JournalNavigationScope(IJournalNavigationScopeHost host) 
        {
            _host = host; 
            _rootNavSvc = host.NavigationService;
        }

        #region DependencyProperties 
        // These properties are declared here, but actual values are set on NavigationWindow and Frame.
        // See OnBackForwardStateChange(). 
 
        // CanGoBack & CanGoForward DPs
 
        private static readonly DependencyPropertyKey CanGoBackPropertyKey =
            DependencyProperty.RegisterReadOnly(
                    "CanGoBack", typeof(bool), typeof(JournalNavigationScope),
                    new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        internal static readonly DependencyProperty CanGoBackProperty = 
            CanGoBackPropertyKey.DependencyProperty; 

        private static readonly DependencyPropertyKey CanGoForwardPropertyKey = 
            DependencyProperty.RegisterReadOnly(
                    "CanGoForward", typeof(bool), typeof(JournalNavigationScope),
                    new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
 
        internal static readonly DependencyProperty CanGoForwardProperty =
            CanGoForwardPropertyKey.DependencyProperty; 
 
        // BackStack & ForwardStack DPs
 
        private static readonly DependencyPropertyKey BackStackPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "BackStack", typeof(IEnumerable), typeof(JournalNavigationScope),
                        new FrameworkPropertyMetadata((IEnumerable)null)); 

        internal static readonly DependencyProperty BackStackProperty = 
                BackStackPropertyKey.DependencyProperty; 

        private static readonly DependencyPropertyKey ForwardStackPropertyKey = 
                DependencyProperty.RegisterReadOnly(
                        "ForwardStack", typeof(IEnumerable), typeof(JournalNavigationScope),
                        new FrameworkPropertyMetadata((IEnumerable)null));
 
        internal static readonly DependencyProperty ForwardStackProperty =
                ForwardStackPropertyKey.DependencyProperty; 
 
        #endregion DependencyProperties
 
        #region INavigatorBase Members

        public Uri Source
        { 
            get { return _host.Source; }
            set { _host.Source = value; } 
        } 
        public Uri CurrentSource
        { 
            get { return _host.CurrentSource; }
        }
        public object Content
        { 
            get { return _host.Content; }
            set { _host.Content = value; } 
        } 

        public bool Navigate(Uri source) 
        {
            return _host.Navigate(source);
        }
        public bool Navigate(Uri source, object extraData) 
        {
            return _host.Navigate(source, extraData); 
        } 
        public bool Navigate(object content)
        { 
            return _host.Navigate(content);
        }
        public bool Navigate(object content, object extraData)
        { 
            return _host.Navigate(content, extraData);
        } 
 
        public void StopLoading()
        { 
            _host.StopLoading();
        }

        public void Refresh() 
        {
            _host.Refresh(); 
        } 

        public event NavigatingCancelEventHandler Navigating 
        {
            add { _host.Navigating += value; }
            remove { _host.Navigating -= value; }
        } 
        public event NavigationProgressEventHandler NavigationProgress
        { 
            add { _host.NavigationProgress += value; } 
            remove { _host.NavigationProgress -= value; }
        } 
        public event NavigationFailedEventHandler NavigationFailed
        {
            add { _host.NavigationFailed += value; }
            remove { _host.NavigationFailed -= value; } 
        }
        public event NavigatedEventHandler Navigated 
        { 
            add { _host.Navigated += value; }
            remove { _host.Navigated -= value; } 
        }
        public event LoadCompletedEventHandler LoadCompleted
        {
            add { _host.LoadCompleted += value; } 
            remove { _host.LoadCompleted -= value; }
        } 
        public event NavigationStoppedEventHandler NavigationStopped 
        {
            add { _host.NavigationStopped += value; } 
            remove { _host.NavigationStopped -= value; }
        }
        public event FragmentNavigationEventHandler FragmentNavigation
        { 
            add { _host.FragmentNavigation += value; }
            remove { _host.FragmentNavigation -= value; } 
        } 

        #endregion INavigatorBase 

        #region INavigator Members
        //
        // Because the INavigator methods of NavigationWindow and Frame simply forward here, 
        // _host.VerifyContextAndObjectState() should be called at every entry point.
 
        public bool CanGoForward 
        {
            get 
            {
                _host.VerifyContextAndObjectState();
                return _journal != null && !InAppShutdown && _journal.CanGoForward;
            } 
        }
        public bool CanGoBack 
        { 
            get
            { 
                _host.VerifyContextAndObjectState();
                return _journal != null && !InAppShutdown && _journal.CanGoBack;
            }
        } 

        /// 
        /// Critical - calls RBW.GoForwardOverride, which is critical. 
        /// Safe: We validate that you can only go back within your application.
        /// Note: SecurityTreatAsSafe is needed here because the method is effectively internal 
        ///   (INavigator is internal). It says 'public' because C# requires methods implementing
        ///   interfaces to be public.
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        public void GoForward()
        { 
            // CanGoForward checks the calling thread and InAppShutdown as well 
            if (CanGoForward == false)
                throw new InvalidOperationException(SR.Get(SRID.NoForwardEntry)); 

            if (!_host.GoForwardOverride())
            {
                JournalEntry je = Journal.BeginForwardNavigation(); 
                // If je is null it indicates that we are going going "forward" to the currently
                // displayed page which has no journal entry. The comment in BeginForwardNavigation 
                // explains how this can happen. 
                if (je == null)
                { 
                    _rootNavSvc.StopLoading();
                    return;
                }
                NavigateToEntry(je); 
                // NavigateToEntry() should call AbortJournalNavigation() if navigation is canceled.
            } 
        } 

        /// 
        /// Critical - calls RBW.GoBackOverride, which is critical.
        /// Safe: We validate that you can only go back within your application.
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        public void GoBack()
        { 
            // CanGoBack checks the calling thread and InAppShutdown as well 
            if (CanGoBack == false)
                throw new InvalidOperationException(SR.Get(SRID.NoBackEntry)); 

            if (!_host.GoBackOverride())
            {
                JournalEntry je = Journal.BeginBackNavigation(); 
                if (je == null) // See comment in GoForwardInternal().
                { 
                    _rootNavSvc.StopLoading(); 
                    return;
                } 
                NavigateToEntry(je);
                // NavigateToEntry() should call Journal.AbortJournalNavigation() if navigation is canceled.
            }
        } 

        public void AddBackEntry(CustomContentState state) 
        { 
            _host.VerifyContextAndObjectState();
            _rootNavSvc.AddBackEntry(state); 
        }

        public JournalEntry RemoveBackEntry()
        { 
            _host.VerifyContextAndObjectState();
            return _journal == null ? null : _journal.RemoveBackEntry(); 
        } 

        public System.Collections.IEnumerable BackStack 
        {
            get
            {
                _host.VerifyContextAndObjectState(); 
                return Journal.BackStack;
            } 
        } 

        public System.Collections.IEnumerable ForwardStack 
        {
            get
            {
                _host.VerifyContextAndObjectState(); 
                return Journal.ForwardStack;
            } 
        } 

        JournalNavigationScope INavigator.GetJournal(bool create) 
        {
            return this;
        }
 
        #endregion INavigator
 
        //----------------------------------------------------- 
        //
        //  Internal Methods 
        //
        //-----------------------------------------------------
        #region Internal Methods
 
        /// 
        /// The Journal instance needs to be lazily-created to allow restoring a deserialized journal 
        /// from the TravelLog or from a child Frame's journaled state (Frame.FramePersistState). 
        /// Call this method to make the back stack and forward stack objects available and to allow
        /// anyone to register journal change event handlers. 
        /// 
        internal void EnsureJournal()
        {
           // The getter lazily creates Journal and notifies the host. 
           Journal journal = Journal;
           Debug.Assert(journal != null); 
        } 

        internal bool CanInvokeJournalEntry(int entryId) 
        {
            // _journal could be null for .deploy apps since the main (second) app is created after a delay
            // (the first app is created to show the progress UI and the main app is created when bits are ready)
            if (_journal == null) 
                return false;
 
            int realIndex = _journal.FindIndexForEntryWithId(entryId); 
            if (realIndex == -1)
                return false; 

            JournalEntry entry = _journal[realIndex];
            // Journal.IsNavigable() will apply the filter, which is normally IsEntryNavigable().
            return _journal.IsNavigable(entry); 
        }
 
        ///  
        /// Critical:  causes a navigate
        /// TreatAsSafe:  but only navigates to an existing entry in our journal, which is limited to the app. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal bool NavigateToEntry(int index)
        { 
            JournalEntry entry = Journal[index];
            return NavigateToEntry(entry); 
        } 

        internal bool NavigateToEntry(JournalEntry entry) 
        {
            if (entry == null)
            {
                Debug.Fail("Tried to navigate to a null JournalEntry."); 
                return false;
            } 
            if (!Journal.IsNavigable(entry)) 
            {
                Debug.Fail("Tried to navigate to a non-navigable journal entry."); 
                return false;
            }

            NavigationService navigationService = _rootNavSvc.FindTarget(entry.NavigationServiceId); 
            Debug.Assert(navigationService != null, "NavigationService cannot be null for journal navigations");
 
            NavigationMode mode = Journal.GetNavigationMode(entry); 
            bool navigated = false;
            try 
            {
                navigated = entry.Navigate(navigationService.INavigatorHost, mode);
            }
            finally 
            {
                if (!navigated) 
                { 
                    AbortJournalNavigation();
                } 
            }
            return navigated;
        }
 
        internal void AbortJournalNavigation()
        { 
            if (_journal != null) 
            {
                _journal.AbortJournalNavigation(); 
            }
        }

        internal INavigatorBase FindTarget(string name) 
        {
            return _rootNavSvc.FindTarget(name); 
        } 

        internal static void ClearDPValues(DependencyObject navigator) 
        {
            navigator.SetValue(CanGoBackPropertyKey, BooleanBoxes.FalseBox);
            navigator.SetValue(CanGoForwardPropertyKey, BooleanBoxes.FalseBox);
 
            navigator.SetValue(BackStackPropertyKey, null);
            navigator.SetValue(ForwardStackPropertyKey, null); 
        } 

#if DEBUG 
        /// 
        /// DO NOT USE - Public debug method to test the journal state for PageFunctions
        /// 
        internal string PrintJournal() 
        {
            Journal journal = Journal; 
            String s = ""; 
            for (int i = 0; i < journal.TotalCount; i++)
            { 
                if (journal[i].IsNavigable())
                {
                    s += "o"  ;
                } 
                else
                { 
                    switch (journal[i].EntryType) 
                    {
                        case JournalEntryType.Navigable: 
                            s += "o";
                            break;
                        case JournalEntryType.UiLess:
                            s += "u"; 
                            break;
                        default: 
                            Invariant.Assert(false, "Invalid JournalEntryType: " + journal[i].EntryType); 
                            break;
                    } 
                }
            }
            return s;
        } 
#endif
        #endregion 
 
        //------------------------------------------------------
        // 
        //  Internal Properties
        //
        //-----------------------------------------------------
        #region Internal Properties 

        ///  
        /// The Journal instance needs to be lazily-created to allow restoring a deserialized journal 
        /// from the TravelLog or from a child Frame's journaled state (Frame.FramePersistState).
        /// The getter triggers the Journal creation and notifes the host. 
        /// 
        /// 
        #if DEBUG
        // to prevent creating the Journal instance prematurely while debugging 
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        #endif 
        internal Journal Journal 
        {
            get 
            {
                if (_journal == null)
                {
                    Journal = new Journal(); 
                }
                return _journal; 
            } 
            // Used by the getter; also by RootBrowserWindow and Frame to install a deserialized Journal.
            set 
            {
                Debug.Assert(_journal == null && value != null,
                    "The Journal should be set only once and never removed."); // see bug 1367999
                _journal = value; 
                _journal.Filter = new JournalEntryFilter(this.IsEntryNavigable);
                _journal.BackForwardStateChange += new EventHandler(OnBackForwardStateChange); 
 
                DependencyObject navigator = (DependencyObject)_host;
                navigator.SetValue(BackStackPropertyKey, _journal.BackStack); 
                navigator.SetValue(ForwardStackPropertyKey, _journal.ForwardStack);

                _host.OnJournalAvailable();
            } 
        }
 
        internal NavigationService RootNavigationService 
        {
            get { return _rootNavSvc; } 
        }

        internal INavigatorBase NavigatorHost
        { 
            get { return _host; }
        } 
 
        #endregion Internal Properties
 
        //------------------------------------------------------
        //
        //  Private Methods
        // 
        //------------------------------------------------------
        #region Private Methods 
 
        private void OnBackForwardStateChange(object sender, EventArgs e)
        { 
            Debug.Assert(sender == _journal);

            // Update CanGoBack and CanGoForward on the host navigator, only if actually changed.
            DependencyObject navigator = (DependencyObject)_host; 
            bool canGoBackFwdChanged = false;
            bool newState = _journal.CanGoBack; 
            if (newState != (bool)navigator.GetValue(CanGoBackProperty)) 
            {
                navigator.SetValue(CanGoBackPropertyKey, BooleanBoxes.Box(newState)); 
                canGoBackFwdChanged = true;
            }
            newState = _journal.CanGoForward;
            if (newState != (bool)navigator.GetValue(CanGoForwardProperty)) 
            {
                navigator.SetValue(CanGoForwardPropertyKey, BooleanBoxes.Box(newState)); 
                canGoBackFwdChanged = true; 
            }
 
            if (canGoBackFwdChanged)
            {
                System.Windows.Input.CommandManager.InvalidateRequerySuggested();
            } 
        }
 
        ///  
        /// This is the filter callback for Journal. To keep a single code path and to avoid
        /// inconsistent results, use Journal.IsNavigable() instead of this method. 
        /// 
        private bool IsEntryNavigable(JournalEntry entry)
        {
            if (entry == null || !entry.IsNavigable()) 
                return false;
            // If the entry is associated with a child frame, the frame has to be currently available. 
            // For a given journal entry group, only the "exit" entry is made visible. Effectively, 
            // this collapses all fragment-navigation and CustomContentState-navigation entries for
            // a page (other than the current one) to a single entry. That's what IE does. 
            NavigationService ns = _rootNavSvc.FindTarget(entry.NavigationServiceId);
            return ns != null
                && (ns.ContentId == entry.ContentId || entry.JEGroupState.GroupExitEntry == entry);
        } 

        private bool InAppShutdown 
        { 
            get { return System.Windows.Application.IsShuttingDown; }
        } 

        #endregion

        //----------------------------------------------------- 
        //
        //  Private Fields 
        // 
        //------------------------------------------------------
 
        #region Private Fields

        private IJournalNavigationScopeHost _host;
        private NavigationService _rootNavSvc; // == _host.NavigationService 
        private Journal _journal; // lazily-created; see Journal property
 
        #endregion Private Fields 
    };
 

    /// 
    /// The interface through which JournalNavigationScope talks back to its navigator host.
    ///  
    internal interface IJournalNavigationScopeHost: INavigatorBase
    { 
        NavigationService NavigationService { get; } 

        void VerifyContextAndObjectState(); 

        void OnJournalAvailable();

        ///  
        /// Allows the navigator host to do its own handling of GoBack. Currently used by
        /// RootBrowserWindow to do the TravelLog integration. 
        ///  
        ///  True to cancel the normal handling of GoBack 
        bool GoBackOverride(); 
        bool GoForwardOverride();
    };
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK