3

Flex3mxmlコンポーネントがあるとしましょう。これをAと呼びます。Aには「b」というget/set属性があります。AI内には、mxmlを使用して指定される別の内部コンポーネントCがあります。mxml内でコンポーネントAを「インスタンス化」する場合、宣言時にbの値を指定でき、すべてが正常に機能します。ただし、Actionscriptを使用してコンポーネントを初期化する場合、コンポーネントの属性(この場合は「b」)を設定する前に、まずコンポーネントをレンダリングされたコンテナーに追加する必要があります。これは、属性'b'のセッターがA内のCに何らかの方法でアクセスした場合に発生します。

したがって、これは実行時に失敗します(Cがnullであると表示されます)...

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を使用しているときの感じ方が気に入らない。基本的に、属性「arguments」を使用せずにmxmlでAを宣言することは、ASでnew演算子を使用してAを宣言することと同等であるという解決策が必要です。少なくとも、Aの内部状態に関しては。

4

3 に答える 3

8

コントロールにその子コントロールを強制的に作成させるには、initialize メソッドを呼び出す必要があります。

つまり、これはうまくいくはずです:

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>

このようにして、コントロールが作成されているかどうかを気にせずにパラメーターを設定できます。

于 2009-01-08T11:46:45.160 に答える
4

そうです。B のセッターが C で動作する場合、問題が発生します。A が構築されたとき、A の MXML で C を宣言したとしても、C はまだそこにないことは間違いありません。

コンポーネントとその子が完全にレンダリングされ、コンテナに追加せずに使用可能であることを保証する方法があるということについては、答えはノーです。 MXML または addChild() を使用してリストを表示します。

もちろん、visible または includeInLayout プロパティ (たとえば、A コンポーネントで両方を false に設定) を使用して、コンポーネントを実際に表示することを回避できます。または、スクリプトでインスタンス化を行う必要がある場合は、A の初期化をリッスンできます。または creationComplete イベント (どちらも 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 でのトークに参加しました。その詳細と包括性は一見の価値があります (そして、もう一度見てからもう一度見てください)。彼女はトーク中に何度かあなたの質問に答えます。それは素晴らしいものです。

頑張ってください!

于 2009-01-08T13:10:03.013 に答える
2

主な質問に答えるには、いいえ、プロパティを設定する場合は、AS3 でインスタンス化されたコンポーネントを表示リストに追加する必要はありません。MXML での作成と AS3 での作成に違いはありません... もちろん、コンポーネントが適切にビルドされていない場合を除きます。

Adobe (旧 Macromedia) の Flex チームは、Flex コンポーネント アーキテクチャの最適化に何年も費やしました。この設計には、問題に関連する 2 つの重要な部分があります。

  1. 一度に多くのプロパティを設定できるように、無効化と検証のシステムを設計しましたが、すべての変更が完了するまで変更の効果は発生しません。

  2. コンポーネントが最初にインスタンス化されるとき、その子はすぐには作成されません。それを行うのに最適な時期があります。それは、コンポーネントが表示リストに追加された後です。

基本的に、MXML でインスタンス化されたコンポーネントと AS3 でインスタンス化されたコンポーネントの動作に違いがある場合、それはコンポーネントがこれら 2 つの機能を考慮せずに構築されたためです。

不適切に動作しているコンポーネントは、おそらく次のようなことを行います。

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>
于 2009-01-09T00:16:21.433 に答える