开发者

How to access non-visible flex components?

I'm a newbie to flex and am building a flex 4.5 app that has a custom component extending SkinnableContainer. This custom component is basically a kind of collapsible panel. When you open it you see all the controls in the contentGroup, when you close they go away and you are left with the title. This is done in the skin by having the contentGroup included only in the open state.

I have a bunch of these containers in the app, some open by default and some closed. So in mxml the structure looks like:

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

My problem is that i cannot access (via actionscript, eg in event handling) the components from the closed containers (and indeed their initialize event code does not run) until they have been opened at least once.

Doing some digging i found that flex has some kind of performance enhancement regarding deferred creation of components. So thinking that this must the answer i set creationPolicy to "all" on the SkinnableContainer:

<ui:MyCustomContainer open="false开发者_如何转开发" label="bla" creationPolicy="all" >

But this does not work. Any ideas?

UPDATE: Full example below

Revealer.as The skinnable container (taken from book Flex 4 in Action and stripped down a bit)

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 The skin for the container

<?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 A custom control placed inside the container

<?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 A sample app to demonstrate the problem

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

Note that if you hit the click me button before opening the second container we are unable to get the value from the control in the initially collapsed group. Opening the group once allows access to the value. Collapsing the group is still ok. It's the first time that's the problem. I have added creationPolicy to the container and itemCreationPolicy to the content group in the skin but no luck!


Actually, it's not creationPolicyyou are looking for but itemCreationPolicy. This is a property of your hidden element (contentGroup). You have to set it to immediate to access the element event if it is not displayed due to currentState.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜