Convert Application Model Differences

历览千载书,时时见遗烈。这篇文章主要讲述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 Frameworkprovides easy ways to implement such converters. This topic describes them.
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.
  2. For complex conversion scenarios, special updaters implementing the  IModelNodeUpdater< T>   interface should be used. Such updaters can perform much more versatile conversions.
【Convert Application Model Differences】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.
 
Convert Application Model Differences

文章图片
  Implement an XML converter    
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.
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:
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> (); } }

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:
C# VB  
public  interface IModelMyOptions { OperatingMode OperatingMode { get; set; } } public  enum OperatingMode { Basic, Advanced }

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:
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 = https://www.songbingjia.com/android/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; } } } } } }

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.
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:
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); } } } }

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.
 
 
Convert Application Model Differences

文章图片
  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.
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:
C# VB  
public  interface IModelMyOptions { OperatingMode OperatingMode { get; set; } } public  enum OperatingMode { Basic, Advanced }

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 }

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:
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 = https://www.songbingjia.com/android/node.GetValue< string> (myProperty); node.ClearValue(myProperty); ((IModelMyOptions)node).ChildOptions.OperatingMode = (OperatingMode)Enum.Parse(typeof(OperatingMode), value); } } }

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.
Note that since a node updater can be implemented anywhere in the application, the updater should be registered via the  ModuleBase.AddModelNodeUpdaters  method:
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); } }


    推荐阅读