Back to Devexpress

Define the Scope of Controllers and Actions

expressappframework-113103-ui-construction-controllers-and-actions-define-the-scope-of-controllers-and-actions.md

latest15.4 KB
Original Source

Define the Scope of Controllers and Actions

  • Jul 09, 2025
  • 7 minutes to read

This topic describes how to set conditions for activating Controllers and their Actions.

Specify the Scope of Controllers

Activate or Deactivate a Controller

If you implement a Controller that executes code in the Controller.Activated event handler or in the OnActivated and OnViewControlsCreated methods, you may have to define the conditions when this code is executed. For example, you may need to define that a Controller that customized a Grid Editor should be active for List Views only. To do this, change the Controller.Active property’s value directly or use one of Controller’s properties listed in this topic.

The Controller.Active property also affects the visibility of all Actions declared in this Controller (if a Controller is inactive, all of its Actions are also inactive). To hide a single Action, you can use the ActionBase class’s properties (see Change the Scope of Actions).

The following members help you specify the required conditions for Controller activation:

MemberDescription
Controller.ActiveProvides access to a collection of reason/value pairs used to activate or deactivate a Controller or determine its active state. The Controller is active when all items in this collection have the true value. You can add an item with a value that contains a conditional expression, so the Controller is deactivated when this expression returns false.
ViewController.TargetObjectTypeSpecifies the type of objects a View should display to activate a View Controller.
ViewController.TargetViewIdSpecifies the ID of the targeted View where a Controller should be active.
ViewController.TargetViewTypeSpecifies the type of the targeted View where a Controller should be active.
ViewController.TargetViewNestingSpecifies whether the targeted View where a Controller should be active is root, nested, or any.
WindowController.TargetWindowTypeSpecifies the kind of the Window where a Window Controller should activate.

Activate a Controller for Particular Views and Objects

You can inherit your Controller from ViewController<ViewType> or ObjectViewController<ViewType, ObjectType> and use the generic parameters to control views and types where a View Controller should become active. The example below demonstrates how to activate a Controller only for the Person Detail View.

csharp
public class ViewController1 : ObjectViewController<DetailView, Person> {
    protected override void OnActivated() {
        base.OnActivated();
        Person person = this.ViewCurrentObject;
        DetailView detailView = this.View;
        // ....
    }
}

Note

The ObjectViewController2.ViewCurrentObject](/eXpressAppFramework/DevExpress.ExpressApp.ObjectViewController-2.ViewCurrentObject) and [ObjectViewController2.View property types change depending on types passed as generic parameters. This may be useful when you want to avoid casting the View Controller’s View to ListView or DetailView. The Visual Studio Designer does not work for Controllers inherited from generic types.

Change the Scope of Actions

When you implement an Action, you may want to display it in a particular form. For example, your application should display a CancelAppointment Action only in the Views of an Appointment object. You may deactivate either the Action’s Controller or the Action itself.

Deactivate an Action’s Controller

In most cases, you can turn off (deactivate) a Controller that declares an Action to hide this Action. If you deactivate a Controller, all its Actions become invisible. Refer to the Specify the Scope of Controllers section to learn how to do this.

Deactivate an Action Itself

You can also define target Views and Windows for each Action individually. To do this, use the following properties:

MemberDescription
ActionBase.ActiveProvides access to a collection of key/value pairs that determine or change the Action’s active state. The resulting state determines the Action’s visibility.
ActionBase.EnabledProvides access to a collection of key/value pairs that determine an Action’s enabled/disabled state. A disabled Action is grayed out in the UI and a user cannot execute it.
ActionBase.TargetObjectsCriteriaSpecifies a criteria to enable an Action.
ActionBase.TargetObjectsCriteriaModeSpecifies whether all the currently selected objects meet the TargetObjectsCriteria criteria to enable an Action.
ActionBase.TargetObjectTypeSpecifies the type of the object(s) that the current View should display to activate an Action.
ActionBase.TargetViewIdSpecifies the ID of the targeted View where an Action should be active.
ActionBase.TargetViewNestingSpecifies whether the View where an Action should be active is root, nested, or any.
ActionBase.TargetViewTypeSpecifies the type of the targeted View where an Action should be active.
ActionBase.SelectionDependencyTypeSpecifies a context to enable an Action.

These properties control whether an Action is visible in certain Views and Windows. Refer to the ActionBase.Active topic to learn other ways to control visibility state (for example, hide an Action depending on a Business Object’s property value).

Activate a Controller or Action for Multiple Business Objects or Views

To make a single ViewController or Action available in Views of different Business Object types simultaneously, consider one of the following solutions:

Examples of Controller Scope Configuration

The following controller activates in nested Paycheck List Views:

csharp
using DevExpress.ExpressApp;

public class ViewController1 : ViewController {
    public ViewController1() {
        TargetObjectType = typeof(Paycheck);
        TargetViewType = ViewType.ListView;
        TargetViewNesting = Nesting.Nested;
    }
}

// Alternatively, you can write the controller above as:
public class ViewControllerAlternative : ObjectViewController<ListView, Paycheck> {
    public ViewControllerAlternative() {
        TargetViewNesting = Nesting.Nested;
    }
}

The next controller activates in Root Views for a set of Business Object types:

csharp
using DevExpress.ExpressApp;

public class ViewController1 : ViewController {
    public ViewController1() {
        TargetViewNesting = Nesting.Root;
    }
    protected override void OnViewChanged() {
        base.OnViewChanged();
        var viewObjectType = View?.ObjectTypeInfo?.Type;
        Active["Only for Employee and Paycheck objects"] =
            viewObjectType == typeof(Employee) || viewObjectType == typeof(Paycheck);
    }
}

You can add multiple activation criteria of arbitrary complexity:

csharp
using DevExpress.ExpressApp;

public class ViewController1 : ViewController {
    protected override void OnViewChanged() {
        base.OnViewChanged();
        if(View is null)
            return;
        Active["Only for nested views"] = !View.IsRoot;
        Active["Not for lookup list views"] =
            Frame.Context != TemplateContext.LookupControl && Frame.Context != TemplateContext.LookupWindow;
        Active["Not for inline edit or split views"] = !(View is ListView listView && (listView.AllowEdit || listView.Model.MasterDetailMode == MasterDetailMode.ListViewAndDetailView));
        Active["Only for specific types"] = CanActivateForType(View.ObjectTypeInfo?.Type);
        Active["Active in specific views only"] = CanActivateForViewId(View.Id);
    }
    private bool CanActivateForType(Type businessObjectType) { /*...*/ }
    private bool CanActivateForViewId(string viewId) { /*...*/ }
}

Examples of Action Scope Configuration

To define Action scope, you can use simple static rules or dynamic rules based on the properties of the selected objects. The following example demonstrates an Action that can deactivate users. This Action is enabled if the following conditions are met:

  • The current View is a root View for ApplicationUser.
  • At least one of the selected objects in a List View or the current object in a Detail View must be an active user (CriteriaOperator.FromLambda<ApplicationUser>(user => user.IsActive).ToString()).
  • The selection cannot include Administrator users.
csharp
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.Data.Filtering;

public class DeactivateUsersController : ViewController {
    SimpleAction deactivateUserAction;
    public DeactivateUsersController() {
        deactivateUserAction = new SimpleAction(this, "DeactivateUser", DevExpress.Persistent.Base.PredefinedCategory.Edit) {
            SelectionDependencyType = SelectionDependencyType.RequireMultipleObjects,
            TargetObjectsCriteria = CriteriaOperator.FromLambda<ApplicationUser>(user => user.IsActive).ToString(),
            TargetObjectsCriteriaMode = TargetObjectsCriteriaMode.TrueAtLeastForOne,
            TargetViewNesting = Nesting.Root,
            TargetObjectType = typeof(ApplicationUser),
            TargetViewType = ViewType.Any,
        };
        deactivateUserAction.Execute += DeactivateUserAction_Execute;
    }
    private void UpdateActionState() {
        // Update action visibility dynamically based on the currently selected objects
        var selectedUsers = deactivateUserAction.SelectionContext?.SelectedObjects?.OfType<ApplicationUser>()
            ?? Array.Empty<ApplicationUser>();
        bool adminUsersSelected = selectedUsers.Any(user => user.Roles.Any(role => role.IsAdministrative));
        deactivateUserAction.Enabled["Cannot deactivate Administrator users"] = !adminUsersSelected;
    }

    private void DeactivateUserAction_Execute(object sender, SimpleActionExecuteEventArgs e) {
        var selectedUsers = deactivateUserAction.SelectionContext?.SelectedObjects?.OfType<ApplicationUser>()
            ?? Array.Empty<ApplicationUser>();
        foreach (var user in selectedUsers) {
            user.IsActive = false;
        }
        ObjectSpace.CommitChanges();
    }
    protected override void OnActivated() {
        base.OnActivated();
        UpdateActionState();
        View.CurrentObjectChanged += View_CurrentObjectChanged;
        if (View is ListView listView) {
            listView.SelectionChanged += ListView_SelectionChanged;
        }
    }
    protected override void OnDeactivated() {
        base.OnDeactivated();
        if (View is not null) {
            View.CurrentObjectChanged -= View_CurrentObjectChanged;
            if (View is ListView listView) {
                listView.SelectionChanged -= ListView_SelectionChanged;
            }
        }
    }
    private void ListView_SelectionChanged(object sender, EventArgs e) => UpdateActionState();
    private void View_CurrentObjectChanged(object sender, EventArgs e) => UpdateActionState();
}

Tip

For more information on how to determine a user’s permissions, refer to the following topic: Determine if the Current User Has Specific Permissions.

See Also

How to: Detect a Lookup List View in Code

Hide or Disable an Action (Button, Menu Item) in Code

Ways to Hide or Disable an Action (Button, Menu Command)

Add a Parametrized Action

Add a Simple Action

Add an Action that Displays a Pop-Up Window

Add an Action with Option Selection

How to: Access the Grid Component in a List View

View Items and Property Editors