Getting Started

  • 4 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

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:

  1. 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}"/>
  2. 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.

  3. The Navigation region

    This is the navigation bar on the left.

    <dxn:NavBarGroup dxmvvm:UIRegion.Region="{x:Static common:Regions.Navigation}" ... >

    Module1 (NavigationItem) and Module2 (NavigationItem) are injected here.


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

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;

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.