Example #1
0
        internal ShellState(ShellBase shell)
        {
            Shell = shell;

            Shell.Closing += ShellOnClosing;
            Shell.Closed  += ShellOnClosed;
        }
Example #2
0
        /// <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);
            }));
        }