Flex 3 - 在使用AS3时,我必须在设置属性之前添加组件吗?

时间:2009-01-08 02:42:06

标签: flex flex3 mxml components

让我们说我有一个Flex 3 mxml组件,称之为A. A有一个名为'b'的get / set属性。在A中我有另一个内部组件C,它是使用mxml指定的。当在mxml中“实例化”组件A时,我可以在声明时指定b的值,一切正常。但是,当我使用Actionscript初始化组件时,我必须先将组件添加到渲染容器中,然后才能设置所述组件的属性(在本例中为“b”)。当属性'b'的setter以某种方式访问​​A中的C时会发生这种情况。

因此,这在运行时失败(它表示C为空)...

var a:A = new A();
a.b = "woopy"; //Sets the Label (declared in mxml) withn A to "woopy"
this.addChild(a);

另一方面,以下任何一种都可以使用

<customNamespace:A b="woopy"/>

var a:A = new A();
this.addChild(a);
a.b = "woopy"; //Sets the Label (declared in mxml) withn A to "woopy"

如图所示,在将组件添加到容器后设置属性时,不会引发运行时错误消息。好吧,这是有道理的,我想在组件添加到容器之前,实际上并没有创建组件的内部。不过,这有点烦人。是否有任何方法可以保证组件内部完全呈现而不将其添加到容器中?当我使用actionscript vs mxml时,我不喜欢它的感觉。我想要一个解决方案,以便基本上在没有属性“arguments”的mxml中声明A等同于在AS中使用new运算符声明A.至少,就A的内部状态而言。

3 个答案:

答案 0 :(得分:8)

要强制控件创建其子控件,您必须调用initialize方法。

即。这应该有效:

var a:A = new A();
a.initialize();
a.b = "woopy";
this.addChild(a);

但是,在声明mxml控件时我到目前为止所做的是将内部控件绑定到脚本块中声明的公共变量。 e.g。

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script>
        <![CDATA[
            [Bindable]
            public var labelText:String = "[Default]";
        ]]>
    </mx:Script>
    <mx:Label text="{labelText}"/>
</mx:Canvas>

通过这种方式,您可以设置参数,而无需担心控件是否已创建。

答案 1 :(得分:4)

这是对的 - 如果B的setter作用于C,你就会遇到问题,因为当A构造完成时,即使你已经在A的MXML中声明了C,C肯定还没有。

关于有任何方法可以保证组件及其子组件在不将其添加到容器的情况下完全呈现和使用,答案是否定的 - 框架不会在组件上执行其创建和渲染魔法,直到它以某种方式通过MXML或addChild()添加到显示列表。

当然,您可以使用visible或includeInLayout属性(例如,在A组件上将两者都设置为false)来实际显示组件,或者如果您必须在脚本中进行实例化,则可以监听A的初始化或者创建完成事件(两者都表示已经创建了A的子项并准备好对其进行操作),并等待设置B直到您收到该通知。但是作为一般规则,我不建议直接调用initialize()方法;它是一个框架方法,无论如何都会在addChild()之后自动调用,而且一般来说最好让框架做它的事情,而不是解决它。

var a:A = new A();
a.addEventListener(FlexEvent.INITIALIZE, a_initialize);
addChild(a);

private function a_initialize(event:FlexEvent):void
{
    a.b = "woopy";
    // ... and so on
}

如果你想确定,那就好了。

Flex团队的工程师Deepa Subramaniam最近在她的网站上发布了an excellent video,详细介绍了Flex组件模型的详细信息。我参加了MAX的演讲,在那里她录制了它,这很容易成为会议中最好的一次。值得观看(并重新观看,然后再次观看)其细节和全面性。在谈话期间,她实际上多次提出你的问题。这很棒。

祝你好运!

答案 2 :(得分:2)

要回答您的主要问题,不,如果要设置其属性,则不必将AS3实例化的组件添加到显示列表中。在MXML中创建它与在AS3中创建它没有区别...当然,除非组件没有正确构建。

Adob​​e的Flex团队(前身为Macromedia)花了很多年时间为Flex组件架构优化了优化。该设计有两个与您的问题相关的重要部分:

  1. 他们设计了失效和验证系统,以便您可以一次设置多个属性,但是在您完成所有更改之后,更改的效果才会发生。

  2. 首次实例化组件时,不会立即创建子组件。这是一个最佳的时间,也就是在将组件添加到显示列表之后。

  3. 基本上,当MXML实例化组件和AS3实例化组件之间的行为有所不同时,这是因为组件的构建没有考虑这两个特性。

    表现不正常的组件可能会执行以下操作:

    private var label:Label;
    
    public function get b():String
    {
        return this.label.text;
    }
    
    public function set b(value:String):void
    {
        this.label.text = value;
    }
    

    问题是组件开发人员没有考虑到Label子组件可能尚未创建!最佳做法是将值保存在变量中并使其无效以便稍后将其传递给子组件(在初始化组件并创建子组件之后,验证周期才会发生。)

    private var label:Label;
    
    private var _b:String;
    
    public function get b():String
    {
        return this._b;
    }
    
    public function set b(value:String):void
    {
        this._b = value;
        this.invalidateProperties();
    }
    
    override protected function commitProperties():void
    {
        super.commitProperties();
        this.label.text = this._b;
    }
    

    或者,如果您构建MXML组件,您可以执行类似的操作,但使用绑定而不是验证系统通常更容易:

    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
        <mx:Label text="{this.b}"/>
        <mx:Script><![CDATA[
    
        private var _b:String;
    
        [Bindable]
        public function get b():String
        {
            return this._b;
        }
    
        public function set b(value:String):void
        {
            this._b = value;
        }
    
        ]]></mx:Script>
    </mx:Application>
    
相关问题