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

发布于 2024-07-10 15:30:21 字数 897 浏览 5 评论 0原文

假设我有一个 Flex 3 mxml 组件,将其称为 A。A 有一个名为“b”的 get/set 属性。 AI 内部还有另一个内部组件 C,它是使用 mxml 指定的。 当在 mxml 中“实例化”组件 A 时,我可以在声明时指定 b 的值,并且一切正常。 但是,当我使用 Actionscript 初始化组件时,我必须首先将组件添加到呈现的容器中,然后才能设置所述组件的属性(在本例中为“b”)。 当属性“b”的设置器以某种方式访问​​ 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 与 mxml 时的不同感觉。 我想要一个解决方案,以便基本上在 mxml 中声明没有属性“参数”的 A 相当于在 AS 中使用 new 运算符声明 A。 至少,就 A 的内部状态而言。

Let us say that I have a Flex 3 mxml component, call it A. A has a get/set attribute called 'b'. Within A I have another internal component C, which is specified using mxml. When "instantiating" component A within mxml, I can specify the value of b at declaration, and everything works fine. However, when I initialize the component using Actionscript, I must first add the component to a rendered container before I can set the attribute (in this case 'b') of said component. This happens when the setter for attribute 'b' somehow accesses C within A.

So, this fails at runtime (it says that C is null)...

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

On the other hand, either of the following will work

<customNamespace:A b="woopy"/>

or

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

As shown, no runtime error message is thrown when a attribute is set after a component is added to a container. Ok, this makes sense, I suppose the internals of the component are not actually created until the component is added to a container. Still, this is kind of annoying. Is there any way to guarantee that the component internals are fully rendered without adding it to a container? I don't like the way it feels different when I am using actionscript vs mxml. I want a solution so that basically declaring A in mxml with no attribute "arguments" is equivalent to declaring A using the new operator in AS. At least, in terms of the internal state of A.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

给不了的爱 2024-07-17 15:30:21

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

也就是说,这应该可行:

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

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

<?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>

这样您就可以设置参数,而不必担心控件是否已创建。

To force a control to create its child controls you have to call the initialize method.

i.e. this should work :

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

However, what I've been doing so far when declaring mxml controls is binding the internal controls to public variables declared in a script block. 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>

This way you can set your parameters without having to worry about whether the controls have been created or not.

滥情哥ㄟ 2024-07-17 15:30:21

没错——如果 B 的 setter 作用于 C,您就会遇到问题,因为当构造 A 时,C 肯定还不存在,即使您已在 A 的 MXML 中声明了 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 最近在她的网站上发布了一段出色的视频,内容涵盖Flex 组件模型的详细、逐步的细节; 我参加了 MAX 的演讲,她录制了演讲,这无疑是会议中最好的演讲之一。 因其细节和全面性而值得观看(并重新观看,然后再次观看)。 事实上,她在演讲过程中多次回答了你的问题。 这是很棒的东西。

祝你好运!

That's right -- if B's setter acts on C, you'll have problems, because when A's constructed, C's definitely not there yet, even if you've declared C in A's MXML.

About there being any way to guarantee a component and its children are fully rendered and usable without adding it to a container, the answer is no -- the framework won't perform its creation and rendering magic on a component until it's somehow added to the display list, either by way of MXML or addChild().

Of course, you could use the visible or includeInLayout properties (setting both to false on your A component, for example) to get around actually displaying the component, or if you had to do the instantiation in script, you could listen for either A's initialize or creationComplete events (both of which indicate A's children have been created and are ready to be acted upon), and just wait to set B until you receive that notification. As a general rule, though, I wouldn't advise calling the initialize() method directly; it's a framework method that gets called automatically just after addChild() anyway, and in general it's better to let the framework do its thing, rather than work around it.

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
}

So it goes, if you want to be sure.

Deepa Subramaniam, an engineer on the Flex team, recently posted an excellent video on her site covering the Flex component model in granular, step-by-step detail; I attended the talk at MAX where she recorded it, it was easily one of the best of the conference. Worth watching (and re-watching, and then watching again) for its detail and comprehensiveness. She actually addresses your question at several times during the talk. It's great stuff.

Best of luck!

苍风燃霜 2024-07-17 15:30:21

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

Adobe(以前称为 Macromedia)的 Flex 团队花费了多年时间来改进 Flex 组件架构的优化。 该设计有两个重要部分与您的问题相关:

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

  2. 当一个组件首次实例化时,它的子组件不会立即创建。 有一个最佳时间来执行此操作,即在将组件添加到显示列表之后。

基本上,当 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>

To answer your main question, no, you don't have to add an AS3-instantiated component to the display list if you want to set its properties. There's no difference between creating it in MXML versus creating it in AS3... unless, of course, the component wasn't built properly.

The Flex team at Adobe (formerly Macromedia) spent many years refining optimizations for the Flex component architecture. There are two important parts of that design that are related to your problem:

  1. They designed system of invalidation and validation so that you can set many properties at once, but the effects of the changes don't happen until you're done making all your changes.

  2. When a component is first instantiated, it's children are not created right away. There's an optimal time to do it, and that's after the component has been added to the display list.

Basically, when you have a difference in behavior between an MXML instantiated component and an AS3 instantiated component, it's because the component was built without these two features in mind.

The component that is behaving improperly probably does something like this:

private var label:Label;

public function get b():String
{
    return this.label.text;
}

public function set b(value:String):void
{
    this.label.text = value;
}

The problem is that the component developer didn't take into account that the Label sub-component may not have been created yet! The best practice is to save the value in a variable and invalidate to pass it to the sub-component later (the validation cycle doesn't happen until after the component is initialized and the children are created).

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

Alternatively, if you build an MXML component, you can do something similar, but it's often easier to use binding instead of the validation system:

<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文