Customize the Application UI and Behavior

As you learned in the previous lesson, persistent classes that form the business model define the database structure and UI. Changes in your business model will result in UI changes. For instance, if you add a new property to a business class, a new editor will be added to the list and detail forms. Thus, in XAF, the business model rules the UI.

Although the default auto-generated user interface is usable "as is", you may need to customize it according to your specific business requirements. The user interface can be customized in the following ways.

Customize the Application UI Metadata

Declarative Approach

You may have already noticed that persistent classes are decorated with the NavigationItemAttribute, which defines a navigation control group for the target class. This approach is similar to the Data Annotations approach widely used when building ASP.NET MVC applications with Entity Framework, because it allows you to quickly set up how your UI will look and behave, directly in the data model code.

[NavigationItem("Marketing")]
public class Customer {
    // ...
}
Note

More examples of customization via attributes can be found in the demo projects. The SimpleProjectManager demo sources are located in the %PUBLIC%\Documents\DevExpress Demos 18.1\Components\eXpressApp Framework\SimpleProjectManager\CS\SimpleProjectManager.Module\BusinessObjects\ path.

Although there are numerous built-in attributes in XAF and XPO that allow you to customize almost every aspect of your business model's look and behavior (the validation, visibility, availability, color and formatting of fields, and much more), it is generally best practice to avoid doing so in large projects, because normally the business model should not be aware of any UI settings. Attributes allows you to edit the Application Model, create controls, etc., right into the Business Model. It is easier, but using these attributes adds a dependency on the XAF assemblies to your data access layer (DAL), which you may wish to avoid (e.g., if your data model is also used in a non-XAF application). However, this is just a recommendation, and you can use attributes if you wish, especially if you build your business model only for XAF projects. This declarative approach is fast and convenient for many customization scenarios, especially small projects.

Visual Approach

If you do not like to add attributes to your business model code, then you can customize your application user interface structure and behavior by editing application metadata (also known as the Application Model) in XAFML files.

  1. In the Solution Explorer, right click the SimpleProjectManager.Module project and select Open Model Editor in the context menu (alternatively, you can double-click the file with the XAFML extension).
  2. In the Model Editor, navigate to the BOModel | Customer node in the tree to the left (you can also click the 'binoculars' button ME_Search in the toolbar to search for this node). Then, set the ImageName property to BO_Customer.

    SPM_ME

  3. Finally, click Save in the Visual Studio toolbar to save your customizations.

The image below illustrates the result. The BO_Customer icon is displayed in the navigation control and the form header.

SPM_Customer

Note

Application Model customizations made in the Model Editor are saved as plain XML in XAFML files. You can open this XAFML file in a text or XML editor to view or edit the markup. You may have already seen a similar technique when building Android, WPF or web applications in which you define the layout structure and specify other UI options via XML, XAML, ASPX or CSS files. To see more customization examples, refer to the XAFML files located in the %PUBLIC%\Documents\DevExpress Demos 18.1\Components\eXpressApp Framework\SimpleProjectManager folder.

In addition to defining the UI structure and behavior, the Application Model is used to store user settings and preferences (e.g., the selected skin, column sorting and grouping options in list forms, or runtime layout customizations of detail forms).

Note that the set of available options in the Model Editor may vary depending on the selected project. For instance, if you invoke the Model Editor for a WinForms executable application project or use the Tools | Edit Model command at runtime, then you will see WinForms-specific options such as UIType, FormStyle and Skin.

Note

End-users can customize different aspects of an XAF application at runtime. The Runtime Customization section in the View Items Layout Customization article describes this.

Define Custom Logic and UI Elements

UI elements and visual controls used in XAF have many options that can be changed using built-in attributes, or via the Model Editor. However, there are certain options that can be changed in code only. You may also want to replace the default application UI parts with custom or third-party controls. Finally, you may need to implement a custom user interaction or call any other arbitrary code.

In this tutorial, you will consider the most popular scenario - providing a custom command that enables an end-user to execute custom business logic from the UI.

In XAF, the common way to accomplish this task is by using Controllers and Actions. Controllers are components that are used to change the application flow, customize UI elements and implement custom end-user interaction. Controllers can host Actions, which are interactive UI elements (buttons, menu items, etc.) that execute predefined code. For instance, navigation control items, toolbar buttons, menu items and other interactive elements are provided by Actions and Controllers.

To implement an Action that will allow users to mark the selected Project Tasks as completed, and also set the EndDate to the current date and time, do the following.

  1. In the Solution Explorer, right-click the SimpleProjectManager.Module\Controllers folder and select Add | Class… in the context menu. Set the class name to ProjectTaskController.
  2. Replace the created class code with the following.

    using System;
    using DevExpress.Data.Filtering;
    using DevExpress.ExpressApp;
    using DevExpress.ExpressApp.Actions;
    using SimpleProjectManager.Module.BusinessObjects.Planning;
    
    namespace SimpleProjectManager.Module.Controllers {
        public class ProjectTaskController : ViewController {
            public ProjectTaskController() {
                TargetObjectType = typeof(ProjectTask);
                TargetViewType = ViewType.Any;
                SimpleAction markCompletedAction = new SimpleAction(
                    this, "MarkCompleted",
                    DevExpress.Persistent.Base.PredefinedCategory.RecordEdit){
                        TargetObjectsCriteria = (
                        CriteriaOperator.Parse("Status != ?",ProjectTaskStatus.Completed)
                                                                         ).ToString(),
                        ConfirmationMessage =
                                "Are you sure you want to mark the selected task(s) as 'Completed'?",
                        ImageName = "State_Task_Completed"
                    };
                markCompletedAction.Execute += (s, e) => {
                    foreach(ProjectTask task in e.SelectedObjects) {
                        task.EndDate = DateTime.Now;
                        task.Status = ProjectTaskStatus.Completed;
                        View.ObjectSpace.SetModified(task); 
                    }
                    View.ObjectSpace.CommitChanges();
                    View.ObjectSpace.Refresh();
                };
            }
        }
    }
    

In the code above, the Controller targets the ProjectTask business class (the target type is specified via the ViewController.TargetObjectType property). This Controller will be active for both list and detail data screens if the ViewController.TargetViewType property is set to Any. A SimpleAction is added by this Controller. This Action will be available in the UI only if the selected data object satisfies a criterion passed to the ActionBase.TargetObjectsCriteria (Status is not Completed). When the Action is executed, selected objects are iterated and object properties are modified. Finally, changes are committed to the database and the current data screen is refreshed.

Note that unlike the DBContext used in Entity Framework or the Session used in XPO, all data manipulations are powered by an Object Space entity, which is an abstraction on the database context, allowing you to query or modify data in the transaction. Object Space is an ORM-independent implementation of the well-known Repository and Unit Of Work design patterns. In addition to the IObjectSpace.CommitChanges method used above, you may find the IObjectSpace.GetObject, IObjectSpace.GetObjectByKey, IObjectSpace.FindObject, IObjectSpace.CreateObject, IObjectSpace.Delete and other methods typically used for Repository and Unit of Work patterns useful (see Create, Read, Update and Delete Data).

The image below illustrates the MarkCompleted Action in a WinForms application and an ASP.NET application.

SPM_Action

Alternatively, you can ...

  • use the built-in View Controller from Template Gallery to create a Controller. In this instance, you can pick an Action from the Toolbox and drag it to the designer's surface instead of writing code.
  • implement the generic ObjectViewController<ViewType, ObjectType> Controller instead of the ViewController and specify the View's and object's type, for which this Controller should be activated, in the ViewType and ObjectType generic parameters.
  • use ActionAttribute to create an action directly from a business class method.
Note

If you experience any problems while following these steps, or you just want to let us know what you think, contact our support team (full and free technical support during the evaluation period is included).

Next topic: Reuse Implemented Functionality

See Also