Getting Started
- 3 minutes to read
This tutorial explains the structure of a simple application created using the DevExpress Template Gallery.
The application consists of four projects:
- Common - contains common interfaces and the names of regions and modules.
- Main - contains the MainWindow and the Bootstrapper class, that composes the application on startup.
- Modules - contains the application’s modules.
- Tests - contains tests.
The application consists of the following modules:
Module Key | View | ViewModel |
---|---|---|
Main | MainWindow (UserControl) | MainViewModel |
Module1 | ModuleView (UserControl) | ModuleViewModel |
Module2 | ModuleView (UserControl) | ModuleViewModel |
Module1 | (Created by a target control) | NavigationItem |
Module2 | (Created by a target control) | NavigationItem |
Tip
Several modules may have the same key as long as they are injected in different regions. This possibility is used to simplify navigation.
The application contains the following regions:
The MainWindow region
This is the content of the MainWindow. The only module injected here is the MainWindow module.
<ContentControl dxmvvm:UIRegion.Region="{x:Static common:Regions.MainWindow}"/>
The Documents region
The region is defined in the MainView UserControl.
<dxdo:DocumentGroup dxmvvm:UIRegion.Region="{x:Static common:Regions.Documents}" ... />
Module1 (ModuleViewModel) and Module2 (ModuleViewModel) are injected in this DocumentGroup.
The Navigation region
This is the navigation bar on the left.
<dxn:NavBarGroup dxmvvm:UIRegion.Region="{x:Static common:Regions.Navigation}" ... > ... </dxn:NavBarGroup>
Module1 (NavigationItem) and Module2 (NavigationItem) are injected here.
Injecting
All modules are registered at the application startup.
Manager.Register(Regions.MainWindow, new Module(AppModules.Main, MainViewModel.Create, typeof(MainView)));
Manager.Register(Regions.Navigation, new Module(AppModules.Module1, () => new NavigationItem("Module1")));
Manager.Register(Regions.Navigation, new Module(AppModules.Module2, () => new NavigationItem("Module2")));
Manager.Register(Regions.Documents, new Module(AppModules.Module1, () => ModuleViewModel.Create("Module1", "Module1 Content"), typeof(ModuleView)));
Manager.Register(Regions.Documents, new Module(AppModules.Module2, () => ModuleViewModel.Create("Module2", "Module2 Content"), typeof(ModuleView)));
Registration allows accessing a registered module by its name. A module needs to be injected to show it in the application. The three initial modules are always injected.
Manager.Inject(Regions.MainWindow, AppModules.Main);
Manager.Inject(Regions.Navigation, AppModules.Module1);
Manager.Inject(Regions.Navigation, AppModules.Module2);
Note
This code can be executed at any time, even when the MainWindow is not visible yet, and there is no visual tree. The MIF queues the injected modules and shows them as soon as the relevant regions are loaded.
There are no injected modules in the Documents region initially.
The DocumentGroup is injected with modules when the user selected one of the modules in the NavBarGroup on the left side.
The Navigation event is used to achieve this kind of navigation.
Manager.GetEvents(Regions.Navigation).Navigation += OnNavigationItemsNavigation;
Manager.GetEvents(Regions.Documents).Navigation += OnDocumentsNavigation;
Note
All the events provided by ModuleManager are weak events [link], and as such, there is no need to unsubscribe from them to prevent memory leaks.
Below is the first event handler:
void OnNavigationItemsNavigation(object sender, NavigationEventArgs e) {
if(e.NewViewModelKey == null) return;
Manager.InjectOrNavigate(Regions.Documents, e.NewViewModelKey);
}
First, it checks if the selected module exists. Then it uses the **InjectOrNavigate** method to navigate a particular module. The first argument specifies a region in which the navigation is happening. The second argument selects a module.
Note, that the modules registered in the Navigation region have the same keys as the modules registered in the Documents region. This allows to map NavigationItem modules to the corresponding ModuleViewModel modules easily.
InjectOrNavigate is a helper method that combines the functionality of the Inject and Navigate methods. If no module with a particular key has been injected before the invocation of the InjectOrNavigate method, the method first injects the provided module and then navigates it.
The second event handler provides the synchronization functionality: when the user selects a particular tab, the corresponding NavigationItem on the left is selected.
void OnDocumentsNavigation(object sender, NavigationEventArgs e) {
Manager.Navigate(Regions.Navigation, e.NewViewModelKey);
}
The code example above contains no check for e.NewViewModelKey because the application always displays a selected tab when running. All NavigationItem modules are injected at startup, and there is no need to inject them again inside the handler.