Flexの入門経験(8)--itemRendererと外部コンポーネントの通信

7052 ワード

例えば次のようなVOがあります

 package com.crap.vo{
	public class Product
	{
		public function Product(name:String,price:Number)
		{
			this.name=name;
			this.price=price;
		}
		
		public var name:String;
		
		public var price:Number;
	}
}

今datagridで、価格が50より大きいものを赤で表示したいのですが、次のようなコードが使えます.

<s:DataGrid dataProvider="{productAC}">
		<s:columns>
			<s:ArrayList>
				<s:GridColumn dataField="name"/>
				<s:GridColumn>
					<s:itemRenderer>
						<fx:Component>
							<s:GridItemRenderer>
								
								<fx:Script>
									<![CDATA[
										import com.crap.vo.Product;
										override public function set data(data:Object):void{
											super.data=data;
											var product:Product=data as Product;
											if(product.price>50){
												this.lblPrice.setStyle("color","red");
											}else{
												this.lblPrice.setStyle("color","black");
											}
										}
									]]>
								</fx:Script>
								
								<s:Label text="{data.price}" id="lblPrice">
								</s:Label>
							</s:GridItemRenderer>
						</fx:Component>
					</s:itemRenderer>
				</s:GridColumn>
			</s:ArrayList>
		</s:columns>
</s:DataGrid>

中に気をつけてlblPrice.setStyle("color","black");この行のコード
itemrendererはリサイクルされるため、システムはすべてのdataをレンダリングするために一定数のitemrendererしか作成しません.
この行のコードがなければitemrendererがcolorをredに設定するとblackにはなりません
しかしhard codeの50は本当に不快なのでtextinputを作って、しきい値をユーザーが入力した数値にします

<?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:mx="library://ns.adobe.com/flex/mx"
			   minWidth="955" minHeight="600">
	<fx:Declarations>
	</fx:Declarations>
	<s:layout>
		<s:VerticalLayout/>
	</s:layout>
	<fx:Script>
		<![CDATA[
			import com.crap.vo.Product;
			
			import mx.collections.ArrayCollection;
			
			
			[Bindable]
			public var productAC:ArrayCollection=new ArrayCollection(
				[new Product("product1",43),
					new Product("product2",35),
					new Product("product3",108)]);
			
		]]>
	</fx:Script>
	
	<s:TextInput id="txtInputNumber" change="productAC.refresh();" >
		
	</s:TextInput>
	<s:DataGrid dataProvider="{productAC}" id="dgProduct">
		<s:columns>
			<s:ArrayList>
				<s:GridColumn dataField="name"/>
				<s:GridColumn>
					<s:itemRenderer>
						<fx:Component>
							<s:GridItemRenderer>
								
								<fx:Script>
									<![CDATA[
										import com.crap.vo.Product;
										override public function set data(data:Object):void{
											super.data=data;
											var product:Product=data as Product;
											if(product.price> Number(outerDocument.txtInputNumber.text) ){
												this.lblPrice.setStyle("color","red");
											}else{
												this.lblPrice.setStyle("color","black");
											}
										}
									]]>
								</fx:Script>
								
								<s:Label text="{data.price}" id="lblPrice">
								</s:Label>
							</s:GridItemRenderer>
						</fx:Component>
					</s:itemRenderer>
				</s:GridColumn>
			</s:ArrayList>
		</s:columns>
	</s:DataGrid>
	
</s:Application>

datagridのdataproviderのarraycollectionに対してrefreshメソッドを呼び出すことで、datagridコンポーネントの状態をリフレッシュすることができることに注意する.
でもここでitemrendererはouterDocumentを使います.txtInputNumberのように外部コントロールにアクセスし、
実はこのlimit値はdatagridに入れるべきで、このようにdatagridとitemrendererはもっとよくパッケージされています.
Datagridをカスタマイズします

package com.crap.compenent{
	import mx.collections.ArrayCollection;
	
	import spark.components.DataGrid;
	
	public class CrapDataGrid extends DataGrid
	{
		public function CrapDataGrid()
		{
			super();
		}
		
		private var _limit:Number;
		
		
		public function get limit():Number
		{
			return _limit;
		}

		public function set limit(value:Number):void
		{
			_limit = value;
			ArrayCollection(this.dataProvider).refresh(); 
			
		}

	}
}

そしてこのように使います

<s:TextInput id="txtInputNumber" text="">
		
	</s:TextInput>
	
	
	<compenent:CrapDataGrid dataProvider="{productAC}" id="dgProduct" limit="{Number(txtInputNumber.text)}">
		<compenent:columns>
			<s:ArrayList>
				<s:GridColumn dataField="name"/>
				<s:GridColumn>
					<s:itemRenderer>
						<fx:Component>
							<s:GridItemRenderer>
								
								<fx:Script>
									<![CDATA[
										import com.crap.compenent.CrapDataGrid;
										import com.crap.vo.Product;
										override public function set data(data:Object):void{
											super.data=data;
											var product:Product=data as Product;
											var crapDataGrid:CrapDataGrid=this.grid.dataGrid as CrapDataGrid;
											if(product.price> crapDataGrid.limit ){
												this.lblPrice.setStyle("color","red");
											}else{
												this.lblPrice.setStyle("color","black");
											}
										}
									]]>
								</fx:Script>
								
								<s:Label text="{data.price}" id="lblPrice">
								</s:Label>
							</s:GridItemRenderer>
						</fx:Component>
					</s:itemRenderer>
				</s:GridColumn>
			</s:ArrayList>
		</compenent:columns>
	</compenent:CrapDataGrid>

GridItemRendererではgridに参照できるgrid属性があり、gridのdataGrid属性はdataGridに参照できる.
GridとDataGridの違いが全く分からず、ドキュメントにもぼろぼろに書かれていて、実際にspark Gridコントロールの使用例が見つからず、ここのAPIがめちゃくちゃに設計されているような気がします.