Я новичок в разработке 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 в группу содержимого в скине, но не повезло!