Обработка собственных событий из ItemRenderer
To view this page ensure that Adobe Flash Player version 11.1.0 or greater is installed.
Основной элемент отображения периодических данных во Флекс - DataGroup / ItemRenderer (и всевозможные их производные, вроде Custom ItemRenderer ). DataGroup фактически во флексе играет ту же роль, что и DataList в ASP.NET - то есть без них никуда. Базовый пример использования DataGroup-ItemRenderer вы можете у меня в блоге - Как создавать простые тетрис-подобные аркады на Флексе за несколько кликов мышкой.
Но когда мне потребовалось обработать собственное событие, создаваемое в ItemRenderer - я сразу и не сообразил как, пришлось взглянуть в инете. Оказалось что прицепить у элементов подобных s:DataGroup прицепить обработчики ItemRenderer можно только в событии updateComplete элемента s:DataGroup. Чтобы эта фишка не забылось (и другим это будет полезно) - я решил написать эту небольшую ремарку.
Конечно, вживую на сайте, это все вычитывается web-сервисами из базы, но для этой заметки такой пример был бы бессмысленным - билеты раскупят и web-сервис по этому отбору будет вызвращать пустой набор билетов. Смысл и код этой маленькой заметочки будет утерян. Поэтому я сделал снимок данных, возвращаемых web-сервисом из базы (так как я описал тут Флекс-сериализаторы. Сериализация/десеализация FLAME вышла вполне точной, за исключением рекурсивного ENUM - как видите, это я поправил вручную.
Итак, приложение, которое вы видите в этой заметке - выглядит вот так:
1: <?xml version="1.0" encoding="utf-8"?>
2: <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
3: xmlns:s="library://ns.adobe.com/flex/spark"
4: xmlns:mx="library://ns.adobe.com/flex/mx"
5: minWidth="654" width="654"
6: applicationComplete="application1_applicationCompleteHandler(event)" backgroundColor="#FDF5E6" height="400" minHeight="400">
7: <fx:Script>
8: <![CDATA[
9: import adobe.utils.CustomActions;
10: import adobe.utils.XMLUI;
11:
12: import flame.serialization.JSONSerializer;
13:
14: import mx.collections.ArrayCollection;
15: import mx.controls.Alert;
16: import mx.events.FlexEvent;
17: import mx.managers.BrowserManager;
18: import mx.managers.IBrowserManager;
19: import mx.utils.StringUtil;
20:
21: [Bindable]
22: protected var Tickets:ArrayCollection;
23:
24: [Embed(source="WebServiceResult.txt",mimeType="application/octet-stream")]
25: private var JSON_text : Class;
26:
27:
28: protected function application1_applicationCompleteHandler(event:FlexEvent):void
29: {
30: var JSONtext:ByteArray = new JSON_text() as ByteArray;
31: var JSONstr:String= JSONtext.readUTFBytes(JSONtext.length);
32: var Flame:flame.serialization.JSONSerializer = new flame.serialization.JSONSerializer
33: var X = Flame.deserialize(JSONstr);
34: Tickets = new ArrayCollection;
35: for (var i:int=0;i<X.length;i++){
36: X.source[i].TicketType = TicketType.Good;
37: Tickets.addItem(X.source[i]);
38: }
39: WebServiceEnd();
40: }
41:
42: //все обращения к сервисам завершились -> все вычитанные данные в Tickets
43: protected function WebServiceEnd():void{
44: if (TicketsGroup.dataProvider!==null){
45: TicketsGroup.dataProvider.removeAll();
46: TicketsGroup.validateNow();
47: TicketsGroup.dataProvider=Tickets;
48: TicketsGroup.validateNow();
49: }
50: else {
51: TicketsGroup.invalidateDisplayList();
52: TicketsGroup.dataProvider=Tickets;
53: }
54: }
55:
56: protected function TicketsGroup_updateCompleteHandler(event:FlexEvent):void
57: {
58: for (var i:int=0;i<TicketsGroup.numElements;i++){
59: var TicketView1:OneTicketView = TicketsGroup.getElementAt(i) as OneTicketView;
60: TicketView1.addEventListener("TicketSelected", TickedSelected_event);
61: }
62: }
63:
64: protected function TickedSelected_event(e:Event):void{
65: URL1.text = (e.currentTarget as OneTicketView).SelectedTicketID;
66: //var RedirectURL:String = FormatURL(URL_Parm.IsDirection, URL_Parm.IsReturn, URL_Parm.FromDate, URL_Parm.ToDate, SelectedTicketID);
67: //flash.net.navigateToURL(new URLRequest("Zakaz.aspx#" + RedirectURL),"_self");
68: }
69:
70: import mx.collections.ArrayCollection;
71: import mx.collections.ArrayList;
72:
73: protected function FormatURL(IsDirection:Boolean, IsReturn:Boolean, FromDate:String, ToDate:String, ID:String):String{
74: return mx.utils.StringUtil.substitute("Direction={0},Return={1},FromDate={2},ToDate={3},CN={4}", IsDirection, IsReturn, FromDate, ToDate, ID);
75: }
76:
77: ]]>
78: </fx:Script>
79:
80: <s:DataGroup id="TicketsGroup" x="0" y="40" width="100%" height="100%" itemRenderer="OneTicketView" updateComplete="TicketsGroup_updateCompleteHandler(event)">
81: <s:layout>
82: <s:VerticalLayout gap="20"/>
83: </s:layout>
84: </s:DataGroup>
85: <s:Label x="50" y="10" width="553" id="URL1"/>
86:
87: </s:Application>
Ключик - привязку к собственному событию ItemRenderer - вы видите в строке 60, ну а теперь собственно код рендерера:
1: <?xml version="1.0" encoding="utf-8"?>
2: <s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
3: xmlns:s="library://ns.adobe.com/flex/spark"
4: xmlns:mx="library://ns.adobe.com/flex/mx" width="654" height="100"
5: creationComplete="bordercontainer1_contentCreationCompleteHandler(event)"
6: contentBackgroundColor="#FDF5E6">
7:
8: <fx:Metadata>
9: [Event(name="TicketSelected", type="flash.events.Event")]
10: </fx:Metadata>
11:
12: <fx:Script>
13: <![CDATA[
14: import mx.controls.Alert;
15: import mx.events.FlexEvent;
16:
17: [Embed(source="../Images/back.png")]
18: [Bindable]
....
41: [Embed(source="../Images/z4.jpg")]
42: [Bindable]
43: public var RedImage:Class;
44:
45:
46: private var _TicketType:TicketType;
47: private var _USDCurs:Number;
48: private var _DirectTicketInfo;
49: private var _ReturnTicketInfo;
50:
51: protected function FormatPrice():String{
52: var NF:NumberFormatter = new NumberFormatter();
53: var DirectCost:Number=0;
54: var ReturnCost:Number=0;
55: var RubCost:Number;
56: if (_DirectTicketInfo !==null){
57: DirectCost = _DirectTicketInfo.Price;
58: }
59: if (_ReturnTicketInfo!==null){
60: ReturnCost = _ReturnTicketInfo.Price;
61: }
62: RubCost = _USDCurs * (DirectCost + ReturnCost);
63: return NF.format(RubCost);
64: }
65:
66:
67: protected function bordercontainer1_contentCreationCompleteHandler(event:FlexEvent):void
68: {
69: _TicketType = data.TicketType;
70: _USDCurs = data.USDCurs;
71: _DirectTicketInfo = data.DirectTicketInfo;
72: _ReturnTicketInfo = data.ReturnTicketInfo;
73: if (_DirectTicketInfo !== null){
74: L1.text = FormatDayNames(_DirectTicketInfo.FromDate);
75: L2.text = _DirectTicketInfo.FromAirport + " " + _DirectTicketInfo.FromTime;
76: L3.text = _DirectTicketInfo.ToAirport + " " + _DirectTicketInfo.FlyTime;
77: L4.text = _DirectTicketInfo.AviaCompanyCode + " " + _DirectTicketInfo.FlyNumber;
78: L5.text = _DirectTicketInfo.HowMany;
79: }
80: if (_DirectTicketInfo.HowMany=="Есть" || _DirectTicketInfo.HowMany=="есть" ){
81: Dir.source = YesImage;
82: }
83: else{
84: Dir.source = NoImage;
85: }
86: if (_ReturnTicketInfo !== null){
87: M1.text = FormatDayNames(_ReturnTicketInfo.FromDate);
88: M2.text = _ReturnTicketInfo.FromAirport + " " + _ReturnTicketInfo.FromTime;
89: M3.text = _ReturnTicketInfo.ToAirport + " " + _ReturnTicketInfo.FlyTime;
90: M4.text = _ReturnTicketInfo.AviaCompanyCode + " " + _ReturnTicketInfo.FlyNumber;
91: M5.text = _ReturnTicketInfo.HowMany;
92: if (_ReturnTicketInfo.HowMany=="Есть" || _ReturnTicketInfo.HowMany=="есть" ){
93: Ret.source = YesImage;
94: }
95: else{
96: Ret.source = NoImage;
97: }
98: }
99: lCost.text = FormatPrice();
100: }
101:
102: public var SelectedTicketID:String;
103: protected function image1_clickHandler(event:MouseEvent):void
104: {
105: if (_DirectTicketInfo !== null){
106: SelectedTicketID = _DirectTicketInfo.ID
107: }
108: if (SelectedTicketID !== ""){
109: SelectedTicketID += "_"
110: }
111: if (_ReturnTicketInfo !== null){
112: SelectedTicketID += _ReturnTicketInfo.ID
113: }
114: dispatchEvent(new Event("TicketSelected", true));
115: }
116:
117: ]]>
118: </fx:Script>
119:
120: <fx:Script source="DateFunction.as" />
121:
122: <fx:Declarations>
123: <!-- Place non-visual elements (e.g., services, value objects) here -->
124: </fx:Declarations>
125: <s:BorderContainer x="0" y="0" width="654" height="100" backgroundImage="{BackImage}" borderVisible="false" backgroundColor="#FDF5E6">
126: <mx:Image id="A1" x="563" y="50" width="91" height="41" useHandCursor="true" buttonMode="true" mouseOver="A1.source=RedImage" mouseOut="A1.source=OkButtImage" click="image1_clickHandler(event)" source="{OkButtImage}"/>
127: <s:Label x="577" y="64" text="заказать" fontSize="16" color="white" useHandCursor="true" buttonMode="true" mouseOver="A1.source=RedImage" mouseOut="A1.source=OkButtImage" click="image1_clickHandler(event)" />
128: <s:Label x="50" y="10" text="Дата вылета"/>
129: <s:Label x="50" y="60" text="Дата вылета" height="14"/>
130: <s:Label x="150" y="10" text="Время вылета"/>
131: <s:Label x="150" y="60" text="Время вылета"/>
132: <s:Label x="250" y="10" text="Время прилета"/>
133: <s:Label x="250" y="60" text="Время прилета"/>
134: <s:Label x="350" y="10" text="Номер рейса"/>
135: <s:Label x="350" y="60" text="Номер рейса"/>
136: <s:Label x="450" y="10" text="Наличие мест"/>
137: <s:Label x="450" y="60" text="Наличие мест"/>
138: <s:Label x="565" y="10" text="звоните" id="lCost" fontSize="20" color="red"/>
139: <s:Label x="50" y="36" id="L1"/>
140: <s:Label x="50" y="85" id="M1"/>
141: <s:Label x="150" y="36" id="L2"/>
142: <s:Label x="150" y="85" id="M2"/>
143: <s:Label x="250" y="36" id="L3"/>
144: <s:Label x="250" y="85" id="M3"/>
145: <s:Label x="350" y="36" id="L4"/>
146: <s:Label x="350" y="85" id="M4"/>
147: <s:Label x="450" y="36" id="L5"/>
148: <s:Label x="450" y="85" id="M5"/>
149: <mx:Image id="Dir" x="490" y="32" width="15" height="15" />
150: <mx:Image id="Ret" x="490" y="82" width="15" height="15" />
151: </s:BorderContainer>
152:
153: </s:ItemRenderer>
154:
Основной элемент рендерера - это событие, обьявляемое в строке 9 - именно на него надо подписатся в DataGroup таким вот хитрым способом, как это я сделал в строке 60 контейнера.
В строке 120 приатачены функции форматирования даты, они в принципе тут для понимания работы не требуются - но вдруг кому-то понядобятся:
1: import spark.formatters.NumberFormatter;
2:
3: //добавить ведущие нули при преобразовании цыфры в строку
4: protected function FormatLeadingZero(Num: int, width: int) : String{
5: var p:String = "";
6: var Str1:String = Num.toString();
7: var L:int = Str1.length;
8: if (width-L>0) for (var i: int = 0; i < width - L; i++){
9: p += '0';
10: }
11: return p+Str1;
12: }
13:
14: //приводит мое цифровое представление даты в представление даты во флексе (new date)
15: protected function FromStrToArr(DateStr:String):Array{
16: var DtArr:Array= DateStr.split(".");
17: if (DtArr.length==3){
18: try{
19: var NF:spark.formatters.NumberFormatter = new spark.formatters.NumberFormatter();
20: DtArr[0] = NF.parseNumber(DtArr[0]) as int;
21: DtArr[1] = (NF.parseNumber(DtArr[1]) as int)-1;
22: DtArr[2] = NF.parseNumber(DtArr[2]) as int;
23: var x:Date = new Date(DtArr[2],DtArr[1],DtArr[0]);
24: return DtArr;
25: }
26: catch(e:Object){
27: //дата некорректна
28: }
29: }
30: //вернем текущую дату вместо мусора на входе функции
31: var Dt:Array = new Array;
32: var y:Date = new Date();
33: Dt.push(y.date);
34: Dt.push(y.month);
35: Dt.push(y.fullYear);
36: return Dt;
37: }
38:
39: protected var RuDay:Array = new Array("ВСК","ПНД","ВТР","СРД","ЧТВ","ПТН","СБТ");
40:
41: //форматирует текстовую дату в моем формате в дату с названием дня
42: protected function FormatDayNames(MyDate:String):String{
43: var DT1:Array = FromStrToArr(MyDate);
44: var DT2:Date = new Date(DT1[2],DT1[1],DT1[0]);
45: var DT3:int = RuDay[DT2.day];
46: return RuDay[DT3] + " " + FormatLeadingZero(DT1[0],2)+ "." + FormatLeadingZero(DT1[1]+1,2)
47: }
|