public async Task SaveNavigationAsync() { DebugWrite($"Frame: {FrameFacadeInternal.FrameId}"); if (CurrentPageType == null) { return; } var args = new CancelEventArgs <Type>(FrameFacadeInternal.CurrentPageType); BeforeSavingNavigation?.Invoke(this, args); if (args.Cancel) { return; } var state = FrameFacadeInternal.PageStateSettingsService(GetType().ToString()); if (state == null) { throw new InvalidOperationException("State container is unexpectedly null"); } state.Write <string>("CurrentPageType", CurrentPageType.AssemblyQualifiedName); state.Write <object>("CurrentPageParam", CurrentPageParam); state.Write <string>("NavigateState", FrameFacadeInternal?.GetNavigationState()); await Task.CompletedTask; }
public void GoBack(NavigationTransitionInfo infoOverride = null) { if (FrameFacadeInternal.CanGoBack) { FrameFacadeInternal.GoBack(infoOverride); } }
public async void Resuming() { DebugWrite($"Frame: {FrameFacadeInternal.FrameId}"); var page = FrameFacadeInternal.Content as Page; if (page != null) { var dataContext = ResolveForPage(page); if (dataContext != null) { dataContext.NavigationService = this; dataContext.Dispatcher = this.GetDispatcherWrapper(); dataContext.SessionState = BootStrapper.Current.SessionState; var pageState = FrameFacadeInternal.PageStateSettingsService(page.GetType(), parameter: FrameFacadeInternal.CurrentPageParam).Values; await dataContext.OnNavigatedToAsync(FrameFacadeInternal.CurrentPageParam, NavigationMode.Refresh, pageState); // update bindings after NavTo initializes data //XamlUtils.InitializeBindings(page); if (page.Content is UserControl pageWith) { XamlUtils.UpdateBindings(pageWith); } else { XamlUtils.UpdateBindings(page); } } } }
async Task NavigateToAsync(NavigationMode mode, object parameter, object frameContent = null) { DebugWrite($"Mode: {mode}, Parameter: {parameter} FrameContent: {frameContent}"); frameContent = frameContent ?? FrameFacadeInternal.Frame.Content; LastNavigationParameter = parameter; LastNavigationType = frameContent.GetType().FullName; var page = frameContent as Page; if (page != null) { if (mode == NavigationMode.New) { var pageState = FrameFacadeInternal.PageStateSettingsService(page.GetType()).Values; pageState?.Clear(); } var dataContext = ResolveForPage(page); if (dataContext != null) { // prepare for state load dataContext.NavigationService = this; dataContext.Dispatcher = this.GetDispatcherWrapper(); dataContext.SessionState = BootStrapper.Current.SessionState; var pageState = FrameFacadeInternal.PageStateSettingsService(page.GetType()).Values; await dataContext.OnNavigatedToAsync(parameter, mode, pageState); // update bindings after NavTo initializes data XamlUtils.InitializeBindings(page); XamlUtils.UpdateBindings(page); } } }
public async Task SaveAsync() { // save navigation state into settings DebugWrite($"Frame: {FrameFacade.FrameId}"); if (CurrentPageType == null) { return; } if (RaiseBeforeSavingNavigation()) { return; } var frameState = Suspension.GetFrameState(); if (frameState == null) { throw new InvalidOperationException("State container is unexpectedly null"); } frameState.Write <string>("CurrentPageType", CurrentPageType.AssemblyQualifiedName); frameState.Write <object>("CurrentPageParam", CurrentPageParam); frameState.Write <string>("NavigateState", FrameFacadeInternal.GetNavigationState()); await Task.CompletedTask; }
public async Task <bool> NavigateAsync(Type page, object parameter = null, NavigationTransitionInfo infoOverride = null) { DebugWrite($"Page: {page}, Parameter: {parameter}, NavigationTransitionInfo: {infoOverride}"); if (page == null) { throw new ArgumentNullException(nameof(page)); } // use CurrentPageType/Param instead of LastNavigationType/Parameter to avoid new navigation to the current // page in some race conditions. if ((page.FullName == CurrentPageType?.FullName) && (parameter == CurrentPageParam)) { return(false); } if ((page.FullName == CurrentPageType?.FullName) && (parameter?.Equals(CurrentPageParam) ?? false)) { return(false); } parameter = SerializationService.Serialize(parameter); await Task.CompletedTask; return(FrameFacadeInternal.Navigate(page, parameter, infoOverride)); }
public async Task <bool> RestoreSavedNavigationAsync() { DebugWrite($"Frame: {FrameFacadeInternal.FrameId}"); try { var state = FrameFacadeInternal.PageStateSettingsService(GetType().ToString()); if (state == null || !state.Exists("CurrentPageType")) { return(false); } FrameFacadeInternal.CurrentPageType = Type.GetType(state.Read <string>("CurrentPageType")); FrameFacadeInternal.CurrentPageParam = state.Read <object>("CurrentPageParam"); FrameFacadeInternal.SetNavigationState(state.Read <string>("NavigateState")); await NavigateToAsync(NavigationMode.Refresh, FrameFacadeInternal.CurrentPageParam); while (FrameFacadeInternal.Frame.Content == null) { Task.Yield().GetAwaiter().GetResult(); } AfterRestoreSavedNavigation?.Invoke(this, FrameFacadeInternal.CurrentPageType); return(true); } catch { return(false); } }
public async Task <bool> NavigateAsync(Type page, object parameter = null, NavigationTransitionInfo infoOverride = null) { DebugWrite($"Page: {page}, Parameter: {parameter}, NavigationTransitionInfo: {infoOverride}"); if (page == null) { throw new ArgumentNullException(nameof(page)); } if ((page.FullName == LastNavigationType) && (parameter == LastNavigationParameter)) { return(false); } if ((page.FullName == LastNavigationType) && (parameter?.Equals(LastNavigationParameter) ?? false)) { return(false); } parameter = SerializationService.Serialize(parameter); await Task.CompletedTask; return(FrameFacadeInternal.Navigate(page, parameter, infoOverride)); }
/* * Navigate<T> allows developers to navigate using a * page key instead of the view type. This is accomplished by * creating a custom Enum and setting up the PageKeys dict * with the Key/Type pairs for your views. The dict is * shared by all NavigationServices and is stored in * the BootStrapper (or Application) of the app. * * Implementation example: * * // define your Enum * public Enum Pages { MainPage, DetailPage } * * // setup the keys dict * var keys = BootStrapper.PageKeys<Views>(); * keys.Add(Pages.MainPage, typeof(Views.MainPage)); * keys.Add(Pages.DetailPage, typeof(Views.DetailPage)); * * // use Navigate<T>() * NavigationService.Navigate(Pages.MainPage); */ // T must be the same custom Enum used with BootStrapper.PageKeys() public bool Navigate <T>(T key, object parameter = null, NavigationTransitionInfo infoOverride = null) where T : struct, IConvertible { DebugWrite($"Key: {key}, Parameter: {parameter}, NavigationTransitionInfo: {infoOverride}"); var keys = BootStrapper.Current.PageKeys <T>(); if (!keys.ContainsKey(key)) { throw new KeyNotFoundException(key.ToString()); } var page = keys[key]; if (page.FullName.Equals(LastNavigationType)) { if (parameter == LastNavigationParameter) { return(false); } if (parameter != null && parameter.Equals(LastNavigationParameter)) { return(false); } } parameter = SerializationService.Serialize(parameter); return(FrameFacadeInternal.Navigate(page, parameter, infoOverride)); }
public void GoBack() { if (FrameFacadeInternal.CanGoBack) { FrameFacadeInternal.GoBack(); } }
public async Task <bool> LoadAsync() { DebugWrite($"Frame: {FrameFacadeInternal.FrameId}"); try { var index = WindowWrapper.Current().NavigationServices.IndexOf(this); var state = FrameFacadeInternal.PageStateSettingsService($"NavigationService{index}"); if (state == null || !state.Exists("CurrentPageType")) { return(false); } FrameFacadeInternal.CurrentPageType = Type.GetType(state.Read <string>("CurrentPageType")); FrameFacadeInternal.CurrentPageParam = state.Read <object>("CurrentPageParam"); FrameFacadeInternal.NavigationService.NavigationState = state.Read <string>("NavigateState"); await NavigateToAsync(NavigationMode.Refresh, FrameFacadeInternal.CurrentPageParam); while (FrameFacadeInternal.Frame.Content == null) { await Task.Delay(1); } AfterRestoreSavedNavigation?.Invoke(this, FrameFacadeInternal.CurrentPageType); return(true); } catch { return(false); } }
public async Task <bool> RefreshAsync() { return(await NavigationOrchestratorAsync(CurrentPageType, CurrentPageParam, NavigationMode.Refresh, () => { Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Reset(); FrameFacadeInternal.SetNavigationState(FrameFacadeInternal.GetNavigationState()); return true; })); }
// after navigate async Task NavigateFromAsync(Page page, INavigable dataContext, bool suspending) { DebugWrite($"Suspending: {suspending}"); dataContext.NavigationService = this; dataContext.Dispatcher = this.GetDispatcherWrapper(); dataContext.SessionState = BootStrapper.Current.SessionState; var pageState = FrameFacadeInternal.PageStateSettingsService(page.GetType()).Values; await dataContext.OnNavigatedFromAsync(pageState, suspending); }
// after navigate async Task NavigateFromAsync(Page page, INavigable dataContext, bool suspending) { DebugWrite($"Suspending: {suspending}"); dataContext.NavigationService = this; dataContext.Dispatcher = this.GetDispatcherWrapper(); dataContext.SessionState = BootStrapper.Current.SessionState; var index = WindowWrapper.Current().NavigationServices.IndexOf(this); var pageState = FrameFacadeInternal.PageStateSettingsService($"NavigationService{index}").Values; await dataContext.OnNavigatedFromAsync(pageState, suspending).ConfigureAwait(false); }
public async Task <bool> NavigateAsync(Type page, object parameter = null, IDictionary <string, object> state = null, NavigationTransitionInfo infoOverride = null) { DebugWrite($"Page: {page}, Parameter: {parameter}, NavigationTransitionInfo: {infoOverride}"); if (page == null) { throw new ArgumentNullException(nameof(page)); } // use CurrentPageType/Param instead of LastNavigationType/Parameter to avoid new navigation to the current // page in some race conditions. if ((page.FullName == CurrentPageType?.FullName) && (parameter == CurrentPageParam)) { return(false); } if ((page.FullName == CurrentPageType?.FullName) && (parameter?.Equals(CurrentPageParam) ?? false)) { return(false); } if (state != null) { var pageState = FrameFacadeInternal.PageStateSettingsService(page, 1, parameter).Values; foreach (var item in state) { pageState[item.Key] = item.Value; } } //var frameContent = FrameFacadeInternal.Frame.Content; //if (frameContent is Page current && frameContent is IDisposable disposable && page.FullName == CurrentPageType?.FullName) //{ // if (current.DataContext is INavigable dataContext) // { // await NavigatingFromAsync(current, page, parameter, dataContext, false, NavigationMode.Refresh); // await NavigateFromAsync(current, dataContext, false); // } // await NavigateToAsync(NavigationMode.Refresh, parameter, current); // FrameFacade.CurrentPageParam = parameter; // FrameFacade.Frame.BackStack.Add(new PageStackEntry(page, SerializationService.Serialize(CurrentPageParam), infoOverride)); // return true; //} parameter = SerializationService.Serialize(parameter); return(FrameFacadeInternal.Navigate(page, parameter, infoOverride)); }
public async Task <bool> GoForwardAsync() { if (!FrameFacade.CanGoForward) { return(false); } var next = FrameFacade.ForwardStack.FirstOrDefault(); var parameter = SerializationService.Deserialize(next.Parameter?.ToString()); return(await NavigationOrchestratorAsync(next.SourcePageType, parameter, NavigationMode.Forward, () => { FrameFacadeInternal.GoForward(); return true; })); }
public async Task <bool> GoBackAsync(NavigationTransitionInfo infoOverride = null) { if (!CanGoBack) { return(false); } var previous = FrameFacade.BackStack.LastOrDefault(); var parameter = SerializationService.Deserialize(previous.Parameter?.ToString()); return(await NavigationOrchestratorAsync(previous.SourcePageType, parameter, NavigationMode.Back, () => { FrameFacadeInternal.GoBack(infoOverride); return true; })); }
async Task NavigateToAsync(NavigationMode mode, object parameter, object frameContent = null) { DebugWrite($"Mode: {mode}, Parameter: {parameter} FrameContent: {frameContent}"); frameContent = frameContent ?? FrameFacadeInternal.Frame.Content; LastNavigationParameter = parameter; LastNavigationType = frameContent.GetType().FullName; var page = frameContent as Page; if (page != null) { if (mode == NavigationMode.New) { var pageState = FrameFacadeInternal.PageStateSettingsService(page.GetType()).Values; pageState?.Clear(); } if (!(page.DataContext is INavigable) | page.DataContext == null) { // to support dependency injection, but keeping it optional. var viewmodel = BootStrapper.Current.ResolveForPage(page.GetType(), this); if (viewmodel != null) { page.DataContext = viewmodel; } } // call viewmodel var dataContext = page.DataContext as INavigable; if (dataContext != null) { // prepare for state load dataContext.NavigationService = this; dataContext.Dispatcher = WindowWrapper.Current(this)?.Dispatcher; dataContext.SessionState = BootStrapper.Current.SessionState; var pageState = FrameFacadeInternal.PageStateSettingsService(page.GetType()).Values; await dataContext.OnNavigatedToAsync(parameter, mode, pageState); { // update bindings after NavTo initializes data XamlUtils.InitializeBindings(page); XamlUtils.UpdateBindings(page); } } } }
public async Task <bool> LoadAsync() { // load navigation state from settings DebugWrite($"Frame: {FrameFacade.FrameId}"); try { var frameState = Suspension.GetFrameState(); if (frameState == null || !frameState.Exists("CurrentPageType")) { return(false); } CurrentPageType = frameState.Read <Type>("CurrentPageType"); CurrentPageParam = frameState.Read <object>("CurrentPageParam"); FrameFacadeInternal.SetNavigationState(frameState.Read <string>("NavigateState")); while (FrameFacade.Content == null) { await Task.Delay(1); } var newPage = FrameFacade.Content as Page; var newViewModel = newPage?.DataContext; if (newPage?.GetType() != CurrentPageType) { // failed to load return(false); } // newTemplate10ViewModel.Properties if (newViewModel is INavigable) { Navigation.SetupViewModel(this, newViewModel as INavigable); } // newNavigatedAwareAsync.OnNavigatedTo await Navigation.NavedToAsync(newPage?.DataContext, NavigationMode.New, null, null, null, newPage, CurrentPageType, CurrentPageParam); RaiseAfterRestoreSavedNavigation(); return(true); } catch { return(false); } }
async Task NavigateToAsync(NavigationMode mode, object parameter, object frameContent = null) { DebugWrite($"Mode: {mode}, Parameter: {parameter} FrameContent: {frameContent}"); frameContent = frameContent ?? FrameFacadeInternal.Frame.Content; var page = frameContent as Page; if (page != null) { if (page is IDisposable cleanup) { cleanup.Dispose(); } //if (mode == NavigationMode.New) //{ // var pageState = FrameFacadeInternal.PageStateSettingsService(page.GetType()).Values; // pageState?.Clear(); //} var dataContext = ResolveForPage(page); if (dataContext != null) { // prepare for state load dataContext.NavigationService = this; dataContext.Dispatcher = this.GetDispatcherWrapper(); dataContext.SessionState = BootStrapper.Current.SessionState; var pageState = FrameFacadeInternal.PageStateSettingsService(page.GetType(), parameter: parameter).Values; await dataContext.OnNavigatedToAsync(parameter, mode, pageState); // update bindings after NavTo initializes data //XamlUtils.InitializeBindings(page); if (page.Content is UserControl pageWith) { XamlUtils.UpdateBindings(pageWith); } else { XamlUtils.UpdateBindings(page); } } } }
// after navigate async Task NavigateFromAsync(bool suspending) { DebugWrite($"Suspending: {suspending}"); var page = FrameFacadeInternal.Content as Page; if (page != null) { // call viewmodel var dataContext = ResolveForPage(page); if (dataContext != null) { dataContext.NavigationService = this; dataContext.Dispatcher = this.GetDispatcherWrapper(); dataContext.SessionState = BootStrapper.Current.SessionState; var pageState = FrameFacadeInternal.PageStateSettingsService(page.GetType()).Values; await dataContext.OnNavigatedFromAsync(pageState, suspending); } } }
public async Task <bool> NavigateAsync(Type page, object parameter = null, NavigationTransitionInfo infoOverride = null) { DebugWrite($"Page: {page}, Parameter: {parameter}, NavigationTransitionInfo: {infoOverride}"); // serialize parameter var serializedParameter = default(string); try { serializedParameter = Settings.SerializationStrategy.Serialize(parameter); } catch { throw new Exception("Parameter cannot be serialized. See https://github.com/Windows-XAML/Template10/wiki/Page-Parameters"); } return(await NavigationOrchestratorAsync(page, parameter, NavigationMode.New, () => { return FrameFacadeInternal.Navigate(page, serializedParameter, infoOverride); })); }
public bool Navigate(Type page, object parameter = null, NavigationTransitionInfo infoOverride = null) { DebugWrite($"Page: {page}, Parameter: {parameter}, NavigationTransitionInfo: {infoOverride}"); if (page == null) { throw new ArgumentNullException(nameof(page)); } if (page.FullName.Equals(LastNavigationType)) { if (parameter == LastNavigationParameter) { return(false); } if (parameter != null && parameter.Equals(LastNavigationParameter)) { return(false); } } parameter = SerializationService.Serialize(parameter); return(FrameFacadeInternal.Navigate(page, parameter, infoOverride)); }
public void GoForward() { FrameFacadeInternal.GoForward(); }
public void Refresh(object param) { FrameFacadeInternal.Refresh(param); }
public void Refresh() { FrameFacadeInternal.Refresh(); }
public void RaiseNavigating(NavigatingEventArgs e) { Navigating?.Invoke(this, e); // for backwards compat FrameFacadeInternal.RaiseNavigating(e); }
public void RaiseForwardRequested(HandledEventArgs args) { ForwardRequested?.Invoke(this, args); // for backwards compat FrameFacadeInternal.RaiseForwardRequested(args); }
private async Task <bool> NavigationOrchestratorAsync(Type page, object parameter, NavigationMode mode, Func <bool> navigate) { using (var locker = await LockAsync.Create(navigationLock)) { DebugWrite($"Page: {page}, Parameter: {parameter}, NavigationMode: {mode}"); if (page == null) { throw new ArgumentNullException(nameof(page)); } if (navigate == null) { throw new ArgumentNullException(nameof(navigate)); } // this cannot be used for duplicate navigation, except for refresh if (!Equals(mode, NavigationMode.Refresh)) { if (Equals(page, CurrentPageType)) { if (Equals(parameter, CurrentPageParam)) { return(false); } } } // fetch current (which will become old) var oldPage = FrameFacadeInternal.Content as Page; var oldParameter = CurrentPageParam; var oldViewModel = oldPage?.DataContext; var oldPageState = await FrameFacadeInternal.GetPageStateAsync(oldPage?.GetType()); var fromInfo = new NavigationInfo(oldPage?.GetType(), oldParameter, oldPageState); var toPageState = await FrameFacadeInternal.GetPageStateAsync(page?.GetType()); var toInfo = new NavigationInfo(page, parameter, toPageState); // call oldViewModel.OnNavigatingFromAsync() var viewmodelCancels = await Settings.ViewModelActionStrategy.NavigatingFromAsync((oldViewModel, false), fromInfo, toInfo, this); if (viewmodelCancels) { return(false); } // raise Navigating event RaiseNavigatingCancels(parameter, false, mode, toInfo, out var cancel); if (cancel) { return(false); } // invoke navigate (however custom) if (navigate.Invoke()) { CurrentPageParam = parameter; CurrentPageType = page; } else { return(false); } // fetch (current which is now new) var newPage = FrameFacadeInternal.Content as Page; var newViewModel = newPage?.DataContext; // note: this has no value now, but it will await Settings.ViewModelActionStrategy.NavigatingToAsync((newViewModel, mode, false), fromInfo, toInfo, this); // raise Navigated event RaiseNavigated(new NavigatedEventArgs() { Parameter = parameter, NavigationMode = mode, PageType = newPage?.GetType(), }); // call oldViewModel.OnNavigatedFrom() await Settings.ViewModelActionStrategy.NavigatedFromAsync((oldViewModel, false), fromInfo, toInfo, this); // call newViewModel.ResolveForPage() if (newViewModel == null) { newViewModel = ResolveViewModelForPage.Invoke(newPage); newPage.DataContext = newViewModel; } // call newTemplate10ViewModel.Properties if (newViewModel is ITemplate10ViewModel vm) { vm.NavigationService = this; } // call newViewModel.OnNavigatedToAsync() await Settings.ViewModelActionStrategy.NavigatedToAsync((newViewModel, mode, false), fromInfo, toInfo, this); // finally return(true); } }
private async Task <bool> NavigationOrchestratorAsync(Type page, object parameter, NavigationMode mode, Func <bool> navigate) { if (!await navigationOrchestratorAsyncSemaphore.WaitAsync(TimeSpan.FromSeconds(10))) { throw new TimeoutException("Semaphore wait ellapsed"); } // using (var locker = await LockAsync.Create(navigationLock)) try { DebugWrite($"Page: {page}, Parameter: {parameter}, NavigationMode: {mode}"); if (page == null) { throw new ArgumentNullException(nameof(page)); } if (navigate == null) { throw new ArgumentNullException(nameof(navigate)); } // this cannot be used for duplicate navigation, except for refresh if (!Equals(mode, NavigationMode.Refresh)) { if (Equals(page, CurrentPageType)) { if (Equals(parameter, CurrentPageParam)) { return(false); } } } // fetch current (which will become old) var oldPage = FrameFacadeInternal.Content as Page; var oldParameter = CurrentPageParam; var oldViewModel = oldPage?.DataContext; var oldPageState = await FrameFacadeInternal.GetPageStateAsync(oldPage?.GetType()); var from = new NavigationInfo(oldPage?.GetType(), oldParameter, oldPageState); var newPageState = await FrameFacadeInternal.GetPageStateAsync(page?.GetType()); var to = new NavigationInfo(page, parameter, newPageState); // call oldViewModel.OnNavigatingFromAsync() var cancelled = await Settings.ViewModelActionStrategy.NavigatingFromAsync((oldViewModel, mode, false), from, to, this); if (cancelled) { return(false); } // raise Navigating event RaiseNavigatingCancels(parameter, false, mode, to, out var cancel); if (cancel) { return(false); } // try to resolve the view-model before navigation var newViewModel = default(object); switch (mode) { case NavigationMode.New: case NavigationMode.Refresh: var strategy = Settings.ViewModelResolutionStrategy; newViewModel = await strategy.ResolveViewModel(page); if (newViewModel != null) { await Settings.ViewModelActionStrategy.NavigatingToAsync((newViewModel, mode, false), from, to, this); } break; } // navigate var newPage = default(Page); if (navigate.Invoke()) { if ((newPage = FrameFacadeInternal.Content as Page) == null) { return(false); } CurrentPageParam = parameter; CurrentPageType = page; } else { return(false); } // fetch current (which is now new) if (newViewModel != null) { newPage.DataContext = newViewModel; } else if ((newViewModel = newPage?.DataContext) != null) { await Settings.ViewModelActionStrategy.NavigatingToAsync((newViewModel, mode, false), from, to, this); } // raise Navigated event RaiseNavigated(new NavigatedEventArgs() { Parameter = parameter, NavigationMode = mode, PageType = newPage?.GetType(), }); // call oldViewModel.OnNavigatedFrom() await Settings.ViewModelActionStrategy.NavigatedFromAsync((oldViewModel, mode, false), from, to, this); // call newTemplate10ViewModel.Properties if (newViewModel is ITemplate10ViewModel vm) { vm.NavigationService = this; } // call newViewModel.OnNavigatedToAsync() await Settings.ViewModelActionStrategy.NavigatedToAsync((newViewModel, mode, false), from, to, this); // finally, all-good return(true); } catch (Exception ex) { throw; } finally { navigationOrchestratorAsyncSemaphore.Release(); } }