用代碼擴展和自定義應用程序模型

You can customize the information loaded to the Application Model via the Model Editor. It allows you to edit the information at design time, forming Application Model layers in each project. The layers are superimposed onto one another in a certain order. Values from every successive layer override the corresponding values from the previous layer (see the Application Model Basics topic). However, there is one more approach you can use to customize the information stored in the Application Model. In most cases, this approach is less suitable because the changes to be made in the Application Model are performed in code. But, this approach is useful when the feature that you implement in a module demands the modification of the information generated in the Application Model, by default. When implementing a new feature, you may need to add custom nodes to the Application Model. You may also need to customize an existing node by adding custom properties to it. In this way, you can allow other developers or end-users to change the behavior of your code by modifying your custom nodes and properties in the Model Editor. This topic explains how to extend and customize the Application Model in Code.

你可以用模型編輯器自定義應用程序模型信息。你可以在設計時候編輯它,在每個項目形成應用模型層。每層按照一定的順序疊加。從每一個連續的值將覆蓋層從上一層的相應值(見應用模型基礎主題)。然而你可以用另外一種方式存儲應用程序模型自定義信息。在大多數情況下,這種方法不太合適,因爲將要在應用模型中所做的更改執行的代碼。但是,這種方法是非常有用的功能,您在一個模塊的需求落實在應用模型產生的信息的修改,默認情況下。當實現一個新功能,需要在應用程序模型中添加自定義節點。你也還需要爲已有的自定義節點添屬性。通過這種方式,允許其它開發者或者終端用戶更改你的代碼用模型編輯器中自定義節點和屬性的操作。這個主題說明如何用代碼擴展和自定義應用程序模型。

Several typical scenarios are provided in this topic. You can select one of them or combine them, to handle more complex customizations:

這個主題包含幾個典型案例。你可以選擇其中一個或者幾個用來處理更復雜的自定義。

If it is required to access properties exposed by an existing node, use the approach described in the Access the Application Model in Code topic.

如果需要訪問已有節點的公共屬性,請參考用代碼訪問應用程序模型

Add a Custom Property to the Existing Node

爲應用節點添加一個自定義屬性

To add new properties to the existing node, you should first define an interface derived from the IModelNode interface, and exposing the required properties:

爲已有節點添加新的屬性,首先定義一個繼承IModelNode接口的接口,並公開所需屬性。

C#

VB

using DevExpress.ExpressApp.Model;

// ...

public interface IModelMyModelExtension : IModelNode {

string MyCustomProperty { get; set; }

}

Then, extend the required node in your Module or Controller. Override the ModuleBase.ExtendModelInterfaces method or implement the IModelExtender interface, respectively.

然後用模塊或者控件擴展需求的節點。分別覆寫ModuleBase.ExtendModelInterfaces方法或實現IModelExtender接口。

C#

VB

public sealed partial class CustomizeModelExampleModule : ModuleBase {

// ...

public override void ExtendModelInterfaces(ModelInterfaceExtenders extenders) {

base.ExtendModelInterfaces(extenders);

extenders.Add<IModelApplication, IModelMyModelExtension>();

}

// ...

}

Rebuild your solution and open the Model Editor, to see how the code above affects the Application Model.

重新編譯項目並打開模型編輯器,觀察以上代碼在應用程序模型中的實現效果。

The IModelApplication node now exposes the MyCustomProperty property. To add the property to another node, substitute the interface corresponding to the required node, instead of the IModelApplication (see Application Model Structure).

IModelApplication節點現在公開MyCustomProperty屬性。要添加另一個節點的熟悉,代替接口對應所需節點,而不是IModelApplication(見應用程序模型結構)

You can decorate nodes' properties with the following attributes:

Attribute(特性)

Description(描述)

Browsable

Indicates that a property is visible in the Model Editor. All properties added via the approach described above are visible, by default. To hide a property, decorate it with the Browsable attribute and pass false as the attribute's parameter.

在模型編輯器中指出屬性是否顯示。默認情況下,所以屬性通過這種方式標示是否顯示。隱藏用特性Browsable設置參數爲false

Category(分類)

Specifies the target property category. The properties of each node are grouped by their categories in the Model Editor's property grid. The default category is "Misc". To assign a category to the property, decorate the property with the Category attribute and pass a category name as the attribute's parameter. If the specified category does not exist, it will be added.

指定目標屬性分類。每個屬性節點分組在模型編輯器屬性表格分類中。默認分類是“Misc”。標示屬性分類,用一個分類名稱參數修飾屬性。如果指定的分類不存在,將被添加。

DataSourceProperty

Specifies a name of the property which exposes a list of the target property's possible values. You will be able to choose a value via the drop-down list in the Model Editor's property grid. When the current property's node exposes a list of child nodes (implements the IModelList<ChildNodeType> interface, as illustrated in the Extend The Application Model with New Nodes section), you can pass "this" as the DataSourceProperty attribute parameter. As the result, the child nodes list will be the current property possible values list.

指定一個屬性可選的值列表。在模型編輯器中通過下拉列表選擇一個值,噹噹前屬性節點公開了子節點列表(實現了IModelList<ChildNodeType>接口,如用新節點擴展應用程序模型圖所示部分),你可以用“this”作爲DataSourceProperty特性的參數。返回結果,子節點列表將用作當前屬性可選值列表。

DefaultValue

Specifies the target property's default value.
指定目標屬性的默認值。

Editor(編輯)

Binds a custom editor to the property (see EditorAttribute).

爲屬性綁定一個自定義編輯(見EditorAttribute)。

Description(描述)

Specifies the target property's description displayed in the Model Editor.

指定在模型編輯器中顯示目標屬性的描述。

Localizable(本地化)

Specifies that the target property can be localized. To define a localizable property, decorate it with the Localizable attribute and pass true as the attribute's parameter.

是否本地化目標屬性。如果需要本地化目標屬性,則設置Localizable特性參數爲“true”.

ReadOnly(只讀)

To prohibit property value modification via the Model Editor, decorate the property with the ReadOnly attribute and pass true as the attribute's parameter. Alternatively, you can omit the property's setter. But, the ReadOnly attribute affects only the Model Editor, and does not restrict the property modification in code.

禁止用模型編輯器修改屬性值,用ReadOnly特性修飾,並設置特性參數爲“true”。或者你省略屬性的寫操作。但是,ReadOnly隻影響模型編輯器,不作用於代碼修改目標屬性。

Required(必須)

Indicates that a target property should have a value. The Model Editor will not allow you to save changes until you supply this property value.

表明一個目標屬性有一個值。模型編輯器不允許屬性值爲空。

Examples of some of these attributes in use will be provided later in this topic.

下面用一些特性的列子.

Note (備註)

Do not create the property named "Application". Otherwise, this property will hide the node's inherited IModelNode.Application property. Hiding the Application property causes the "Cannot compile the generated code" exception.

不能用名稱爲”Application”的屬性。否則,這個屬性將隱藏繼承IModelNode.Application屬性。隱藏應用程序屬性會導致“不能編譯生成的代碼”的異常。

Extend The Application Model with New Nodes(用新節點擴展應用程序模型)

The extension of the Application Model with new nodes is performed similarly to adding new properties. First, you should define interfaces representing your custom nodes and their properties:

用新節點擴展應用程序模型跟添加新屬性相似。首先,定義接口描述你的自定義節點和他們的屬性。

C#

VB

using System.ComponentModel;

// ...

[KeyProperty("Name")]

public interface IModelMyChildNode : IModelNode {

string Name { get; set; }

[Localizable(true)]

string MyStringProperty { get; set; }

int MyIntegerProperty { get; set; }

}

public interface IModelMyNodeWithChildNode : IModelNode {

IModelMyChildNode MyChildNode { get; }

}

public interface IModelMyNodeWithChildNodes : IModelNode, IModelList<IModelMyChildNode> {

}

As you can see, each custom node is derived from the IModelNode interface. The IModelMyNodeWithChildNode node exposes a single IModelMyChildNode child node.

正如你所看到的,每個自定義節點都繼承於IModelNode接口。IModelMyNodeWithChildNode公開了一個IModelMyChildNode子節點

Note (備註)

When determining whether a property will be a child node or value, the existence of the setter in its declaration is taken into account. If the property has a setter, then it will not automatically be filled with values, and vice versa. So, the MyChildNode property has no setter (marked as ReadOnly in VB).

在判斷一個屬性是否是一個子節點或值,要考慮定義寫屬性。如果這個屬性有一個可寫,那麼他的值不會自動填充,反之亦然。因此,MyChildNode屬性沒有可寫(在VB中標誌用ReadOnly)

The IModelMyNodeWithChildNodes node exposes the list of IModelMyChildNode nodes, as it supports the IModelList<IModelMyChildNode> interface.

IModelMyNodeWithChildNodes公開了IModelMyChildNode節點列表,因爲他支持IModelList<IModelMyChildNode> 接口。

You can decorate interfaces, representing nodes, with the following attributes:

你可以用下列特性修飾接口,節點。

Attribute(特性)

Description(描述)

DisplayName
(
顯示名稱)

Specifies the node's display name, which is used as the node's caption in the Model Editor.

指定一個節點的顯示名稱,這是用作模型編碼器中用節點的標題。

DisplayProperty
(顯示屬性)

Specifies the node's property name, whose value is used as the node's caption in the Model Editor.
指定節點的屬性名稱,其值是用做模型編輯器節點的標題

ImageName
(圖片名稱)

Specifies the node's image, which is used in the Model Editor. See the ImageNameAttribute topic for additional information.
指定節點圖片,用在模型編輯器中。其他信息見ImageNameAttribute

KeyProperty
(關鍵鍵屬性)

Specifies the node's key property. The key property is used to identify nodes. Only a string property can be a key property. If the KeyProperty attribute is omitted, the Id key property is generated automatically. The use of this attribute is illustrated in the code above.

指定節點的關鍵屬性。關鍵屬性是用來識別節點。只用字符串屬性才能用作關鍵屬性。如果忽略,ID關鍵屬性自動生成。上面代碼演示了這個作用。

To add these nodes to a certain parent node in the Application Model, extend the required node's interface, as described in the Add a Custom Property to the Existing Node section of this topic.

在應用程序模型中爲某一個父節點添加這些節點,擴展需要的節點的接口,見爲存在的節點添加自定義屬性。

C#

VB

public interface IModelMyModelExtension : IModelNode {

// ...

IModelMyNodeWithChildNode MyNodeWithOneChildNode { get; }

IModelMyNodeWithChildNodes MyNodeWithSeveralChildNodes { get; }

}

// ...

public override void ExtendModelInterfaces(ModelInterfaceExtenders extenders) {

base.ExtendModelInterfaces(extenders);

extenders.Add<IModelApplication, IModelMyModelExtension>();

}

Rebuild your solution and open the Model Editor to see how the code above affects the Application Model.

重新不要你的項目,並打開模型編輯器,看到如下結果。

You can add child nodes to the MyNodeWithSeveralChildNodes node via the context menu.

你可以通過上下文菜單爲MyNodeWithSeveralChildNodes添加子節點。

Customize the Application Model via the Nodes Generator Class

通過自定義應用程序模型節點生成類

In some scenarios, it is required to implement logic to be executed when the custom node is added to the Application Model. The so-called Generator classes serve this purpose. The Generator is the ModelNodesGeneratorBase descendant. The ModelNodesGeneratorBase class exposes the GenerateNodesCore virtual method. To implement the required logic, override this method. To access the node for which the generator is invoked, use the method's node parameter. The following snippet illustrates Generator implementation.

在某些情況下,當給應用程序模型添加自定義節點,它需要邏輯實現。所謂生成器類能達到這個目的。生成器是ModelNodesGeneratorBase的後代。ModelNodesGeneratorBase公開了虛方法GenerateNodesCore覆寫該虛方法,實現需求邏輯。用生成器訪問節點,用方法的節點參數。下面演示生成器的實現。

C#

VB

using DevExpress.ExpressApp.Model.Core;

// ...

public class MyChildNodesGenerator : ModelNodesGeneratorBase {

protected override void GenerateNodesCore(ModelNode node) {

for (int i = 0; i < 10; i++) {

string childNodeName = "MyChildNode " + i.ToString();

node.AddNode<IModelMyChildNode>(childNodeName);

node.GetNode(childNodeName).Index = i;

}

}

}

Note (備註)

The node parameter exposes the Application property, providing you with access to the whole Application Model.
節點參數公開了應用程序屬性,供你訪問整個應用程序模型。

This Generator creates ten IModelMyChildNode nodes and assigns indexes to them. To apply the Generator to the required node, use the ModelNodesGenerator attribute:

這個生成器建立十個IModelMyChildNode節點並標出索引。要應用生成所需節點,請用ModelNodesGenerator 特性

C#

VB

[ModelNodesGenerator(typeof(MyChildNodesGenerator))]

public interface IModelMyNodeWithChildNodes : IModelNode, IModelList<IModelMyChildNode> {

}

Each Node can have only one generator. However, additional customizations can be performed via the Generator Updaters

每個節點只有一個生成器。然而,通過Generator Updaters可以實現另外的自定義。

Rebuild your solution and open the Model Editor, to see how the code above affects the Application Model.

重新編譯項目並打開模型編輯器,看到如下結果。

Note(備註)

The Generator affects the Application Model zero layer. So, the GenerateNodesCore method will be automatically executed on demand, when the data stored in the MyNodeWithSeveralChildNodes is required for the first time. For details on the Model layers, refer to the Application Model Basics topic. To ensure that the generator is executed only once, you can do the following:

生成器作用於應用程序模型零層。因此,GenerateNodesCore方法將被按需執行,第一次必須存儲MyNodeWithSeveralChildNodes數據。有關模型層的詳細情況,請參考應用程序模型基礎主題。爲了確保生成器只被生成一次,你可以按照以下方法做:

  • Set the breakpoint inside the GenerateNodesCore method.
    GenerateNodesCore方法內設置斷點。
  • Run the Windows Forms application.
    運行Windwos Forms應用程序。
  • Invoke the run-time Model Editor. The application execution will be interrupted.
    在運行時調用模型編輯器。應用程序將被中斷。
  • Continue the application execution and close the Model Editor.
    關閉模型編輯器並繼續運行應用程序。
  • Invoke the run-time Model Editor once again. The application execution will not be interrupted. The Application Model's zero layer already contains all the required information at this moment, so there is no need to invoke the Generator again.
    再次在運行時調用模型編輯器。應用程序將不被中斷。此刻應用程序模型的零層已經包含所有所需的信息,因此將不需再此調用生成器。

Implement a Property Having a List of Predefined Values

實現一個擁有預定義值列表的屬性

Let's assume that the IModelMyNodeWithChildNodes node should expose the SelectedChildNode property, representing the "selected" child node. The user-friendly approach is to provide a drop-down, allowing you to choose one of the valid values in the Model Editor. So, the property should have a list of predefined values. This property can be implemented in the following manner:

假設IModelMyNodeWithChildNodes節點應公開SelectedChildNode屬性,代表選擇的子節點。爲用戶提供最好的方法是下列,在模型編輯器中允許選擇也該可用值。因此,這個屬性應有一個預定義的值列表。這個屬性的實現方式如下:

C#

VB

using DevExpress.Persistent.Base;

// ...

public interface IModelMyNodeWithChildNodes : IModelNode, IModelList<IModelMyChildNode> {

[DataSourceProperty("this")]

IModelMyChildNode SelectedChildNode { get; set; }

}

Generally the DataSourceProperty attribute can be used to specify a name of the current node's property which exposes a list of the target property's possible values. Additionally, you can pass "this" as the DataSourceProperty attribute parameter (as illustrated in the code above). In this case, a list of the target property's possible values will be filled with the current node's child nodes.
一般來說DataSourceProperty特性可被用於給節點屬性提供可用值列表。另外你可用“this”作爲DataSourceProperty特性的參數(如圖上代碼所示)。這樣,當前節點的子節點填充到目標屬性的可用值列表。

Rebuild your solution, and open the Model Editor to see how the code above affects the Application Model.
重新編譯項目並打開模型編輯器,看到如下結果。

You can add and remove child nodes, and the drop-down list will reflect changes instantly.

你可用添加或者移除子節點,下列列表立即發生改變。

Note(備註)

To define a more complex logic for generating the list or predefined values, implement the supplementary property holding the required list, as described in the text section of this topic. Then, make this property hidden, by applying the Browsable(false) attribute to it. Finally, decorate your target property with the DataSourceProperty attribute and pass the supplementary hidden property name as the parameter. Note that the list items must be of the same type as the target property.

要定義一個更復雜的生成列表或預定義值邏輯,實現屬性持有所需的補充列表,參考本主題文本所述。然後,使用Browsable(false)特性隱藏這個屬性。最後,用DataSourceProperty修飾目標屬性並作爲參數補充隱藏屬性名稱。注意作爲目標屬性列表屬性必須是相同類型。

Use the Domain Logic to Implement the Calculated Property

用域邏輯實現可計算屬性

To customize the node's properties behavior, the Domain Logic (which is a part or the Domain Components technology) can be used. The common use case of Domain Logic is implementing calculated properties. The following code illustrates how to implement the NumberOfChildNodes property, which gets the number of current node's child nodes.

用域邏輯(域組件)實現自定義節點的屬性行爲。通常域邏輯實現可計算屬性。下面代碼演示如何實現NumberOfChildNodes屬性,計算當前節點的子節點個數。

C#

VB

using DevExpress.ExpressApp.DC;

// ...

public interface IModelMyNodeWithChildNodes : IModelNode, IModelList<IModelMyChildNode> {

// ...

int NumberOfChildNodes { get; }

}

// ...

[DomainLogic(typeof(IModelMyNodeWithChildNodes))]

public class MyNodeWithChildNodesLogic {

public static int Get_NumberOfChildNodes(

IModelMyNodeWithChildNodes modelMyNodeWithChildNodes) {

return modelMyNodeWithChildNodes.NodeCount;

}

}

The DomainComponentAttribute in the code above indicates that the MyNodeWithMultipleChildNodesLogic class represents the Domain Logic for the IModelMyNodeWithChildNodes node. This class exposes the Get_NumberOfChildNodes method, executed when getting the NumberOfChildNodes property value. This method returns the number of IModelMyChildNode child nodes exposed by the IModelMyNodeWithChildNodes node. For details on Domain Logic, refer to the Domain Components Basics topic.

在上面的代碼DomainComponentAttribute表明MyNodeWithMultipleChildNodesLogic類代表的IModelMyNodeWithChildNodes節點域邏輯。這個類公開Get_NumberOfChildNodes方法,執行時獲取NumberOfChildNodes屬性值。此方法返回IModelMyChildNode子節點的情況,IModelMyNodeWithChildNodes節點暴露節點的數目。有關域邏輯的細節,請參考域組件基本主題。

Rebuild your solution, and open the Model Editor to see how the code above affects the Application Model.

重新編譯項目並打開模型編輯器,看到如下結果。

You can add and remove child nodes and the NumberOfChildNodes property value will reflect changes instantly.

你可用添加或者移除子節點,下列列表立即發生改變。

Add the Generator Updaters

Each node can have a single Generator assigned. However, you can "attach" one or more Updaters to the Generator. The Generator Updater is the ModelNodesGeneratorUpdater<T> class' descendant. The ModelNodesGeneratorUpdater<T> class exposes the UpdateNode virtual method. To implement the required logic, override this method. To access the node for which the Updater is invoked, use the method's node parameter. The following snippet illustrates the implementation of two Generator Updaters.

每個節點有一個生成器分配。然而,你可以附加一個或多個Updaters給生成器。這個生成器Updater是ModelNodesGeneratorUpdater<T>類的後代。ModelNodesGeneratorUpdater<T> 類公開虛方法UpdateNode覆寫這個方法實現需求邏輯。要訪問該更新被調用時,使用該方法的節點參數節點。下面的代碼片段說明了兩個生成器更新者的執行情況。

C#

VB

public class MyChildNodesUpdater1 : ModelNodesGeneratorUpdater<MyChildNodesGenerator> {

public override void UpdateNode(ModelNode node) {

foreach (IModelMyChildNode childNode in ((IModelMyNodeWithChildNodes)node)) {

childNode.MyIntegerProperty = childNode.Index + 1;

}

}

}

public class MyChildNodesUpdater2 : ModelNodesGeneratorUpdater<MyChildNodesGenerator> {

public override void UpdateNode(ModelNode node) {

((IModelMyNodeWithChildNodes)node).SelectedChildNode = "MyChildNode 9";

}

}

Note (備註)

The node parameter exposes the Application property, providing you with access to the whole Application Model.
這個節點參數公開應用程序屬性,供你訪問整個應用程序模型。

The first Updater sets the IModelMyChildNode.MyIntegerProperty values. The second sets the IModelMyNodeWithChildNodes.SelectedChildNode property value. All the Updaters should be registered in the overridden ModuleBase.AddGeneratorUpdaters method:

第一次更新設置IModelMyChildNode.MyIntegerProperty值。第二次設置IModelMyNodeWithChildNodes.SelectedChildNode屬性值。所有的更新都需覆寫ModuleBase.AddGeneratorUpdaters方法註冊。

C#

VB

public sealed partial class CustomizeModelExampleModule : ModuleBase {

// ...

public override void AddGeneratorUpdaters(ModelNodesGeneratorUpdaters updaters) {

base.AddGeneratorUpdaters(updaters);

updaters.Add(new MyChildNodesUpdater1());

updaters.Add(new MyChildNodesUpdater2());

}

// ...

}

Rebuild your solution and open the Model Editor, to see how the code above affects the Application Model.

重新編譯項目並打開模型編輯器,看到如下結果。

Note (備註)

If you previously modified these property values in the Model Editor, you should reset differences for the MyNodeWithSeveralChildNodes node to see the changes. To do this,right-click this node and select Reset Differences. The reason for this is that the Updaters operate at the Application Model zero layer, and changes can be overridden in higher layers.
如果你之前修改哪些屬性用模型編輯器,你應當重置MyNodeWithSeveralChildNodes節點看到不同變化。其原因是更新者在應用程序模型零層操作,並能在更高層覆寫。

To see another example of a custom Generator Updater, refer to the EnumDescriptor.GenerateDefaultCaptions method description.

看其他自定義生成器更新者的例子,請參考EnumDescriptor.GenerateDefaultCaptions方法描述。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章