[Flex]2つのDataGridで列定義を同期させてみる

Flex の DataGrid で、列の定義をするのに DataGridColumn を使いますが、それを、2つの DataGrid で同じ DataGridColumn を共有し、それぞれの DataGrid の列定義を同期させてみようという小ネタをご紹介します。
例として、上下に並べた DataGrid で、どちらかの列幅を変えたときにもう片方の列幅も一緒に変更されるといったことをやってみました。

以下がサンプルソースになります。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*"
	creationComplete="creationCompleteHandler(event)">
	<mx:Script>
		<![CDATA[
			import mx.events.DataGridEvent;
			import mx.events.FlexEvent;
			
			private var dgColumns:Array = new Array();
			
			[Bindable]
			private var dgData1:Array = [
			{no:1, name:'氏名1-1', age:21, address:'住所1-1'},
			{no:2, name:'氏名1-2', age:22, address:'住所1-2'},
			{no:3, name:'氏名1-3', age:23, address:'住所1-3'},
			{no:4, name:'氏名1-4', age:24, address:'住所1-4'},
			{no:5, name:'氏名1-5', age:25, address:'住所1-5'}
			];
			[Bindable]
			private var dgData2:Array = [
			{no:1, name:'氏名2-1', age:31, address:'住所2-1'},
			{no:2, name:'氏名2-2', age:32, address:'住所2-2'},
			{no:3, name:'氏名2-3', age:33, address:'住所2-3'},
			{no:4, name:'氏名2-4', age:34, address:'住所2-4'},
			{no:5, name:'氏名2-5', age:35, address:'住所2-5'}
			];
			
			public function creationCompleteHandler(event:FlexEvent):void
			{
				dataGrid2.columns = dataGrid1.columns;
				
				dataGrid1.addEventListener(DataGridEvent.COLUMN_STRETCH, dgColumnStretch);
				dataGrid2.addEventListener(DataGridEvent.COLUMN_STRETCH, dgColumnStretch);
			}
			
			public function dgColumnStretch(event:DataGridEvent):void
			{
				if (event.currentTarget == dataGrid1)
					dataGrid2.invalidateList();
				else
					dataGrid1.invalidateList();
			}
		]]>
	</mx:Script>
	
	<mx:VBox>

	<mx:DataGrid id="dataGrid1" dataProvider="{dgData1}">
		<mx:columns>
			<mx:DataGridColumn headerText="NO" dataField="no"/>
			<mx:DataGridColumn headerText="氏名" dataField="name"/>
			<mx:DataGridColumn headerText="年齢" dataField="age"/>
			<mx:DataGridColumn headerText="住所" dataField="address"/>
		</mx:columns>
	</mx:DataGrid>
	
	<mx:DataGrid id="dataGrid2" dataProvider="{dgData2}">
	</mx:DataGrid>

	</mx:VBox>
</mx:Application>


上記ソースでは、2つ目の DataGrid の columns プロパティを定義せずに、アプリケーションの creationCompleteイベントのハンドラーで、dataGrid1 の columns プロパティをそのままコピーしています。

	dataGrid2.columns = dataGrid1.columns;

この時点で、上下の DataGrid の列定義が同じになり、上の DataGrid と 下の DataGrid の列定義(ヘッダー文字列、表示する内容など)が同じものになります。
このままですと、同じ DataGridColumn を使っているだけですので、初期表示の列定義をコピーしただけになります。

そこで、それぞれの DataGrid の columnStretch イベントのハンドラーメソッドで、お互いの invalidateList メソッドを呼んで描画をリフレッシュするようにします。

	private function dgColumnStretch(event:DataGridEvent):void
	{
		if (event.currentTarget == dataGrid1)
			dataGrid2.invalidateList();
		else
			dataGrid1.invalidateList();
	}

すると、上下の DataGrid の列幅が、常に同期するということができるようになります。
同じ DataGridColumn を見に行っているので当たり前といえば当たり前です。
ただ、列幅変更時にリフレッシュしない場合、表面上はそれぞれの DataGrid の列幅が違いますが、裏側では同じですので、再表示のタイミングでいきなり列幅が変わるという見方によっては不具合と捉えられる怪しい挙動をしてしまいます。

以下が、上記ソースで作成したFlexアプリケーションのサンプルになります。
上下それぞれの DataGrid の列幅を変更して、実際の動作を試してみてください。

最後に、DataGrid の columns プロパティは Arrayクラスですが、値を取得または設定するとき、元データの一連のエレメントを取り出して、新しい配列で取得または設定する sliceメソッドを使用しています。

そのため、列の順序を変更した場合は、上記のやり方だけですと上下の DataGrid で別々の列順序になってしまいます。

列の順序を変更した場合は、DataGrid の headerShift イベントのハンドラーメソッドなどで、columns の順序も考慮した同期を取るようにしたほうが良いと思います。

このブログについて

このブログは吉祥寺にあるブレインチャイルド株式会社の社員で投稿しています。
業務ではまってしまったことや発見したこと。
自分達で新たに学習してみようと思って勉強し始めたことなどを綴っています。
こんな社員が働いているブレインチャイルドに興味がわいててきたなら、是非お問い合わせください。
会社案内
求人案内
先輩のコメント