XAF 转换不同应用程序模型

 

Convert Application Model Differences
转换不同应用程序模型

eXpressApp Framework > Concepts > Application Model > Convert Application Model Differences

The eXpressApp Framework is based on the modules concept. As a rule, every module implements a certain feature. Entities implemented in a module, such as persistent classes or extra Application Model nodes - can be customized by users of the application via the Model Editor. Such customizations are saved as Application Model differences in XafML files. Legacy Application Model differences might pose a problem when a module is updated to a new version, and its internal structure is changed. So, developers implementing modules should provide means to convert Application Model differences with new versions. The eXpressApp Framework provides easy ways to implement such converters. This topic describes them.

eXpressApp框架基于模块构成。作为一个规则,每个模块实现一个特定功能。在一个模块中实现实体,如持久类或者用户应用程序可以通过模型编辑器定制其他应用程序模型节点。这种自定义保存不同应用程序模型在XafML文件中。当你升级一个模块是,可能不同应用程序模型会有问题,它的内部结构发生改变。因此,要实现转换新版本应用程序模型的差异部分。eXpressApp框架通过了非常容易的方法实现转换。本主题详细描述。

Basically, Application Model differences are converted in two steps.
基本上,转换应用程序模型差异部分分两步。

  1. The XafML files stored in XML format can be processed by a module implementing the IModelXmlConverter interface. This step allows the application to start correctly, where otherwise, legacy Application Model differences would cause an exception at the application start. In simple conversion scenarios, this may be the only required step.
    XafML
    文件以XML文件格式存储,能被由实现IModelXmlConverter接口的模块处理。这个步骤可使应用程序正常启动,另外应用程序模型的差异可能导致应用程序在启动时异常。这是实现简单转换必须要做的步骤。
  2. For complex conversion scenarios, special updaters implementing the IModelNodeUpdater<T> interface should be used. Such updaters can perform much more versatile conversions.
    复杂的转换,指定更新者实现IModelNodeUpdater<T>接口。这样的更新者可以实现更灵活的转换。

Depending on a particular scenario, you may need to perform either both of these steps or just one. So, for example, in one scenario you may need to implement an XML converter, so that the application could start, and a node updater, to perform a complex conversion. In other scenarios, you may need to implement only an XML converter or a node updater.

根据不同情况,你可能需要实现这两个步骤中一个或多个。例如,在一种情况下你可能需要实现一个XML转换,启动应用程序,一个节点更新,实现一个复杂转换。在其他情况下,你可能只需实现一个XML转换或一个节点更新。

Implement an XML converter(实现一个XML转换)

An XML converter is represented by a module implementing the IModelXmlConverter interface. The interface declares the IModelXmlConverter.ConvertXml method, which is invoked for each node customized in Application Model differences. The method takes the ConvertXmlParameters object, supplying differences as a parameter. You can handle changes to a node in the method's body, by converting differences and making them correspond to the actual model. Consider the following example.

用一个模块实现IModelXmlConverter接口代表一个XML转换器。这个接口定义了IModelXmlConverter.ConvertXml方法,被用在应用程序模型差异部分的每个自定义节点。
该方法使用ConvertXmlParameters参数对象作为差异参数.你可以在方法内改变一个节点处理,通过转换差异使他们适应实际模型。参考下面例子。

Suppose your application uses a module which adds an OperatingMode string property to the Application Model's Options node. This property is designed to take either a "Simple" or "Complex" word as a value. Originally, the module extends the Application Model in the following way:

假设你用了一个应用程序给应用程序模型的选项节点添加一个字符串属性OperatingMode模块,这个属性用“Simple”或“Complex”作为值。最初,这个模块同过以下方式扩展应用程序模型

C#

 

VB

 

using DevExpress.ExpressApp.Model;

 

public interface IModelMyOptions{

    string OperatingMode { get; set; }

}

public sealed partial class MyModule : ModuleBase {

    //...

    public override void ExtendModelInterfaces(ModelInterfaceExtenders extenders) {

        base.ExtendModelInterfaces(extenders);

        extenders.Add<IModelOptions, IModelMyOptions>();

    }

}

Imports DevExpress.ExpressApp.Model

 

Public Interface IModelMyOptions

    Property OperatingMode() As String

End Interface

Public NotInheritable Partial Class MyModule

    Inherits ModuleBase

    '...

    Public Overrides Sub ExtendModelInterfaces(ByVal extenders As ModelInterfaceExtenders)

        MyBase.ExtendModelInterfaces(extenders)

        extenders.Add(Of IModelOptions, IModelMyOptions)()

    End Sub

End Class

 

Users of your application customize this property value and it is stored to their Application Model differences. Then, the module is updated to a new version which introduces a couple of changes. First, the OperatingMode property type is changed to a newly introduced enumeration. Second, string representations of the new enumeration values are different from the previously used string values:

应用程序的用户自定义这个属性值并存储到他们的应用程序模型差异。接着,模块更新到新版本改动。首先,OperatingMode属性类型更改为新进的枚举。第二,新的枚举字符串值不同于之前用的字符串值:

C#

 

VB

 

public interface IModelMyOptions {

    OperatingMode OperatingMode { get; set; }

}

public enum OperatingMode { Basic, Advanced }

Public Interface IModelMyOptions

    Property OperatingMode() As OperatingMode

End Interface

Public Enum OperatingMode

    Basic

    Advanced

End Enum

 

If you now recompile the application with the updated module and redistribute it, existing users will not be able to use the application. At the application start, a message will be displayed stating that an error has occurred while loading the Application Model differences. To avoid this, an XML converter should be implemented in the module. The following code snippet illustrates a possible solution:

如果你用更新模块重新编辑应用程序并重新发布,已有的用户将不能用这个应用程序。在应用程序启动时,将显示一个信息,指出有错误发生,在加载应用程序模型差异。为了避免这个错误提示,应当在模块中实现一个XML转换器。下面代码说明一个可能的解决方案:

C#

 

VB

 

using DevExpress.ExpressApp.Model;

using DevExpress.ExpressApp.Updating;

 

public sealed partial class MyModule : ModuleBase, IModelXmlConverter {

    //...

    public void ConvertXml(ConvertXmlParameters parameters) {

        if(typeof(IModelOptions).IsAssignableFrom(parameters.NodeType)) {

            string property = "OperatingMode";

            if(parameters.ContainsKey(property)) {

                string value = parameters.Values[property];

                if(!Enum.IsDefined(typeof(OperatingMode), value)) {

                    switch(value.ToLower()) {

                        case "complex":

                            parameters.Values[property] = OperatingMode.Advanced.ToString();

                            break;

                        default:

                            parameters.Values[property] = OperatingMode.Basic.ToString();

                            break;                           

                    }                                 

                }                   

            }

        }

    }

}

Imports DevExpress.ExpressApp.Model

Imports DevExpress.ExpressApp.Updating

 

Public NotInheritable Partial Class MyModule

    Inherits ModuleBase

    Implements IModelXmlConverter

    '...

    Public Sub ConvertXml(ByVal parameters As ConvertXmlParameters)

        If GetType(IModelOptions).IsAssignableFrom(parameters.NodeType) Then

            Dim [property] As String = "OperatingMode"

            If parameters.ContainsKey([property]) Then

                Dim value As String = parameters.Values([property])

                If (Not System.Enum.IsDefined(GetType(OperatingMode), value)) Then

                    Select Case value.ToLower()

                        Case "complex"

                            parameters.Values([property]) = OperatingMode.Advanced.ToString()

                        Case Else

                            parameters.Values([property]) = OperatingMode.Basic.ToString()

                    End Select

                End If

            End If

        End If

    End Sub

End Class

 

The converter checks whether the currently processed node is the Options node. If it is, the converter checks whether the OperatingMode property has a legacy value. Then, the "Complex" value becomes OperatingMode.Advanced and all other values become OperatingMode.Basic.

这个转换器检查当前处理的节点是否是选项节点。如果是,他将检查OperatingMode是否有值。接着,"Complex"值变为OperatingMode.Advanced 并且其他值变为OperatingMode.Basic

Now, consider another very common scenario when a node's property is renamed. Suppose, a Mode property declared in the Options node was renamed to OperatingMode. The following code snippet illustrates a possible XML converter:

现在,考虑另一种常用的情况,重命名一个节点的属性。假设,重命名一个定义在选项节点中模型属性。下面代码说明一个可能的XML转换器:

C#

 

VB

 

using DevExpress.ExpressApp.Model;

using DevExpress.ExpressApp.Updating;

 

public sealed partial class MyModule : ModuleBase, IModelXmlConverter {

    //...

    public void ConvertXml(ConvertXmlParameters parameters) {

        if(typeof(IModelOptions).IsAssignableFrom(parameters.NodeType)) {

            string oldProperty = "Mode";

            string newProperty = "OperatingMode";

            if(parameters.ContainsKey(oldProperty)) {

                parameters.Values[newProperty] = parameters.Values[oldProperty];

                parameters.Values.Remove(oldProperty);

            }

        }

    }

}

Imports DevExpress.ExpressApp.Model

Imports DevExpress.ExpressApp.Updating

 

Public NotInheritable Partial Class MyModule

    Inherits ModuleBase

    Implements IModelXmlConverter

    '...

    Public Sub ConvertXml(ByVal parameters As ConvertXmlParameters)

        If GetType(IModelOptions).IsAssignableFrom(parameters.NodeType) Then

            Dim oldProperty As String = "Mode"

            Dim newProperty As String = "OperatingMode"

            If parameters.ContainsKey(oldProperty) Then

                parameters.Values(newProperty) = parameters.Values(oldProperty)

                parameters.Values.Remove(oldProperty)

            End If

        End If

    End Sub

End Class

Private < Mod Cod

 

As illustrated by the examples, an XML converter works with one node at a time. So, complex conversions, affecting several nodes at once, are not possible. In these cases, special updaters implementing the IModelNodeUpdater<T> interface should be used.

用例子说明,一个XML转换器一次由一个节点工作。接着,复杂的转换,不可能一次影响几个节点。在这种情况下,应当用指定的更新器实现IModelNodeUpdater<T>接口。

Implement a Node Updater(属性一个节点更新器)

A node updater is represented by a class implementing the IModelNodeUpdater<T> interface. The generic type parameter specifies the type of the nodes for which the updater is intended. The interface declares a single IModelNodeUpdater<T>.UpdateNode method, which takes two parameters. The first parameter is the Application Model node in process, represented by an object implementing the IModelNode interface. The second parameter is the application's Application Model, represented by an object, implementing the IModelApplication interface. Since you have access to the whole Application Model, complex conversions affecting multiple nodes can be performed. Consider the following example.

一个节点更新器表示一个类实现IModelNodeUpdater<T>接口。更新者的目的是泛型参数类型指定节点的类型。该接口定义一个IModelNodeUpdater<T>.UpdateNode方法,有两个参数。第一个参数是应用程序模型节点在处理过程中。表示一个对象实现了IModelNode接口。第二个参数是应用程序的应用程序模型,由一个对象实现IModelApplication接口。既然你已经访问整个应用程序模型,执行影响多个节点的复杂转换。看下面例子。

Suppose your application uses a module which adds an OperatingMode string property to the Application Model's Options node. Originally, the interface extending the Application Model looks like this:

假设你用了一个应用程序给应用程序模型的选项节点添加一个字符串属性OperatingMode模块,最初,接口扩展应用程序模型如下:

C#

 

VB

 

public interface IModelMyOptions {

    OperatingMode OperatingMode { get; set; }

}

public enum OperatingMode { Basic, Advanced }

Public Interface IModelMyOptions

    Property OperatingMode() As OperatingMode

End Interface

Public Enum OperatingMode

    Basic

    Advanced

End Enum

 

Then, the module is updated to a new version which moves the property to a newly introduced child node:

然后,模组更新到一个新的版本,移动到新推出的子节点的属性:

C#

 

VB

 

using DevExpress.ExpressApp.Model;

 

public interface IModelMyOptions {

    IModelChildOptions ChildOptions { get; }

}

public interface IModelChildOptions : IModelNode {

    OperatingMode OperatingMode { get; set; }

}

public enum OperatingMode { Basic, Advanced }

Imports DevExpress.ExpressApp.Model

 

Public Interface IModelMyOptions

    ReadOnly Property ChildOptions() As IModelChildOptions

End Interface

Public Interface IModelChildOptions

    Inherits IModelNode

    Property OperatingMode() As OperatingMode

End Interface

Public Enum OperatingMode

    Basic

    Advanced

End Enum

 

 If you now recompile the application with the updated module and redistribute it, the original OperatingMode property values specified by users of the application will be lost. To avoid this, a node updater should be implemented. A possible place for the implementation is the updated module:

如果你用更新模块重新编辑应用程序并重新发布,已有的用户将不能用这个应用程序。原来OperatingMode所指定的属性值将会丢失应用程序的用户。为了避免这种情况,应当实现一个节点更新器。更新模块可能用一下方法实现。

 

C#

 

VB

 

using DevExpress.ExpressApp.Model;

using DevExpress.ExpressApp.Model.Core;

 

public sealed partial class MyModule : ModuleBase, IModelNodeUpdater<IModelOptions> {

    //...

    public void UpdateNode(IModelOptions node, IModelApplication application) {

        string myProperty = "OperatingMode";

        if(node.HasValue(myProperty)) {

            string value = node.GetValue<string>(myProperty);

            node.ClearValue(myProperty);

            ((IModelMyOptions)node).ChildOptions.OperatingMode =

                (OperatingMode)Enum.Parse(typeof(OperatingMode), value);

        }

    }       

}

Imports DevExpress.ExpressApp.Model

Imports DevExpress.ExpressApp.Model.Core

 

Public NotInheritable Partial Class MyModule

    Inherits ModuleBase

    Implements IModelNodeUpdater(Of IModelOptions)

    '...

    Public Sub UpdateNode(ByVal node As IModelOptions, ByVal application As IModelApplication)

        Dim myProperty As String = "OperatingMode"

        If node.HasValue(myProperty) Then

            Dim value As String = node.GetValue(Of String)(myProperty)

            node.ClearValue(myProperty)

            CType(node, IModelMyOptions).ChildOptions.OperatingMode = _

            CType(System.Enum.Parse(GetType(OperatingMode), value), OperatingMode)

        End If

    End Sub

End Class

 

The updater in the example checks whether the currently processed node has a legacy OperatingMode property value. If there is such a value, it is assigned to the new OperatingMode property, and the legacy property value is cleared.

 在实例中检查是否当前处理节点有一个OperatingMode属性值。如果有值,它被标识为新的OperatingMode属性并清除之前的值。

Note that since a node updater can be implemented anywhere in the application, the updater should be registered via the ModuleBase.AddModelNodeUpdaters method:

注意,一个节点的更新可以在任何应用程序实现,这个更新者应该通过ModuleBase.AddModelNodeUpdaters方法注册:

C#

 

VB

 

using DevExpress.ExpressApp.Model;

using DevExpress.ExpressApp.Model.Core;

 

public sealed partial class MyModule : ModuleBase, IModelNodeUpdater<IModelOptions> {

    //...

    public override void AddModelNodeUpdaters(IModelNodeUpdaterRegistrator updaterRegistrator) {

        base.AddModelNodeUpdaters(updaterRegistrator);

        updaterRegistrator.AddUpdater<IModelOptions>(this);

    }   

}Imports DevExpress.ExpressApp.Model

Imports DevExpress.ExpressApp.Model.Core

 

Public NotInheritable Partial Class MyModule

    Inherits ModuleBase

    Implements IModelNodeUpdater(Of IModelOptions)

    '...

    Public Overrides Sub AddModelNodeUpdaters( _

    ByVal updaterRegistrator As IModelNodeUpdaterRegistrator)

        MyBase.AddModelNodeUpdaters(updaterRegistrator)

        updaterRegistrator.AddUpdater(Of IModelOptions)(Me)

    End Sub

End Class

 

 欢迎转载,转载请注明出处:http://www.cnblogs.com/Tonyyang/

原文地址:https://www.cnblogs.com/Tonyyang/p/1934186.html