Customize Controllers and Actions(自定义控制器和操作)
To implement a new feature in the XAF, create a new Controller. If the feature requires end-user interaction, add Actions to it. At the same time, you may need to customize a Controller or Action provided by the XAF or a third party. Most of built-in Controllers expose events you can handle to add your custom code. Another approach is to inherit from the existing Controller and override its virtual methods. In some situations, it is easier and more effective to handle the Controller’s events or the Action’s events. In this topic, we will detail the situations in which each of these approaches to customize the provided features is more appropriate.
要在XAF中实现新功能,请创建一个新的Controller。如果该功能需要最终用户交互,请向其中添加Actions。同时,您可能需要自定义XAF或第三方提供的Controller或Action。大多数内置Controller都会公开您可以处理的事件以添加您的自定义代码。另一种方法是从现有Controller继承并覆盖其虚拟方法。在某些情况下,处理Controller的事件或Action的事件更容易、更有效。在本主题中,我们将详细介绍这些自定义提供的功能的方法中的每一种更合适的情况。
Access Controller’s Events and Properties(访问控制器的事件和属性)
This approach to customizing a particular feature is more appropriate if several additional independent customizations of an Action’s behavior or a Controller’s behavior are required. For instance, two modules declare business objects that demand additional initialization when they are created via the New Action. In this instance, both of these modules should extend the New Action behavior independently. In this case, handling events is more appropriate than inheriting from a Controller.
如果需要对Action的行为或Controller的行为进行几个额外的独立定制,这种定制特定功能的方法更合适。例如,两个模块声明了在通过New Action创建时需要额外初始化的业务对象。在这种情况下,这两个模块都应该独立扩展New Action行为。在这种情况下,处理事件比从Controller继承更合适。
Note
In specific situations, you may need to handle a chain of events, rather than a single event. 在特定情况下,您可能需要处理一系列事件,而不是单个事件。
You can access any built-in Controller from your custom Controller using the Frame.GetController<ControllerType> method.
您可以使用Frame. GetController<ControlllerType>方法从自定义控制器访问任何内置控制器。
The following code demonstrates how to remove the Person item from the New Action’s items list, to prohibit end-users from creating Person objects. A new Controller is created for this purpose. In its OnActivated method, the NewObjectViewController is accessed to subscribe to its NewObjectViewController.CollectDescendantTypes event. This event is fired when generating the New Action’s items list. In the CollectDescendantTypes event handler, the Person item is removed from this list. The OnDectivated method unsubscribes the CollectDescendantTypes event.
下面的代码演示了如何从New Action的项目列表中删除Person项目,以禁止最终用户创建Person对象。为此目的创建了一个新的Controller。在其OnActivated方法中,访问NewObjectViewController以订阅其NewObjectViewControllerCollectDescendantTypes事件。生成New Action的项目列表时会触发此事件。在CollectDescendantTypes事件处理程序中,Person项目将从此列表中删除。OnDectivated方法取消订阅CollectDescendantTypes事件。
C#
using DevExpress.ExpressApp.SystemModule;
using DevExpress.Persistent.BaseImpl;
// ...
public class CustomizeNewActionWindowController : ViewController {
protected override void OnActivated(){
base.OnActivated();
NewObjectViewController controller = Frame.GetController<NewObjectViewController>();
if (controller != null) {
controller.CollectDescendantTypes += NewObjectViewController_CollectDescendantTypes;
}
}
private void NewObjectViewController_CollectDescendantTypes(
object sender, CollectTypesEventArgs e) {
foreach (Type type in e.Types) {
if (type.Name == nameof(Person)) { e.Types.Remove(type); break; }
}
}
protected override void OnDeactivated() {
NewObjectViewController controller = Frame.GetController<NewObjectViewController>();
if (controller != null) {
controller.CollectDescendantTypes -= NewObjectViewController_CollectDescendantTypes;
}
base.OnDeactivated();
}
}
Important
To avoid possible null reference exceptions when accessing an existing Controller from your code, always ensure that the Frame.GetController<ControllerType> method result is not null when the XafApplication.OptimizedControllersCreation property is true.
要避免从代码访问现有控制器时可能出现的空引用异常,请始终确保当XafApplication.OptimizedControllersCreation属性为true时,Frame. GetController<ControlllerType>方法结果不为空。
Inherit From a Controller(从控制器继承)
When building an XAF application, you may face the following task: a Controller provides a useful feature, but you need to slightly customize it. This customization does not depend on any conditions, so you will not need to modify the customizations in another module. In this instance, the best technique is to inherit from the required Controller and override its virtual methods. You may need to customize a particular Action as well. In this instance, since Actions are contained in Controllers, you will also need to inherit from the Action’s Controller and override its virtual methods.
在构建XAF应用程序时,您可能会面临以下任务:控制器提供了一个有用的功能,但您需要稍微对其进行自定义。这种自定义不依赖于任何条件,因此您不需要修改另一个模块中的自定义。在这种情况下,最好的技术是从所需的控制器继承并覆盖其虚拟方法。您可能还需要自定义特定的操作。在这种情况下,由于操作包含在控制器中,因此您还需要从操作的控制器继承并覆盖其虚拟方法。
All of the Controllers that do not have descendants are instantiated for a Frame. Also, since a descendant Controller inherits the base Controller’s Actions, it generally does not make sense to create several descendants of a Controller within modules that might be used together in an XAF application. In this situation, all of these descendants will be instantiated, and there will be several copies of the base Controller’s Actions available. This situation causes an exception because Actions must have unique IDs. Thus, it is better to create only one descendant of the base Controller and perform all the customizations in it. If required, however, you can have several descendant Controllers, but in this instance you will need to manually disable inherited Actions in the Controllers’ code.
所有没有后代的控制器都将为框架实例化。此外,由于后代控制器继承了基本控制器的操作,因此在XAF应用程序中可能一起使用的模块中创建多个控制器的后代通常没有意义。在这种情况下,所有这些后代都将被实例化,并且将有几个可用的基本控制器操作副本。这种情况会导致异常,因为操作必须具有唯一的ID。因此,最好只创建一个基本控制器的后代并在其中执行所有自定义。但是,如果需要,您可以有几个后代控制器,但在这种情况下,您需要在控制器代码中手动禁用继承的操作。
Important
- Take a special note on selecting an appropriate built-in Controller type when creating its descendant. In most cases, creating a descendant of a built-in Controller requires selecting the last descendant in the inheritance chain. For example, if a Controller has WinForms, ASP.NET Web Forms or ASP.NET Core Blazor-specific descendants (such as the WinModificationsController, WebModificationsController and BlazorModificationsController descendants of the ModificationsController class), it is necessary to create their descendants rather than a descendant of the parent class. Otherwise, both the built-in Controller and your descendant will be activated, and duplicate Actions will be displayed, as mentioned above.
在创建其后代时,请特别注意选择适当的内置控制器类型。在大多数情况下,创建内置控制器的后代需要选择继承链中的最后一个后代。例如,如果控制器具有WinForms、ASP.NETWeb Forms或ASP.NETCore Blazor特定的后代(如ModificationsController类的WinModificationsController、WebModificationsController和BlazorModificationsController后代),则需要创建它们的后代而不是父类的后代。否则,内置控制器和您的后代都将被激活,并显示重复的操作,如上所述。
However, remember that ViewController and WindowController are basic Controllers. They do not provide any particular features and are designed for developing new Controllers. Therefore, you can inherit from these parent Controllers to create new Controllers in your UI-specific module projects. If your solution does not contain these projects, add a Controller to an application project. Your newly implemented items will not conflict with any other of ViewController’s and WindowController’s children.
但是,请记住ViewController和WindowController是基本的控制器。它们不提供任何特定功能,是为开发新的控制器而设计的。因此,您可以从这些父控制器继承,以便在您的UI特定模块项目中创建新的控制器。如果您的解决方案不包含这些项目,请将控制器添加到应用程序项目中。您新实现的项目不会与ViewController和WindowController的任何其他子项目冲突。- Do not change the ViewController.TargetObjectType, ViewController.TargetViewType, ViewController.TargetViewId or ViewController.TargetViewNesting property values when inheriting a built-in Controller. Otherwise, you will lose the functionality of the inherited Controller in other Views that do not match the conditions specified by these properties.
继承内置控制器时不要更改ViewController. TargetObjectType、ViewController.TargetViewType、ViewController.TargetViewId或ViewController.TargetViewNest属性值。否则,您将在与这些属性指定的条件不匹配的其他视图中丢失继承的控制器的功能。
When inheriting from a Controller, the Application Model will contain information on both the base and inherited Controllers. In the ActionDesign | Controllers node, the new Controller will contain Actions declared in it. The inherited Actions will be displayed under the base Controller’s node.
从控制器继承时,应用程序模型将包含有关基本控制器和继承控制器的信息。在ActionDesign|控制器节点中,新的控制器将包含在其中声明的操作。继承的操作将显示在基本控制器的节点下。
As an example of this customization type, consider the WebModificationsController Controller. It contains the following Actions: Cancel, Save, SaveAndClose and Edit. Each Action has a virtual method: Cancel, Save, SaveAndClose and ExecuteEdit. This method is invoked when an end-user performs a certain operation with the Action. So to customize a default execution process, you can inherit from the WebModificationsController Controller and override any of these virtual methods. In this case, all of the UI settings (Category, Caption, Image, Shortcut, Tooltip, etc.) and the management state (Active and Enabled) of the Actions will be reused.
作为这种自定义类型的示例,考虑WebModificationsController控制器。它包含以下操作:取消、保存、保存和编辑。每个操作都有一个虚拟方法:取消、保存、保存和执行编辑。当最终用户使用操作执行某个操作时,会调用此方法。因此,要自定义默认执行过程,您可以从WebModificationsController控制器继承并覆盖这些虚拟方法中的任何一个。在这种情况下,所有UI设置(类别、标题、图像、快捷方式、工具提示等)和操作的管理状态(活动和已启用)都将被重用。
By default, after executing the SaveAndClose Action in an ASP.NET Web Forms application, a Detail View is displayed in a view mode. With the Controller demonstrated in the code below, the Incident Detail View is closed after executing this Action.
默认情况下,在ASP.NETWeb窗体应用程序中执行SaveAndClos操作后,将以视图模式显示详细信息视图。使用下面代码中演示的控制器,执行此操作后将关闭事件详细信息视图。
C#
using DevExpress.ExpressApp.Web.SystemModule;
// ...
public class MyWebModificationsController : WebModificationsController
{
protected override void SaveAndClose(SimpleActionExecuteEventArgs e) {
View view = View;
base.SaveAndClose(e);
if ((view != null) && (view.ObjectTypeInfo.Type == typeof(Incident))) {
view.Close();
}
}
}
In this example, an Action behavior is customized via a single method. However, Controllers and Actions can be more complex, so, you may need to override several virtual methods.
在此示例中,Action行为是通过单个方法自定义的。但是,控制器和操作可能更复杂,因此您可能需要覆盖多个虚拟方法。