XAF之深入了解Application Model
XAF之深入了解Application Model
一.鸟瞰Application Model
XAF的两大特色是1.自动生成UI;2.使用相同的业务逻辑产生不同平台的程序,而这两大特色都归功于Application Model才能完成。首先,XAF扫描程序代码,提取声明的类做出分析后创建数据结构和用户接口。扫描分析的结果是创建中性的数据格式,使用该格式定义数据库结构和程序特性,才能跨平台地读取使用。这个中性格式的元数据就是Application Model,实际上Application Model就是使用XML语言写成的文本,自然能够很方便地分享和更改,所以就为XAF程序提供了极大的自定义自由度。可以在设计时利用它修改程序配置(设置),也可以在运行时修改。由于Application Model是用XML书写的,使用简单的文本编辑器就能够对程序做出更改,但XAF提供了模块编辑器Model Editor能够很方便地修改Application Model,如图1所示。当然,也可以在代码中修改,这也是本文探讨修改Application Model的主要方式。

图1 Application Model Editor
Application Model将信息组织成树形结构,如图2所示。根节点是Application,根节点下有许多子节点,如图2中的ActionDesign, BOModel, CreatableItem, ImageSource, NavigationItems, ViewItems, View等等,每一个树中的节点都拥有一系列的属性,它们决定特定程序元素的特性。如果要对某类程序元素做出配置,则到对应节点下设置即可,如要配置导航栏,则展开NavigationItems节点,在其中做出适当的配置即可。

图2 Application Model(树形结构)
下面简单介绍几个二级节点,如图3所示。

图3 Application Model主要节点
1.ActionDesign
该节点下存放了程序中所有的Action的相关信息,其下的Actions节点存放了程序中所有Controller的包含的Action的定义,ActionToContainerMapping节点下是所有ActionContainer的信息,而Controllers节点下记录了所有的WindowController和ViewController,还有DisableReasons下存在了一些已声明的禁用某些UI元素的原因。
2.BOModel
该节点下存放了所有的业务对象模型,包括XAF自带的XPO对象河我们自己定义的XPO对象。
3.NavigationItems
该节点下存放了导航栏的项,通过对它进行设置可以改变导航栏的行为,该节点下的子节点可包含更多子节点,包含子节点的为导航分组,不包含的为导航项。
4.ViewItems
该节点下存放了详细视图的UI元素,如PropertyEditors。
5.Views
该节点下存放了程序中全部视图,主要包括所有XPO对象的ListView, DetailView, LookupListView,以及DashboardView视图(图3中没有)。
由此可见,Application Model包含了程序运行的大部分配置。经典的MVC架构的元素在这里都体现出来了,而据XAF开发团队的开发人员说,他们的确是读了MVC的基本经典著作后谋划开发的XAF,所以理解MVC架构的开发者应该很容易掌握XAF,不像我摸索地这么久,当然,这是题外话了。好了,既然XAF的配置信息都放在Application Model里了,那XAF程序是怎样使用Application Model来配置程序特性的呢,那就先要理解Application Model的分层结构了。
二. Application Model的层次结构
在程序中不同地方自定义Application Model时,要能够意识到Model产生的顺序,即图4所示的层级结构。

图4 Application Model的层次结构
- 在最底层是Application Model的零层。该层是基于程序引用的模块的代码自动产生的。
- 在零层上,是XAF程序的各个模块,以各模块的 Xafml文件为代表。除此之外,若在程序项目中有其他引用模块的Xafml文件,它们也会生成对应的层。这些层的生成依据了它们的依赖关系。
- 然后是程序工程即application's project的Xafml文件生成的层。
- 在最顶部的是终端用户自定义后生成的层,它存储在WinForm程序的Model.User.xafml文件中或ASP.NET程序的浏览器cookies中。
- 最后,还有一层叫做管理层(master layer)。它自身并不包含任何信息,它仅充当一个其他层的代理,实际上,当访问Application Model时,是和管理层在打交道。
| Object | Property |
| View | View.Model |
| ActionBase | ActionBase.Model |
| PropertyEditor | PropertyEditor.Model |
| XafApplication | XafApplication.Model |




private void WindowController1_Activated(object sender, EventArgs e)
{
Application.Model.Title = "change model from code";
IModelAction aboutAction =(IModelAction) Application.Model.ActionDesign.Actions.GetNode("About Info");
aboutAction.Caption = "Information";
//ActionDesign并不直接提供ActionToContainerMapping成员,故需
//按上述方法查看其接口类型,强制转换得到IModelActionToContainerMapping
IModelActionToContainerMapping actionToContainer = (IModelActionToContainerMapping)Application.Model.ActionDesign.GetNode("ActionToContainerMapping");
IModelActionContainer tools = (IModelActionContainer)actionToContainer.GetNode("Tools");
foreach (IModelActionContainer container in actionToContainer.GetNodes<IModelActionContainer>())
{
Console.WriteLine("ActionContainer Id:{0}", container.Id);
}
}
运行结果如图7 所示。
ActionContainer Id:File
ActionContainer Id:Save
...................................................
ActionContainer Id:Menu
ActionContainer Id:Windows

IModelListView listView = View.Model as IModelListView;
IModelListViewFilters filters = (IModelListViewFilters)listView.GetNode("Filters");
IModelListViewFilterItem filter1 = filters.AddNode<IModelListViewFilterItem>("all");
filter1.Caption = "All";
filter1.Criteria = null;
IModelListViewFilterItem filter2 = filters.AddNode<IModelListViewFilterItem>("filter2");
filter2.Caption = "Greater than 100";
filter2.Criteria = "[Number] > 100";
filters.CurrentFilter = filter1;
View.SetModel(listView);
另外,这里顺便说一点。在Application Model中添加的是UI级别的过滤,即所有的数据是在加载到了程序会话后再过滤的。若要加载大量数据,除了启用ServerMode外,建议在ViewController的Actived事件中将过滤器CriteriaOperator添加到ListView.CollectionSource.Criteria字典中,这样才能避免程序假死。还有,在更改了View的Model后要使用View.SetModel方法重新加载Model才会使更改生效,否则只有关掉程序,下次再运行才能看到效果。而调用SetModel方法会自动调用SaveModel和 LoadModel方法。View.SaveModel将model的新配置信息保存,而View.LoadModel则从Application Model重新加载配置,更新AllowEdit, AllowNew 等等属性后,还会根据新的Model信息重建View的Control,这意味着View可能会像刚打开一样,比如之前选中的ListView某记录变成选中ListView第一条记录,某些空间的事件需要重新订阅等等。所以,若非必要,不要在代码中对Application Model尤其是Views节点做过多更改,这在使用DashboardView时体现得尤其重要。若必须要在代码中更改DashboardView的某些行为,可以尝试使用DashboardView子View在内存中的对象,对他们做出的更改会立即生效,不需要重新加载Model。

浙公网安备 33010602011771号