Dorado 5 : 3.1.ViewModel方法使用详解 (T32)

ViewModel服务端事件使用详解

下面对这个类里面每个方法进行解析一下(引自《dorado 5 用户指南》):

方法

说明

void init(int state)

ViewModel的初始化方法。参数为ViewModel当前的状态。

void initDatasets()

ViewModel的初始化其中的各个Dataset的方法。如前面关于ViewModel状态的文字所述,究竟有那些Dataset会在该方法中被初始化是取决于ViewModel的当前状态的。

void initControls()

ViewModel的初始化其中所有的不可视控件的方法。不可视控件包括下拉框、菜单、命令。其他的可视控件默认是不会在此处初始化的,它们甚至还没有被创建。可视控件默认都是"懒创建"的,只有当将来JSP的Taglib真正引用到它或者用户利用ViewModel的getControl(id)方法获取它时才会被创建起来。

void initControl(Control control)

此方法会在initControls()的执行过程中以及JSP的执行过程中,针对每一个创建出来的控件被激发。

void doLoadData()

当ViewModel开始为其中的Dataset装载数据时调用的方法。只有在initDatasets()中已被初始化的Dataset才会在此处装载数据,因此究竟有那些Dataset会被处理是取决于ViewModel的当前状态的。

void doLoadData(ViewDataset dataset)

此方法会在doLoadData()的执行过程中针对每一个要处理的Dataset被激发。如果doLoadData()中需处理3个Dataset,那么doLoadData(ViewDataset dataset)也将被调用3次。

void doUpdateData(ParameterSet parameters, ParameterSet outParameters)

默认的数据提交的处理方法。

以上方法不是在所有情况都会被执行的。
在页面打开时的处理过程是这样的。此时ViewModel的state为STATE_VIEW。
void init(int state)
void initDatasets() 初始化ViewModel中所有的Dataset。
void doLoadData()
void doLoadData(ViewDataset dataset)
void initControls()
void initControl(Control control)
执行Dataset动态数据刷新时的过程是这样。此时ViewModel的state为STATE_SERVICE。
void init(int state)
void initDatasets() 仅初始化当前执行数据加载动作的这一个Dataset。
void doLoadData()
void doLoadData(ViewDataset dataset)
执行数据提交时的过程是这样的。此时ViewModel的state为STATE_SERVICE。
void init(int state)
void initDatasets() 仅初始化被提交上来的Dataset。
void doUpdateData(ParameterSet parameters, ParameterSet outParameters)
由此,在使用ViewModel实现类时应注意下面的一些事项。
最好不要将自定义的初始化Dataset或Control的代码写在init()中,因为init()会在ViewModel的每一种状态下被执行。例如你在init()中写了一段自动为DataTable创建表格列的代码,那么当界面上某个Dataset执行flushData()时,这段代码同样会被执行,这毫无意义的。正确的做法是写在initControls()或者initControl()中。由Dorado来帮你判断这段代码应在什么时候执行。
事实上,在实际应用中init()应该是一个很少被用到的方法。有时我们可能会在这里做一些权限的校验,判断当前登录用户是否有权访问这个ViewModel。再比如可以在这里指定ViewModel的role属性。
同样是这面提到的这端代码,写在initControl()中往往优于写在initControls()中。因为在initControls()中你必须通过getControl()方法才能得到你所需要的DataTable对象,而getControl()会强制Dorado创建这个DataTable对象,这会打破该对象的"懒创建"机制。对于一个只在ViewModel的XML中定义过但并没有在JSP中引用的对象,在默认情况下Dorado是根本不会创建它的,而getControl()会强制Dorado去创建它。
对于Dataset同样适用上面的规则。手工处理Dataset的数据加载过程时,相关的代码写在doLoadData(ViewDataset dataset)要优于doLoadData()中。在initDatasets()或doLoadData()必须利用getDataset()方法来获取某个Dataset,这会导致一些本不需要创建的Dataset被强制的创建。例如:在执行Dataset的flushData()的过程中,ViewModel中应该只有一个Dataset被创建。多创建几个Dataset有时并不是什么大的系统开销,但是多余的Dataset会引起多余的数据装载过程(如执行SQL),这是相当昂贵的操作。
其实对于针对某个Dataset的特别操作,像利用Java代码动态的为Dataset创建Field或者设定其他参数等。我们更加推荐把代码写在Dataset的Listener中,而不是前面提到的doLoadData(ViewDataset dataset)中。因为在doLoadData(ViewDataset dataset)必须判断ID来确定当前传入的是否我们所关心的那个Dataset,这有时会让代码显得有些混乱。
ViewModel方法的使用:

    1. init

super.init(state)方法里面是先对ViewModel对应的view.xml里view节点下的内容做初始化;初始化ViewModel对应的角色配置文件;初始化view.xml里的Datasets和Controls,当中根据state的状态还执行initDataset(dataset);执行initDatasets();根据state的状态执行initControls()和view的事件代码。
根据super.init(state) 方法里面的实现内容,那我们在init方法里就可以实现我们对view的一些动态设置或者对view处理的业务逻辑。比如要根据state的状态才能super.init(state),也就是说我要保证这个页面在某些状态才能使用view.xml的配置内容。比如我们要通过java代码来创建新的Datasets,那我们一般会在super.init(state)之前来创建,这样才能在initDataset(dataset)和initDatasets()得到新创建的Dataset来做Dataset的初始化。Controls的创建一般会在super.init(state)之后。

    1. initDataset和initDatasets

initDataset是Dataset创建的时候触发的。initDataset(dataset)方法之前ViewModel对该dataset执行了Dataset.init()动作,把该Dataset在view.xml里的定义设置属性给该dataset。想在Dataset.init()之前对该dataset设置一些属性只能在super.init(state)之前做;在initDataset(dataset)方法里面设置属性就可以改变Dataset.init()时的属性,做到动态改变dataset的属性。
根据view.xml创建Datasets或者在super.init(state)前创建的Datasets,这些Datasets做完所有initDataset(dataset)之后执行initDatasets,在这里所有的dataset已经init好,我们就可以做一些dataset之间的逻辑判断之类的代码。

    1. initControl和initControls

这里跟initDataset和initDatasets是一样的。

    1. doLoadData

super.doLoadData()的方法里面通过查找所有的Dataset来做doLoadData(dataset),在super.doLoadData(dataset)里执行dataset.load()来查询数据。所以在super.doLoadData()之前还可以对所有dataset改变属性设置等,在super.doLoadData(dataset)之前可以根据判断来要不要执行super.doLoadData(dataset)。dataset.load()里执行了datasetListeners的一些方法,这个会在Dataset的章节说到。

    1. doUpdateData

如果在UpdateCommand里没有定义method属性,那该UpdateCommand会默认到doUpdateData方法里面处理。doUpdateData方法里面通过查找所有在该UpdateCommand里需要提交的Dataset来做dataset.update(),在dataset.update里执行了datasetListeners的一些方法,这个会在Dataset的章节说到。
在UpdateCommand里自定义了method属性,在这个method方法里直接super.doUpdateData(parameters, outParameters),这个跟没有定义method属性是一样的。在这里可以对该UpdateCommand做个判断来要不要执行super.doUpdateData(parameters, outParameters)。
通过UpdateCommand提交的时候,调用的method方法应该在最后调用一下super.doUpdateData(parameters, outParameters),这样才确保数据返回客户端的时候状态和数据内容保持一致。

ViewModel客户端事件使用详解

我们先来了解一下Dorado页面的初始化过程(下面内容出自《Dorado5性能指南》):

  1. 页面下载完成。
  2. 创建所有的Dataset。
  3. 触发onDatasetsPrepared事件。
  4. 创建所有非可视化控件(DropDown、Menu、Command)。
  5. 创建必须的可视化控件。建立其中的数据控件与Dataset的绑定关系。
  6. 所有的Dataset向绑定的数据敏感控件发出数据刷新的消息,数据敏感控件显示出数据。
  7. 触发onLoad事件。

 

  1. onDatasetsPrepared

初始化Dataset数据的代码放在onDatasetsPrepared事件中将会获得更高的效率。
从Dorado页面的初始化过程可见,当执行到第6个步骤时数据敏感控件事实上已经就绪。如果您在onLoad事件中对Dataset总的数据做了修改,那么Dataset将不得不重新向绑定的数据敏感控件发送数据被更新的消息,导致数据敏感控件发生更新动作。而如果这些代码是写在onDatasetsPrepared事件中的,那么你对数据的修改将在第6个步骤中被一并处理,每一个敏感控件只需要刷新一次数据。
当我们需要编写在页面加载时自动执行的代码时,应该首先考虑使用onDatasetsPrepared事件。但是,onDatasetsPrepared事件并不能完全替代onLoad事件,主要原因是在系统触发onDatasetsPrepared事件时ViewModel中的控件还没有被创建出来,如果您的逻辑代码中包含控件的直接操作,那么这一部分代码将只能写在onLoad事件中。有时,我们需要同时使用这两个事件,在onDatasetsPrepared事件中初始化Dataset,在onLoad事件中处理控件。

  1. onLoad

这里写一些页面onLoad的javascript代码,与页面控件或者页面展现相关的逻辑代码等等。

  1. onUnload

当页面关闭时触发的事件,一般我们会用来判断页面是否还有数据没提交,或者在这里调用RPCCommand来后台处理离开页面的操作。
下面是通过ViewModel的onUnload事件来提醒用户还有数据没提交,是否提交再离开页面:

if(commandUpdate.isDirty()){ 
	if(confirm("还有数据未保存,你现在需要保存吗?")){ 
		commandUpdate.execute(); 
	} 
}