internal ShellState(ShellBase shell) { Shell = shell; Shell.Closing += ShellOnClosing; Shell.Closed += ShellOnClosed; }
/// <summary> /// Notifies <see cref="Data"/> and <see cref="View"/> about navigation completion. /// </summary> /// <param name="parent"></param> internal void NavigationCompleted(ShellBase parent) { (Data as INavigatable)?.Navigated(); if (View != null) { Shell.Dispatcher.Invoke(() => View.Navigated(Shell, parent)); } }
private static Task NavigateInner <T>(T target) where T : INavigationTarget { return(InvokeOnDispatcherAsync(() => { if (_shellResolver == null) { throw new InvalidOperationException("Shell resolver must be set before invoking Navigate method."); } var type = target.GetType(); if (!_navitaionTargetToConfigs.ContainsKey(type)) { NavigationFailed?.Invoke(NavigationFailReason.NotConfigured, target); return; } //1. Find config var configs = _navitaionTargetToConfigs[type]; // If registered more than 1 config, find config which matches target. If no found or only 1 config - use first navigation config. var config = (configs.Count > 1 ? configs.FirstOrDefault(x => x.MatchesTarget(target)) : null) ?? configs.First(); var navMode = config.Mode; if (navMode == NavigationMode.DependsOnTarget) { navMode = config.GetNavigationMode(target); } // Navigation mode after getting from config cannot be NavigationMode.DependsOnTarget if (navMode == NavigationMode.DependsOnTarget) { throw new InvalidOperationException("NavigationConfig.GetNavigationMode returned invalid value: NavigationMode.DependsOnTarget"); } ShellState shellState = null; bool existingShell = false; if (!config.AllowMultiple) { var conflict = _states.FirstOrDefault(x => x.Config == config); if (conflict != null) { //Check if config can handle navigation when already navigated. try { if (config.TryHandleNavigation(target, conflict.Data)) { return; } } catch (NotImplementedException) { } NavigationFailed?.Invoke(NavigationFailReason.NotAllowedToHaveMultiple, target); return; // No futher navigation required. } } //Only for default navigation mode can be searched existing shells. if (navMode == NavigationMode.Default) { //Try find available shell foreach (var state in _states) { // Check if config allows reuse shell if (!state.Config.CanLeave(target)) { continue; } //Only Default and NewWindow can be reused. if (!(state.Mode == NavigationMode.Default || state.Mode == NavigationMode.NewWindow)) { continue; } // On this line shell can be reused. shellState = state; existingShell = true; break; } } // Create shell data from config object shellData; ShellBase parent = null; if (!existingShell) { // Check if need to set parent. if ((navMode == NavigationMode.ChildWindow || navMode == NavigationMode.DialogWindow)) { // Set parent window if shellState.Mode is Dialog or Child if (_states.Any()) //TODO: Improve logic for selecting parent window. { parent = _states[0].Shell; } } // Create new shell if not found available. var shell = _shellResolver.CreateShell(parent); shellState = new ShellState(shell); shellState.ShellClosed += ShellStateOnShellClosed; _states.Add(shellState); shellData = config.GenerateDataForTarget(target, shellState.Shell.Dispatcher); if (shellData == null) { throw new InvalidOperationException("Config returned null from generating object for target."); } // Set data in ShellBase shellState.Load(navMode, config, target, shellData); // Show shell. if (shellState.Mode == NavigationMode.DialogWindow) { shellState.Shell.Dispatcher.InvokeAsync(() => shellState.Shell.ShowDialog()); } else { shellState.Shell.Dispatcher.Invoke(() => { shellState.Shell.Show(); shellState.Shell.Activate(); }); } } else { shellData = config.GenerateDataForTarget(target, shellState.Shell.Dispatcher); if (shellData == null) { throw new InvalidOperationException("Config returned null from generating object for target."); } // Unload current navigatable data. shellState.Unload(); // Set data in ShellBase shellState.Load(navMode, config, target, shellData); } //Navigation to target comleted. shellState.NavigationCompleted(parent); })); }