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.

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.

 

 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 = 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.

 

 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 = 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);
}
}

Convert Application Model Differences的更多相关文章

  1. Core - Provide an easy way to store administrator and user model differences in a custom store (e.g., in a database)

    https://www.devexpress.com/Support/Center/Question/Details/S32444/core-provide-an-easy-way-to-store- ...

  2. Implement Property Value Validation in the Application Model 在应用程序模型中实现属性值验证

    In this lesson, you will learn how to check whether or not a property value satisfies a particular r ...

  3. How to map Actions to a certain RibbonPage and RibbonGroup using the Application Model or in code

    https://www.devexpress.com/Support/Center/Question/Details/S134617/how-to-map-actions-to-a-certain-r ...

  4. Windows Forms Application Creation and Initialization

    Windows Forms Application Creation and Initialization This topic details the steps performed after a ...

  5. ASP.NET Application Life Cycle

    The table in this topic details the steps performed while an XAF ASP.NET application is running. Not ...

  6. Unit Testing a zend-mvc application

    Unit Testing a zend-mvc application A solid unit test suite is essential for ongoing development in ...

  7. 【转载】Using the Web Service Callbacks in the .NET Application

    来源 This article describes a .NET Application model driven by the Web Services using the Virtual Web ...

  8. TensorFlow Lite demo——就是为嵌入式设备而存在的,底层调用NDK神经网络API,注意其使用的tf model需要转换下,同时提供java和C++ API,无法使用tflite的见后

    Introduction to TensorFlow Lite TensorFlow Lite is TensorFlow’s lightweight solution for mobile and ...

  9. [AngularJS] 5 simple ways to speed up your AngularJS application

    Nowdays, Single page apps are becoming increasingly popular among the fornt-end developers. It is th ...

随机推荐

  1. IntelliJ IDEA2017/2018 激活方法 破解补丁激活(亲测可用)(注册码方法以和谐)

    IntelliJ IDEA2017 激活方法(注册码方法以和谐): 搭建自己的授权服务器,对大佬来说也很简单,我作为菜鸟就不说了,网上有教程. 我主要说第二种,现在,直接写入注册码,是不能成功激活的( ...

  2. n=n+1 放在print(s)的上面的影响 (2) n=n=+1在前面,则不满足前面<100条件时候,才跳出while的循环,这时候while循环结束, 到了外面的下一步-->print()

    1+2+3+....+100=     ? n=1 s = 0 while n < =100: s = s+n n= n+1 # n=n+1    在print(s)上面的情况 print(s)

  3. django中session的存储位置

    django-session 存放位置 设置session的保存位置,有三种方法: 保存在关系数据库(db) 保存在缓存数据库(cache) 或者 关系+缓存数据库(cache_db) 保存在文件系统 ...

  4. 【ASP.NET】#001 获取服务器IP

    客户端ip: Request.ServerVariables.Get("Remote_Addr").ToString(); 客户端主机名: Request.ServerVariab ...

  5. nodejs11安装教程(升级最新版本)

    nodejs需要不断升级,那么电脑如何安装nodejs11呢,下面将通过亲身实践来详细介绍   工具/原料   电脑 nodejs11安装包 方法/步骤     访问node11官网,下载安装包,如下 ...

  6. cocos2d-x(十一)Lua开发飞机大战-6-加入子弹

    接下来我们为飞机加入子弹,首先创建一个BulletLayer: module("BulletLayer",package.seeall) local bulletBatchNode ...

  7. P1439 【模板】最长公共子序列

    题目描述 给出1-n的两个排列P1和P2,求它们的最长公共子序列. 输入输出格式 输入格式: 第一行是一个数n, 接下来两行,每行为n个数,为自然数1-n的一个排列. 输出格式: 一个数,即最长公共子 ...

  8. Hadoop学习之路(二)Hadoop发展背景

    Hadoop产生的背景 1. HADOOP最早起源于Nutch.Nutch的设计目标是构建一个大型的全网搜索引擎,包括网页抓取.索引.查询等功能,但随着抓取网页数量的增加,遇到了严重的可扩展性问题—— ...

  9. Day2 数据类型和运算符

    基本数据类型 Java 是一种强类型的语言,声明变量时必须指明数据类型.变量(variable)的值占据一定的内存空间.不同类型的变量占据不同的大小.Java中共有8种基本数据类型,包括4 种整型.2 ...

  10. MySQL无法存储Emoji表情问题

    数据插入的时候报错: 1366 - Incorrect string value: '\xF0\x9F\x98\x81' for column 'job' at row 23 解决办法: 1.修改配置 ...