/// <summary>
        /// Creates a new window and its view model.
        /// </summary>
        /// <typeparam name="TWindow">The type of window that is to be created.</typeparam>
        /// <param name="parameters">The parameters that are passed to the window's view model.</param>
        /// <exception cref="InvalidOperationException">If the the window or it's view model can not be instantiated, an <see cref="InvalidOperationException"/> is thrown.</exception>
        /// <returns>Returns the navigation result, the new window, and the new view model of the window.</returns>
        private async Task <WindowCreationResult> CreateWindowAsync <TWindow>(object parameters) where TWindow : Window
        {
            // Creates a new navigation service for the window
            NavigationService navigationService = new NavigationService(this.iocContainer);

            // Determines the type of the view model, which can be done via attribute or convention
            Type windowViewModelType = null;
            ViewModelAttribute viewModelAttribute = typeof(TWindow).GetCustomAttributes <ViewModelAttribute>().FirstOrDefault();

            if (viewModelAttribute != null)
            {
                windowViewModelType = viewModelAttribute.ViewModelType;
            }
            else
            {
                this.assemblyTypes = this.assemblyTypes ?? typeof(TWindow).Assembly.GetTypes();
                string viewModelName = this.ViewModelNamingConvention(typeof(TWindow).Name);
                windowViewModelType = this.assemblyTypes.FirstOrDefault(type => type.Name == viewModelName);
            }

            // Instantiates the new view model
            if (windowViewModelType != null)
            {
                try
                {
                    // Lets the IOC container instantiate the view model, so that all dependencies can be injected (including the navigation service itself, which is set as an explitic constructor argument)
                    navigationService.WindowViewModel = this.iocContainer.GetInstance(windowViewModelType, navigationService).Inject(parameters) as IViewModel;
                }
                catch (Exception e)
                {
                    throw new InvalidOperationException(Resources.Localization.WindowNavigationService.WindowViewModelCouldNotBeInstantiatedExceptionMessage, e);
                }

                // Checks whether the view model implements the IViewModel interface
                if (navigationService.WindowViewModel == null)
                {
                    throw new InvalidOperationException(Resources.Localization.WindowNavigationService.WrongViewModelTypeExceptionMessage);
                }
            }

            // Calls the activate event and then the navigate event of the window view model
            if (navigationService.WindowViewModel != null)
            {
                // Raises the activate event of the new window view model
                await navigationService.WindowViewModel.OnActivateAsync();

                // Raises the on navigate to event of the new window view model, and checks if it allows to be navigated to
                NavigationEventArgs eventArguments = new NavigationEventArgs(NavigationReason.WindowOpened);
                await navigationService.WindowViewModel.OnNavigateToAsync(eventArguments);

                if (eventArguments.Cancel)
                {
                    // Since the window view model does not allow to be navigated to, the new window view model is deactivated, disposed of, and the navigation is aborted
                    await navigationService.WindowViewModel.OnDeactivateAsync();

                    navigationService.WindowViewModel.Dispose();
                    return(new WindowCreationResult {
                        NavigationResult = NavigationResult.Canceled
                    });
                }
            }

            // Instantiates the new window
            try
            {
                // Lets the IOC container instantiate the window, so that all dependencies can be injected
                navigationService.Window = this.iocContainer.GetInstance <TWindow>();
            }
            catch (Exception e)
            {
                // Since an error occurred, the new window view model is deactivated and disposed of
                if (navigationService.WindowViewModel != null)
                {
                    await navigationService.WindowViewModel.OnDeactivateAsync();

                    navigationService.WindowViewModel.Dispose();
                }

                // Rethrows the exception
                throw new InvalidOperationException(Resources.Localization.WindowNavigationService.WindowCouldNotBeInstantiatedExceptionMessage, e);
            }

            // Since window is a framework element it must be properly initialized
            if (!navigationService.Window.IsInitialized)
            {
                MethodInfo initializeComponentMethod = navigationService.Window.GetType().GetMethod("InitializeComponent", BindingFlags.Public | BindingFlags.Instance);
                if (initializeComponentMethod != null)
                {
                    initializeComponentMethod.Invoke(navigationService.Window, new object[0]);
                }
            }

            // Sets the view model as data context of the window
            navigationService.Window.DataContext = navigationService.WindowViewModel;

            // Subscribes to the closing event of the window, so that the window can be properly closed (with all the lifecycle callbacks)
            navigationService.Window.Closing += (sender, e) =>
            {
                // Calls the close window method in order to execute the lifecycle methods (the window is not closed within this call)
                if (navigationService.CloseWindowAsync(true, NavigationReason.WindowClosing, false).Result == NavigationResult.Canceled)
                {
                    e.Cancel = true;
                    return;
                }

                // Removes the navigation manager from the list of window navigation managers
                this.navigationServices.Remove(navigationService);
                if (this.WindowClosed != null)
                {
                    this.WindowClosed(this, new WindowEventArgs(navigationService));
                }
            };

            // Returns the result
            return(new WindowCreationResult
            {
                Window = navigationService.Window,
                ViewModel = navigationService.WindowViewModel,
                NavigationResult = NavigationResult.Navigated,
                NavigationService = navigationService
            });
        }
예제 #2
0
        /// <summary>
        /// Navigates the user to the specified view.
        /// </summary>
        /// <param name="parameters">The parameters that are to be passed to the view model.</param>
        /// <typeparam name="TView">The type of the view to which the user is to be navigated.</typeparam>
        /// <exception cref="InvalidOperationException">If the view or the view model can not be instantiated, or the window does not support navigation, an <see cref="InvalidOperationException"/> is thrown.</exception>
        /// <returns>Returns <see cref="NavigationResult.Navigated"/> if the user was successfully navigated and <see cref="NavigationResult.Canceled"/> otherwise.</returns>
        public async Task <NavigationResult> NavigateAsync <TView>(object parameters) where TView : Page
        {
            // Checks if the current window supports navigation
            if (!this.SupportsNavigation)
            {
                throw new InvalidOperationException(Resources.Localization.NavigationService.NavigationNotSupportedExceptionMessage);
            }

            // Raises the on navigated from event of the current view model, if the view model does not allow to be navigated away from, then the navigation is aborted
            NavigationEventArgs eventArguments = null;

            if (this.CurrentViewModel != null)
            {
                eventArguments = new NavigationEventArgs(NavigationReason.Navigation);
                await this.CurrentViewModel.OnNavigateFromAsync(eventArguments);

                if (eventArguments.Cancel)
                {
                    return(NavigationResult.Canceled);
                }
            }

            // Determines the type of the view model, which can be done via attribute or convention
            Type viewModelType = null;
            ViewModelAttribute viewModelAttribute = typeof(TView).GetCustomAttributes <ViewModelAttribute>().FirstOrDefault();

            if (viewModelAttribute != null)
            {
                viewModelType = viewModelAttribute.ViewModelType;
            }
            else
            {
                this.assemblyTypes = this.assemblyTypes ?? typeof(TView).Assembly.GetTypes();
                string viewModelName = this.ViewModelNamingConvention(typeof(TView).Name);
                viewModelType = this.assemblyTypes.FirstOrDefault(type => type.Name == viewModelName);
            }

            // Instantiates the new view model
            IViewModel viewModel = null;

            if (viewModelType != null)
            {
                try
                {
                    // Lets the IOC container instantiate the view model, so that all dependencies can be injected (including the navigation service itself, which is set as an explitic constructor argument)
                    viewModel = this.iocContainer.GetInstance(viewModelType, this).Inject(parameters) as IViewModel;
                }
                catch (Exception e)
                {
                    throw new InvalidOperationException(Resources.Localization.NavigationService.ViewModelCouldNotBeInstantiatedExceptionMessage, e);
                }

                // Checks whether the view model implements the IViewModel interface
                if (viewModel == null)
                {
                    throw new InvalidOperationException(Resources.Localization.NavigationService.WrongViewModelTypeExceptionMessage);
                }
            }

            // Calls the activate event and then the navigate event of the view model
            if (viewModel != null)
            {
                // Raises the activate event of the new view model
                await viewModel.OnActivateAsync();

                // Raises the on navigate to event of the new view model, and checks if it allows to be navigated to
                eventArguments = new NavigationEventArgs(NavigationReason.Navigation);
                await viewModel.OnNavigateToAsync(eventArguments);

                if (eventArguments.Cancel)
                {
                    // Since the view model does not allow to be navigated to, the new view model is deactivated, disposed of, and the navigation is aborted
                    await viewModel.OnDeactivateAsync();

                    viewModel.Dispose();
                    return(NavigationResult.Canceled);
                }
            }

            // Instantiates the new view
            Page view = null;

            try
            {
                // Lets the IOC container instantiate the view, so that all dependencies can be injected
                view = this.iocContainer.GetInstance <TView>();
            }
            catch (Exception e)
            {
                // Since an error occurred, the new window view model is deactivated and disposed of
                if (viewModel != null)
                {
                    await viewModel.OnDeactivateAsync();

                    viewModel.Dispose();
                }

                // Rethrows the exception
                throw new InvalidOperationException(Resources.Localization.NavigationService.ViewCouldNotBeInstantiatedExceptionMessage, e);
            }

            // Since view is a framework element it must be properly initialized
            if (!view.IsInitialized)
            {
                MethodInfo initializeComponentMethod = view.GetType().GetMethod("InitializeComponent", BindingFlags.Public | BindingFlags.Instance);
                if (initializeComponentMethod != null)
                {
                    initializeComponentMethod.Invoke(view, new object[0]);
                }
            }

            // Sets the view model as data context of the view
            view.DataContext = viewModel;

            // Adds the old view to the navigation stack
            if (this.CurrentViewModel != null)
            {
                this.CurrentViewModel.IsInView = false;
            }
            if (this.CurrentView != null)
            {
                this.navigationStack.Push(new KeyValuePair <Page, IViewModel>(this.CurrentView, this.CurrentViewModel));
            }

            // Sets the current view and view model
            this.CurrentView      = view;
            this.CurrentViewModel = viewModel;

            // Navigates the user to the new view
            this.navigationFrame.Navigate(this.CurrentView);
            if (this.CurrentViewModel != null)
            {
                this.CurrentViewModel.IsInView = true;
            }

            // Since the navigation was successful, Navigated is returned as a result of the navigation
            return(NavigationResult.Navigated);
        }