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