(Flex) Flex (2012 год)

Обработка собственных событий из 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:  }


Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/Flex_ItemRenderer_event/index.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>