Skip to main content
.NET 6.0+

How to: Create an Action Using the Action Attribute

  • 6 minutes to read

This example demonstrates how to create an Action within a persistent class declaration (i.e., how to convert a persistent class method into a SimpleAction or PopupWindowShowAction).

Important Notes on Using the Action Attribute

Actions created with the ActionAttribute are not designed to operate in List Views without any selected objects. The attribute’s ActionAttribute.SelectionDependencyType parameter can be set either to RequireSingleObject or RequireMultipleObjects (see MethodActionSelectionDependencyType). To create an Action that does not require the selected object, add a Controller and implement an Action in it (see Add a Simple Action and Add an Action that Displays a Pop-Up Window).

ActionAttribute is primarily used in simple scenarios when you execute logic based on data available within the business class context (for instance, modify class properties). ActionAttribute is not suitable for any UI-related logic and complex user interactions. It is also not possible to access XafApplication, Views, and other XAF UI-related entities within the business class code, because it violates the separation of concerns principle and is against the MVC architecture (your data model should not be tied to the UI). To access XafApplication, Views, and other UI-related entities, implement Controllers with Actions.

Create A Simple Action

Add a Task business class to your project.

[DefaultClassOptions,ImageName("BO_Task"),DefaultProperty(nameof(Subject))]
public class Task : BaseObject {
    public virtual string Subject { get; set; }
    public virtual bool IsCompleted { get; set; }
}

// Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.

Implement an Action that changes the IsCompleted property to true. Add the following Complete method to the Task class and decorate it with the ActionAttribute.

[Action(Caption="Complete", TargetObjectsCriteria = "Not [IsCompleted]")]
public void Complete() {
    IsCompleted = true;
}

Such methods are automatically collected from business classes by the ObjectMethodActionsViewController. This controller creates the Task.Complete Action, that invokes the Complete method for each selected Task. Note the use of the ActionAttribute.TargetObjectsCriteria parameter. The Action is disabled for Tasks that are already completed (the IsCompleted property is true). You can pass other parameters to customize the Action’s look and behavior.

The images below illustrate the Complete Action in the UI.

ASP.NET Core Blazor

ActionAttributeExample_CompleteAction

WinForms

ActionAttributeExample_CompleteAction

ASP.NET Web Forms

ActionAttributeExample_CompleteAction

Create an Action that Displays a Pop-up Dialog

Extend the Task class with two additional properties (Deadline and Comments) to demonstrate a more complex scenario.

using DevExpress.ExpressApp.Model;
// ...
public virtual DateTime? Deadline { get; set; }

[FieldSize(FieldSizeAttribute.Unlimited),ModelDefault("AllowEdit", "False")]
public virtual string Comments { get; set; }

// Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.

Implement an Action that postpones the Deadline by a specified number of days and updates the Comments text. First, declare the following non-persistent class that holds parameters to be specified when a user postpones a Task.

using DevExpress.ExpressApp.DC;
// ...
[DomainComponent]
public class PostponeParametersObject {
    public PostponeParametersObject() { PostponeForDays = 1; }
    public uint PostponeForDays { get; set; }
    [FieldSize(FieldSizeAttribute.Unlimited)]
    public string Comment { get; set; }
}

Then, add the following Postpone method to the Task class. This method takes a parameter of the PostponeParametersObject type and is decorated with the Action attribute.

[Action(Caption = "Postpone",
    TargetObjectsCriteria = "[Deadline] Is Not Null And Not [IsCompleted]")]
public void Postpone(PostponeParametersObject parameters) {
    if (Deadline.HasValue && !IsCompleted && (parameters.PostponeForDays > 0)) {
        Deadline += TimeSpan.FromDays(parameters.PostponeForDays);
        Comments += String.Format("Postponed for {0} days, new deadline is {1:d}\r\n{2}\r\n",
        parameters.PostponeForDays, Deadline, parameters.Comment);
    }
}

As a result, the Task.Postpone Action, that accompanies the Task Views, is automatically created. This Action invokes a dialog with the PostponeParametersObject Detail View and executes the Postpone method after a user specifies the parameters and clicks OK. The following images illustrate this.

ASP.NET Core Blazor

The Postpone Action ASP.NET Core Blazor

WinForms

The Postpone Action WinForms

ASP.NET Web Forms

The Postpone Action ASP.NET Web Forms

Tip

If it is necessary to reorder parameters displayed in a popup dialog, modify the layout of a parameter object’s Detail View in the Model Editor. In the example above, the appropriate Detail View node is PostponeParametersObject_DetailView. Refer to the folowing topic to learn more about layout customizations: View Items Layout Customization.

Access the current object instance

If you declare a PostponeParametersObject constructor that takes a parameter of type Task, the current Task instance is passed to this constructor when a user initiates the Action.

[DomainComponent]
public class PostponeParametersObject {
    private Task task;
    public PostponeParametersObject(Task task) {
        PostponeForDays = 1;
        this.task = task;
    }
    // ...
}