Как получить доступ к невидимым гибким компонентам? - PullRequest
0 голосов
/ 03 октября 2011

Я новичок в разработке Flex и создаю приложение Flex 4.5, в котором есть пользовательский компонент, расширяющий SkinnableContainer. Этот пользовательский компонент в основном является своего рода складной панелью. Когда вы открываете его, вы видите все элементы управления в contentGroup, когда вы закрываете их, они исчезают, и у вас остается заголовок. Это делается в скине, если группа содержимого включена только в открытом состоянии.

У меня есть куча этих контейнеров в приложении, некоторые открыты по умолчанию, а некоторые закрыты. Так что в mxml структура выглядит так:

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

Моя проблема в том, что я не могу получить доступ (с помощью ActionScript, например, при обработке событий) к компонентам из закрытых контейнеров (и действительно, их код события инициализации не запускается), пока они не будут открыты хотя бы один раз.

Проделав некоторое копание, я обнаружил, что flex имеет некоторое улучшение производительности в отношении отложенного создания компонентов. Подумав, что это должен быть ответ, я установил creationPolicy со значением «all» в SkinnableContainer:

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

Но это не работает. Есть идеи?

ОБНОВЛЕНИЕ: полный пример ниже

Revealer.as Контейнер для скинов (взят из книги Flex 4 в действии и немного урезан)

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 Ответ

1 голос
/ 03 октября 2011

На самом деле, вы ищете не creationPolicy, а itemCreationPolicy . Это свойство вашего скрытого элемента (contentGroup). Вы должны установить его на immediate для доступа к событию элемента, если оно не отображается из-за currentState.

...