如何访问不可见的flex组件?

时间:2011-10-03 13:38:14

标签: actionscript-3 flex4.5

我是flex的新手,正在构建一个flex 4.5应用程序,它有一个扩展SkinnableContainer的自定义组件。这个自定义组件基本上是一种可折叠的面板。当你打开它时,你会看到contentGroup中的所有控件,当你关闭它们时它们会消失,你就会得到标题。这是通过使contentGroup仅包含在打开状态而在皮肤中完成的。

我在应用程序中有一堆这样的容器,有些是默认打开的,有些是关闭的。 所以在mxml中结构如下:

<ui:MyCustomContainer open="false" label="bla">
  <s:HGroup>
    <s:Button />
    <ui:AnotherComponent />
    <etc />
  </s:HGroup>
</ui:MyCustomContainer>

我的问题是我无法访问(通过动作脚本,例如在事件处理中)来自已关闭容器的组件(实际上它们的初始化事件代码不会运行),直到它们至少打开一次。

进行一些挖掘我发现flex在延迟创建组件方面有一些性能提升。因此,我认为这必须是我在SkinnableContainer上将creationPolicy设置为“all”的答案:

<ui:MyCustomContainer open="false" label="bla" creationPolicy="all" >

但这不起作用。有什么想法吗?

更新:以下完整示例

Revealer.as可换肤容器(摘自Flex 4 in Action并略微删除)

package
{
import flash.events.Event;

import spark.components.SkinnableContainer;
import spark.components.ToggleButton;
import spark.components.supportClasses.TextBase;

[SkinState("open")]
[SkinState("closed")]
[SkinState("disabled")] //Not used: just appeasing compiler in the skin when host component is defined.
[SkinState("normal")]   //Not used: just appeasing compiler in the skin when host component is defined.

public class Revealer extends SkinnableContainer
{
    private var m_open:Boolean = true;
    private var m_label:String;

    [SkinPart]
    public var toggler:ToggleButton;

    [SkinPart(required="false")]
    public var labelDisplay:TextBase;


    public function Revealer()
    {
        super();
    }

    public function get open():Boolean { return m_open; }   
    public function set open( value:Boolean ):void
    {
        if( m_open == value )
            return;
        m_open = value;
        invalidateSkinState();  
        invalidateProperties();
    }       

    public function get label():String { return m_label; }
    public function set label( value:String ):void
    {
        if( m_label == value )
            return;
        m_label = value;
        if( labelDisplay != null )
            labelDisplay.text = value;
    }

    override protected function getCurrentSkinState():String { return m_open ? "open" : "closed"; }

    override protected function partAdded( name:String, instance:Object ):void
    {
        super.partAdded( name, instance );
        if(instance == toggler) 
        {
            toggler.addEventListener( Event.CHANGE, toggleButtonChangeHandler );
            toggler.selected = m_open;
        }
        else if( instance == labelDisplay )
        {
            labelDisplay.text = m_label;
        }
    }

    private function toggleButtonChangeHandler( e:Event ):void
    {
        open = toggler.selected;    
    }
}
}

RevealerSkin.mxml容器的外观

<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark" >
<fx:Metadata>[HostComponent("Revealer")]</fx:Metadata>
<s:states>
    <s:State name="open" />
    <s:State name="closed" />
    <s:State name="disabled" /> <!--not used: just appeasing compiler in the skin when host component is defined. -->
    <s:State name="normal" />   <!--not used: just appeasing compiler in the skin when host component is defined. -->
</s:states>
<s:Rect radiusX="5" top="0" left="0" right="0" bottom="0" minWidth="200">
    <s:stroke><s:SolidColorStroke weight="2" alpha="0.5"/></s:stroke>
</s:Rect>
<s:Group left="0" top="0" right="0" bottom="5">
    <s:ToggleButton id="toggler" label="toggle" left="5" top="5" /> 
</s:Group>
<s:Label id="labelDisplay" left="{toggler.width + 10}" top="10" right="0" />
<s:Group id="contentGroup" includeIn="open" itemCreationPolicy="immediate" left="5" right="5" top="35" bottom="5"  />
</s:Skin>

MyControl.mxml放置在容器内的自定义控件

<?xml version="1.0" encoding="utf-8"?>
<s:BorderContainer xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
                   borderWeight="2" borderColor="black"
               borderAlpha="0.2" cornerRadius="2"
           height="25">
<fx:Script>
    <![CDATA[
        [Bindable] public var minVal:Number;
        [Bindable] public var maxVal:Number;
        [Bindable] public var defaultVal:Number;            
        public function get value():Number  { return valueSlider.value; }
    ]]>
</fx:Script>
<s:layout>
    <s:VerticalLayout/>
</s:layout>
<s:HGroup width="100%" paddingTop="5" paddingBottom="5" paddingLeft="5" paddingRight="5">
    <s:Label text="Value:" />
    <s:Spacer width="100%" />
    <s:HSlider id="valueSlider" minimum="{minVal}" maximum="{maxVal}" value="{defaultVal}" />
</s:HGroup>
</s:BorderContainer>

RevealerTest.mxml用于演示问题的示例应用

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
           xmlns:local="*"
           minWidth="955" minHeight="600" >
<fx:Script>
    <![CDATA[
        protected function onClick( e:MouseEvent ):void {
            debugArea.text += control1.value + "\n" + control2.value + "\n";
        }
    ]]>
</fx:Script>
<s:HGroup>
    <s:VGroup>
        <s:Button label="click me" click="onClick(event)" />
        <local:Revealer label="Group 1" skinClass="RevealerSkin" creationPolicy="all">
            <local:MyControl id="control1" minVal="0" maxVal="10" defaultVal="5"/>
        </local:Revealer>
        <local:Revealer label="Group 2" open="false" skinClass="RevealerSkin" creationPolicy="all">
            <local:MyControl id="control2" minVal="0" maxVal="100" defaultVal="50"/>
        </local:Revealer>
    </s:VGroup>
    <s:TextArea id="debugArea" />
</s:HGroup>
</s:Application>

请注意,如果在打开第二个容器之前点击“我”按钮,则无法从最初折叠的组中的控件获取值。打开组一次允许访问该值。折叠组仍然可以。这是第一次出现问题。我已将creationPolicy添加到容器中,并将itemCreationPolicy添加到皮肤中的内容组,但没有运气!

1 个答案:

答案 0 :(得分:1)

实际上,这不是creationPolicy您正在寻找itemCreationPolicy。这是隐藏元素(contentGroup)的属性。如果由于immediate而未显示,则必须将其设置为currentState才能访问元素事件。