/// <summary>
        /// Craetes a new FamFrame and adds the resulting NavigationService to the 
        /// WindowWrapper collection. In addition, it optionally will setup the 
        /// shell back button to react to the nav of the Frame.
        /// A developer should call this when creating a new/secondary frame.
        /// The shell back button should only be setup one time.
        /// </summary>
        public Services.NavigationService.NavigationService NavigationServiceFactory(BackButton backButton, ExistingContent existingContent)
        {
            var frame = new Frame
            {
                Language = Windows.Globalization.ApplicationLanguages.Languages[0],
                Content = (existingContent == ExistingContent.Include) ? Window.Current.Content : null,
            };

            var navigationService = new Services.NavigationService.NavigationService(frame);
            WindowWrapper.Current().NavigationServices.Add(navigationService);

            if (backButton == BackButton.Attach)
            {
                // TODO: unattach others

                // update shell back when backstack changes
                // only the default frame in this case because secondary should not dismiss the app
                frame.RegisterPropertyChangedCallback(Frame.BackStackDepthProperty, (s, args) => UpdateShellBackButton());

                // update shell back when navigation occurs
                // only the default frame in this case because secondary should not dismiss the app
                frame.Navigated += (s, args) => UpdateShellBackButton();
            }

            // this is always okay to check, default or not
            // expire any state (based on expiry)
            DateTime cacheDate;
            // default the cache age to very fresh if not known
            var otherwise = DateTime.MinValue.ToString();
            if (DateTime.TryParse(navigationService.FrameFacade.GetFrameState(CacheDateKey, otherwise), out cacheDate))
            {
                var cacheAge = DateTime.Now.Subtract(cacheDate);
                if (cacheAge >= CacheMaxDuration)
                {
                    // clear state in every nav service in every view
                    foreach (var service in WindowWrapper.ActiveWrappers.SelectMany(x => x.NavigationServices))
                    {
                        service.FrameFacade.ClearFrameState();
                    }
                }
            }
            else
            {
                // no date, that's okay
            }

            return navigationService;
        }
 private static void AttachFrameEvents(NavButtonBehavior behavior, Frame frame)
 {
     if (behavior == null || frame == null)
     {
         return;
     }
     FrameEventRegistration eventReg;
     if (behavior._eventRegistrationInfo.TryGetValue(frame, out eventReg))
     {
         // events already attached
         return;
     }
     eventReg = new FrameEventRegistration();
     behavior._eventRegistrationInfo.Add(frame, eventReg);
     eventReg.GoBackReg = frame.RegisterPropertyChangedCallback(Frame.CanGoBackProperty, (s, e) => behavior.CalculateThrottled());
     eventReg.GoForwardReg = frame.RegisterPropertyChangedCallback(Frame.CanGoForwardProperty, (s, e) => behavior.CalculateThrottled());
     frame.Navigated += behavior.OnNavigated;
     frame.Loaded += behavior.FrameOnLoaded;
 }
        // this is private because there's no reason for the developer to call this
        private Frame InitializeFrame(ILaunchActivatedEventArgs e)
        {
            // do not recreate the frame
            if (Window.Current.Content is Frame)
                return Window.Current.Content as Frame;

            // first show the splash 
            var splashScreen = default(UIElement);
            if (SplashFactory != null)
            {
                splashScreen = SplashFactory(e.SplashScreen);
                Window.Current.Content = splashScreen;
                Window.Current.Activate();
            }
            else
            {
                // if there is no SplashScreen then the default/static splash will show.
            }

            // in any case, next create a new, default frame
            var defaultFrame = new Frame
            {
                Language = Windows.Globalization.ApplicationLanguages.Languages[0]
            };

            // set default frame as primary, default visual
            Window.Current.Content = defaultFrame;

            // next setup the default view
            var navigationService = new Services.NavigationService.NavigationService(defaultFrame);
            WindowWrapper.Current().NavigationServices.Add(navigationService);

            // this anon method will be used to refresh the shell back button
            Action updateShellBack = () =>
            {
                // show the shell back only if there is anywhere to go in the default frame
                SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
                    (ShowShellBackButton && NavigationService.Frame.CanGoBack)
                        ? AppViewBackButtonVisibility.Visible
                        : AppViewBackButtonVisibility.Collapsed;
            };

            // update shell back when backstack changes
            // only the default frame in this case because secondary should not dismiss the app
            defaultFrame.RegisterPropertyChangedCallback(Frame.BackStackDepthProperty, (s, args) => updateShellBack());

            // update shell back when navigation occurs
            // only the default frame in this case because secondary should not dismiss the app
            defaultFrame.Navigated += (s, args) => updateShellBack();

            // expire any state (based on expiry)
            DateTime cacheDate;
            // default the cache age to very fresh if not known
            var otherwise = DateTime.MinValue.ToString();
            if (DateTime.TryParse(navigationService.FrameFacade.GetFrameState(CacheDateKey, otherwise), out cacheDate))
            {
                var cacheAge = DateTime.Now.Subtract(cacheDate);
                if (cacheAge >= CacheMaxDuration)
                {
                    // clear state in every nav service in every view
                    foreach (var service in WindowWrapper.ActiveWrappers.SelectMany(x => x.NavigationServices))
                    {
                        service.FrameFacade.ClearFrameState();
                    }
                }
            }
            else
            {
                // no date, that's okay
            }

            // finally return our new frame
            return defaultFrame;
        }