分类:
2010-05-15 17:37:59
最后更新日期:2010年7月22日
由于parsley可以在配置文件内定义托管对象,包括视图元素。对于FLEX应用程序,这种方法并不理想,因为你可能想在你的MXML文件的组件中声明你的组件,而不是parsley配置文件中声明组件。因此,你需要一个机制将parsley配置文件内的对象与MXML文件中的组件联系起来。
parsley在本章提供了使用案例。
用MXML标签初始化上下文
在FLEX应用程序中,你可以使用ContextBuilder
标签(version 2.2版本引入)。这将用自动在视图根上使用文档对象(document object)。
你自己想直接指定视图根的情况很罕见,可以如下配置:
viewRoot="{someOtherDisplayObject}"/>
上下文编码初始化
如果你通过程序初始化框架,视图根必须描述:
XML配置(XML configuration)
var viewRoot:DisplayObject = ...;
XmlContextBuilder.build("bookStoreConfig.xml", viewRoot);
多个配置机制
var viewRoot:DisplayObject = ...;
var builder:CompositeContextBuilder = new DefaultCompositeContextBuilder(viewRoot);
FlexContextBuilder.merge(BookStoreConfig, builder);
XmlContextBuilder.merge("logging.xml", builder);
builder.build();
如果你想将一个组件直接注入到组件自身所在的上下文中,你可以有二个选择。第一,你可以使用
xmlns:mx=""
xmlns:parsley="">
在FLEX4中,这将需要使用
xmlns:mx=""
xmlns:parsley=""
xmlns:view="myproject.view.*">
target="{model}" />
本例中,我们声明一个表示层model,并将这个model注入到上下文中。万一视图组件自身不是由parsley容器管理,你就不能在该视图组件内设置任何parsley元标签。这个model主要用于性能优化。参见下一节的第二部分将重点谈谈如何避免大型组件类的过多反射.
在flash应用程序中注入
在flash应用程序中,本章的注入方式并不能用。没有MXML去定义视图,我们经常直接在XML配置文件或actionscript配置文件中声明与视图相关的对象。因此,这里并不需要明确描述如何注入他们。
万一你不想在上下文中定义视图,而是想使用动态注入上下文方式,这样你就能派发一个事件,就歇脚在FLEX中使用了
var viewRoot:DisplayObject = ...;
ActionScriptContextBuilder.build(MyConfig, viewRoot);
这样,每个在视图根中描述的DisplayObject 对象,当它被添加到stage中,就可以派发一个注入的事件。
public class MyView extends Sprite {
function MyView () {
addEventListener(Event.ADDED_TO_STAGE, configure);
}
private function configure () : void {
dispatchEvent(new Event("configureView", true));
}
/* ... */
}
Parsley对所有管理对象和组件反射操作代价很大,主要是由于其属性、方法和事件太多。一个组件可能花费30毫秒。parsley维护一个内部反射缓存,如果你使用了大多的不同组件,缓存的意义就不大了。一个小的应用程序,这种花费很少,但是对于大型系统,就要重点关注了。本节内容通过一些案例让你避免性能大幅下降。
为了允许性能优化,Parsley 2.2引入标签FastInject:
xmlns:mx=""
xmlns:parsley=""
xmlns:view="myproject.view.*">
import com.bookstore.model.MyPanelPM;
public var model:MyPanelPM;
]]>
这有点类似与
FastInject标签也允许通过子标签定义多个注入:
如果你想执行所有的注入的话,必须将它们合并为单一的父标签。如果你使用独立的标签,你需要手动检查哪些已经注入已处理。在上面的例子可以保证,只有所有的注入都执行后,init方法只会被调用。
自Version2.2后,你还可以通过自动视图注入,避免为单个组件类添加具体配置。但是parsley存在多上下文环境,自动注入会导致不知道哪些上下文中。目前只能基于他们所处的视图层次的位置。一个组件被注入到最接近的上下文中。
因为这个功能很新,没有严格测试,因此,必须注意parsley的版本号:
MXML
ActionScript
GlobalFactoryRegistry.instance.viewManager.autowireFilter.enabled = true;
在第一个上下文创建之前,上一行语句必须执行。正如你所期望的,autowireFilter可是选 的。你可以实现自己的选择逻辑,告诉框架哪个组件应该注入。默认仅注入MXML或XML文件中
这里简单的展示了视图定和相关视图模型。仅仅这里的视图将注入到上下文中。本例中,我们还使用了空视图标签,你也可以象对象标签一样隐藏标签,参见
你也可以实现你自定义的autowire过滤器,最简单的方式是继承DefaultViewAutowireFilter
并覆盖filter方法:
public class MyAutowireFilter extends DefaultViewAutowireFilter {
public override function filter (view:DisplayObject) : ViewAutowireMode {
if (... someCondition ...) {
return ViewAutowireMode.ALWAYS;
}
else {
return ViewAutowireMode.NEVER;
}
}
}
最终,使用filter如下所示:
GlobalFactoryRegistry.instance.viewManager.autowireFilter = new MyAutowireFilter();
大多数情况下,元数据是够用的,组件上的元数据标签与容器创建的对象具有相同的效果。
xmlns:mx=""
addedToStage="dispatchEvent(new Event('configureView', true));">
import com.bookstore.events.*;
import com.bookstore.model.*;
[Bindable]
private var user:User;
[Inject]
public var model:LoginPanelPM;
[MessageHandler]
public function handleLogin (event:LoginEvent) : void {
this.user = event.user;
}
]]>
一些开发人员要避免添加过多的逻辑到组件中。大部分情况下,在组件的表示模型类上使用parsley标签[Inject]封装所有的逻辑和数据。
自Version2.2,你可以在MXML或XML上配置视图。在两种情况下会很方便:一、你可以在不同的脚本中使用相同的组件类;二、你可能想使用配置机制去描述如同演示的自动注入。
这个功能已用在了Flicc中,当它被注入到上下文中,容器将配置信息作用到视图上。作用于注入组件的配置信息将根据ID或type匹配:
这看上去象一般对象的配置信息。视图标签的使用说明,parsley等到任何匹配的组件动态地获取注入的上下文,应用配置后,再创建该类的实例。
Parsley首先根据ID匹配。ID既可以是FLEX组件的名字,也可以是配置标签的ID
如果根据ID没有匹配,框架将根据类型匹配。如果定义含糊,则抛出错误。如果没有匹配类型,parsley将使用传统机制去处理元数据。
由于FLEX组件与IOC容器有关联,组件生命周期与直接定义在容器内的对象是不同的。这个由标签[Init]和
[Destroy]决定。
方法标签[Init]
Methods annotated with [Init]
对于一个声明在parsley配置文件中的对象,容器创建并配置好对象后才开始执行这些方法。对于一个动态注入的FLEX组件,容器捕获组件派发的事件和所有的注入都注入后,才开始执行这些方法。
方法标签[Destroy]
Methods annotated with [Destroy]
对于一个直接在parsley配置文件内声明的对象,这些方法仅在容器被销毁并且调用Context.destroy()后执行。对于一个动态注入的FLEX组件,destroy方法将在组件从stage移出后调用。
最后如果该组件的生命周期应该不依赖于它在stage上的时间花费,您可以切换此默认行为。你可以设置ViewManagerFactory属性,无论是在GlobalFactoryRegistry或CompositeContextBuilder.factories设置上下文。对于Flex这也可以配置的设置标签
当组件从stage中移除后,以上设置使组件不会从上下文中移除。当需要不再注入时,替代这样一个组件必须派发"removeView"事件。
最后,在单个组件上添加以下元数据:
[RemovedEvent("removeView")]
For Flex Popups and Native AIR Windows some extra step is required to tell the framework about them. This is because those are views which are disconnected from the view hierarchy below the main Application component. A Flex Popup usually sits somewhere right below the SystemManager. A Native AIR Window even comes with its own SystemManager. So you have to connect both manually to a Parsley ViewManager
if you want to use view wiring in popups and windows. This is quite easy:
Flex Popup
[Inject]
public var context:Context;
private function showPopup () : void {
var win:TitleWindow = new TitleWindow();
// set properties
context.viewManager.addViewRoot(win);
PopUpManager.addPopUp(win, this);
}
AIR Window
[Inject]
public var context:Context;
private function openWindow () : void {
var win:Window = new Window();
// set properties
context.viewManager.addViewRoot(win);
win.open();
}
The removeViewRoot
method of the ViewManager
interface will not be called by application code directly in most cases, as the default implementation of the interface will automatically remove a view root when it is removed from the stage.
下图展示了如何在模块化系统中进行视图注入,最重要的是如何人工连接FLEX的Popups和本地AIR容器到上下文。
包含
图中的上下文C你会看到上下文有两个视图根:一个是加载模块的根组件,另一个是为弹出窗体打开的视图根。很明显,为什么手工连接popup是必要的:如果一个组件的级别比popup低,派遣一个冒泡事件在SystemManager结束,不能达到ViewManager在根坐在模块组成部分,所以我们必须设置第二个监听器。
最后,这种机制是针对应用程序领域的:parsley的内部ModuleManager在根模块组件设置监听器,捕获ContextBuilders发出的
事件,告诉应用程序如何使用。
在某些罕见情况下,您可能要加载的Flex模块只包含了一些注入的视图类,但没有控制器,指挥,演示或域模式。你也许会跳过创建上下文,在这种情况会导致部分注入到根上下文。所以,你还是应该建立在模块中的根组件上下文,即使它是空的。这可以简单地透过根组件放入一个空