The process of building eXpressApp Framework applications can be divided into several steps. The first step – business model implementation, the second – default UI customization, and the third is custom feature development (to change your application's flow and implement custom end-user interaction). For the last step, you will need to use Controllers. eXpressApp Framework provides a number of built-in Controllers that are used when generating the default UI. For instance, validation, navigation and search features are already included in the default UI. To implement a custom feature, you will need to create a Controller - a class derived from Controller, ViewController or WindowController class. This topic explains how to do this properly.
Controllers serve two main purposes:
Perform specific actions when a Window (Frame) is created or destroyed.
When a Window (Frame) is created, all the Controllers that are intended for it are activated, which means that their special events are raised (see Controller.Activated). You can handle these events to implement features related to the current Window (Frame) or its View. When a Window (Frame) is disposed of, its Controllers are deactivated, which means that their special event is raised (see Controller.Deactivated). This allows you to perform specific actions when closing a Window or disposing of a Frame.
Extend the user interface.
In most cases, features demand end-user interaction. For this purpose, Controllers can serve as containers for Actions. Actions are objects that represent abstract UI elements, and can be displayed in a UI using actual controls: a button, combo box, submenu, etc. To respond to an end-user's manipulations with an action control, handle the corresponding Action's events.
As with most of the XAF entities, information on Controllers found in the application's modules is loaded into the Application Model. You can access Controller settings in the IModelControllers node. Please refer to this node's description for information on possible customizations.
WindowController, ViewController and Controller Classes
Physically, Controllers are Controller class descendants. Note that you will not need to create direct descendants of this class to provide Controllers for your application. Instead, you will deal with two predefined descendants - ViewController (including its generic versions: ViewController<ViewType> and ObjectViewController<ViewType, ObjectType>) and WindowController. These classes provide the Controller.Activated and Controller.Deactivated events that allow you to perform specific actions when the corresponding Window (Frame) is being created or destroyed. To access the Window (Frame) or its View in these event handlers, the ViewController class offers the Controller.Frame and ViewController.View properties. The WindowController class exposes the corresponding Window using the WindowController.Window property.
Though these two classes have a great deal in common, you should use them in different scenarios. More about this now.
View Controllers are intended for implementing features (filter or search features, etc.) for Views. Basically, you need to use a View Controller every time you need to implement a data-aware feature.
Actions contained in a View Controller accompany Views for which the Controller is activated. For instance, if a Controller is activated for a nested List View (List View of a collection property), its Actions will be attached to this View, not to the entire Window.
View Controllers are activated for both Windows and Frames when a View is set to a Window/Frame. However, you can specify the type or ID of the View that you need to be contained in the Window or Frame. For this purpose, use the following ViewController's properties:
Specifies the View type: List View, Detail View or any View. By default, the value of this property is Any.
Specifies whether the current Controller is allowed to be activated for the root View, nested View or any View. By default, the value of this property is Any.
Specifies the type of a persistent object displayed by the View.
Specifies the View ID. This ID is specified in the Application Model.
Window Controllers are activated when a Window or a Frame is created, and intended for implementing features for Windows, i.e., features that are not related to specific Views. So, these features are not related to data in most cases. An example can be a Controller that changes the appearance of a navigation control in the main Window (refer to the How to: Access the Navigation Control topic to see the example). The Actions contained in Window Controllers are always displayed in a Window, no matter what View is currently displayed.
Window Controllers are activated for Windows only. You can additionally specify the Window type for which the Controller will be activated. For this purpose, use the Controller's WindowController.TargetWindowType property. Its value can be set to Any, Main or Child. Note that XAF applications have a single Main window, which is displayed first. The rest are Child windows.
Implement Custom Controllers
If a Controller, together with its Actions, is UI-independent, it should be implemented in a Module Project. At the same time, there may be a UI-specific task. In this instance, a Controller should be developed in a UI-specific Module. Note that Controllers should always be declared within XAF modules. If you add a Controller to an application project, it will not be discovered and plugged into your application automatically.
You can use the ready-to-use Controller templates to create a custom Controller. In Solution Explorer, select a Module Project to which you want to add a Controller. Right-click the Controllers folder located inside the project to invoke the context menu and select Add DevExpress Item | New Item... to invoke DevExpress Template Galery. The following dialog will be displayed.
Select Window Controller or View Controller, specify its name, and press the Add Item button to add a new Controller to your project. Use the Controller's Designer to both add Actions from the Toolbox and to customize your Controller's properties using the Properties window. To invoke the Designer, you can right-click the controller file in Solution Explorer and select the View Designer context menu item. Note that Visual Studio designer cannot be used with generic Controllers. Refer to the ViewController<ViewType> or ObjectViewController<ViewType, ObjectType> description for information on how to make the designer available. Do not forget to rebuild your solution after making changes in the Designer. Otherwise, you will not see them in the Model Editor.
The Controllers folder is added to each module project for your convenience, to keep all your Controllers together. Meanwhile, using this folder is not a requirement. The structure of your project is fully up to you.
A Controller created using a template is declared as a partial class and contains a code-behind file that will hold your customizations made using the Designer. An alternative way to create a custom Controller is to declare a class derived from a Controller, ViewController (ViewController<ViewType>, ObjectViewController<ViewType, ObjectType>) or WindowController. Note that in this case, by default, customizations made using the Designer will be added to the class body, which can make reading the Controller code a bit more difficult. In this instance, it may be more appropriate to not use the Designer at all, and make all required customizations in the Controller code manually. One advantage of this approach is that hand-written code can be more readable. Another advantage is that you can easily copy such a Controller as its code is located in a single file.