본문 바로가기

Flex

데이터그리드 아이템랜더러 사용 및 CollectionEvent

오늘 좀 한가하다 -ㅅ-;;;
덕분에 하나 더 올리게 되었다.

이번 포스팅은 이전 포스팅의 계량형이라고 할까.. 업그레이드 버전 정도 된다.
2010/03/09 - [Flex/Event] - 데이터 그리드 ListEvent / DatagridEvent 특정 칼럼만 에디트 하기

목적

이전 포스팅에서 더블클릭으로 아이템 에디트 모드로 들어가고 클릭으로 선택 하는 형식으로 만들었는데 이번에는 itemRenderer를 이용해서 에디트 버튼을 가지고 있는 데이터 그리드를 만든다.
그리고 디비에 데이터를 업데이트 한다고 할때 어느 시점에서 업데이트를 해야 하는지 CollectionEvent를 이용해서 알아본다.

										rinn				퍼플린				B										magis				들캔디				A										zzatung				짝퉁				??									.btnEditColumn{			upSkin: Embed(source="assets/edit.png");			overSkin: Embed(source="assets/edit_over.png");			downSkin: Embed(source="assets/edit.png");		}																


기본적으로 mxml 부분은 이전과 같다.
Datagrid 에 붙어있던 각종 이벤트 처리 부분이 랜더러로 빠져나가기 때문에 Datagrid 태그쪽만 좀 한가해졌다.

아이템랜더러는 엄청나게 많이 사용되고 질문또한 많이 올라오는 부분중에 하나이다. 간단하게 버튼을 넣는거 부터 복잡하게는 랜더러와 에디터를 따로 커스터마이징 해서 사용하는 경우까지 상황이 다양하지만. 기본적으로는 비슷하기 때문에 이 포스트에서 다루는 정도만 해도 기초적인것은 커버 될꺼라 생각한다.

위 소스 에서 <mx:DataGridColumn dataField="name" itemRenderer="renAddEditButton"> 이곳에 설정된 itemRenderer 로 사용되고 있는 renAddEditButton 이 이번 포스트의 핵심이다.

일단 소스 풀소스를 보자.

package{	import flash.events.MouseEvent;		import mx.containers.Canvas;	import mx.controls.Button;	import mx.controls.DataGrid;	import mx.controls.Label;	import mx.controls.dataGridClasses.DataGridColumn;	import mx.controls.dataGridClasses.DataGridListData;	import mx.controls.listClasses.BaseListData;	import mx.controls.listClasses.IDropInListItemRenderer;	import mx.core.ClassFactory;	public class renAddEditButton extends Canvas implements IDropInListItemRenderer	{		private var _btnEdit:Button;		private var _label:Label;		private var _listData:DataGridListData;				public function renAddEditButton()		{			super();		}				override protected function createChildren():void		{			super.createChildren();			this.horizontalScrollPolicy = "off";						_label = new Label();			addChild(_label);			_btnEdit = new Button();			_btnEdit.styleName = "btnEditColumn";			_btnEdit.visible = false;			addChild(_btnEdit);						_btnEdit.addEventListener(MouseEvent.CLICK, hBtnClick);						this.addEventListener(MouseEvent.MOUSE_OVER, hRollOver);			this.addEventListener(MouseEvent.MOUSE_OUT, hRollOut);		}				override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void		{			super.updateDisplayList(unscaledWidth, unscaledHeight);			_label.width = unscaledWidth-21;			_label.x = 3;			_label.y = 2;			_btnEdit.x = unscaledWidth-18;		}				private function hBtnClick(e:MouseEvent):void		{			var dg:DataGrid = DataGrid(listData.owner);			dg.editable = true;			dg.editedItemPosition = {columnIndex:1, rowIndex:listData.rowIndex};			trace("aa");		}				private function hRollOver(e:MouseEvent):void		{			_btnEdit.visible = true;		}				private function hRollOut(e:MouseEvent):void		{			_btnEdit.visible = false;		}				public function set listData(value:BaseListData):void		{			_listData = DataGridListData(value);			_label.text = listData.label;		}				public function get listData():BaseListData		{			return _listData;		}			}}


복잡해보이지만 별건 없다.
데이터 그리드의 아이템 랜더러를 사용하기 위해서 IDropInListItemRenderer를 구현한다. 저 인터페이스가 요구하는건 데이터 그리드의 listData를 엑세스 하기 위한 getter/setter 뿐이다.

기본흐름

createChildren을 override 해서 버튼과 라벨을 만들어준다.
updateDisplayList 에서는 위치를 잡아주고
데이터 그리드에 오버 했을때 버튼이 나타나도록 하기 위해서 해당 이벤트 핸들러를 등록한다.
랜더러 안에 있는 버튼을 클릭했을때 해당 데이터 그리드의 참조를 획득해서 editable = true 로 세팅해주고 이전 소스에서 나왔던 Datagrid.editedItemPosition 을 사용해서 해당 셀을 에디트 가능 상태로 만든다.

DataGrid 에는 itemEditEnd 이벤트를 걸어주고 아이템이 수정이 끝났을때 editable = false 로 다시 세팅해준다.

메인 mxml 부분의 스크립트를 보자.

import mx.events.CollectionEvent;import mx.collections.ArrayCollection;import mx.events.ListEvent;[Bindable]private var acData:ArrayCollection;private function init():void{	acData = new ArrayCollection(csData.node);	acData.addEventListener(CollectionEvent.COLLECTION_CHANGE, hCollectionChange);}private function hCollectionChange(e:CollectionEvent):void{	if(e.kind == "update")	{		if(e.items[0].property == "name")		{			trace(e.items[0].newValue);		}	}}


dataProvider로 사용하는 ArrayCollection 에 CollectionEvent를 받을수 있는 이벤트핸들러를 등록한다.
CollectionEvent는 ArrayCollection이나 XMLListCollection 같은 ListCollectionView를 구현하고 있는 넘들의 데이터의 변화 상황을 알려준다.

Inheritance : CollectionEvent Inheritance Event Inheritance Object

The mx.events.CollectionEvent class represents an event that is dispatched when the associated collection changes.

CollectionEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false, kind:String = null, location:int = -1, oldLocation:int = -1, items:Array = null)

아이템이 수정이 완료 되고 데이터 프로바이더에 반영되고나면 CollectionEvent가 발생하게 되고 이걸 캐치 하게 되면 수정사항이 반영된 ArrayCollection에 접근할 수 있다.

CollectionEvent.COLLECTION_CHANGE 이벤트의 핸들러인 hCollectionChange 함수에서 이벤트의 kind 를 확인 해서 업데이트가 된것인지 삭제가 된것인지등의 컬렉션의 변화 사항을 체크 한다.

e.kind 의 값은 "add", "update", "remove" 가 있고 update 일 경우 items 값은 mx.events.PropertyChangeEvent 가 된다.
정석으로 하려면 e.items 를 PropertyChangeEvent로 캐스팅 하고 거기에서 kind 값을 다시 받아서 "update"인지를 확인 하고 해야겠지만.. 어차피 이 데이터 그리드에서는 변경이 라벨 변경밖에 되지 않으니.. 그냥 0 으로 받고 변경된 property가 name 필드 인지만 확인 하는 정도로 하자.

trace(e.items[0].newValue);


에서 새로 입력된 값이 나오게 된다. 이 시점에서 디비에 수정된 사항을 업데이트 하는 정도로 구현하면 될것이다.

CollectionEvent는 이 경우 처럼 라벨을 수정하는 정도에서는 간단하게 처리가 되지만.
드래그앤 드랍이라던지. Tree에서 이용하기 위해서는 경우의 수가 많아진다.

따라서 그때는 CollectionEvent를 사용하지 않고 따로 업데이트 되는 시점을 체크 할 수 있는 방법이 필요하다.
드랍될때 데이터를 세팅한다거나 수정 할때 기본 itemEditor를 사용하지 않고 custom itemEditor를 사용해서 에디터 내부에서 변경된 값을 넘겨준다거나 하는 방식으로 하는것이 더 효율적일 수 있다.

하지만 CollectionEvent는 실제 작업을 할때 이용하지 않더라도 데이터 이동을 디버깅할때 여간 편하게 쓰이기 때문에 한번씩 사용해 보는것이 좋을 것이다.



ps.
이걸 만들면서도 뭔가 더 깔쌈한 방법이 있을꺼같은데 저정도 밖에 안되나 하는 생각이 들었는데. 좀더 나은 구현방법이 있으신분은 그냥 가지 마시고 꼭 댓글이나 트랙백을 달아주셔서 안목을 넓혀주셨으면 합니다.