/// <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; }