Wednesday, April 1, 2009

Reuse ItemRenderers for Multiple columns

When dealing with item renderers, one will come across all sorts of problems thrown at . One such case is "how to reuse the same itemrenderer"

Picture this case. You have a custom itemrenderer,( imagine a check box within a canvas for now) that performs a specific task and you want to reuse it on multiple columns. But how will the itemrenderer know which field in the arrayCollection is to be used to render itself appropriately?

Alright. Here is the trick.

There is this interface called IDropInListItemRenderer which your itemrenderer will have to implement to get access to listData which can be typeCasted to DataGridListData. The listData variable will hold reference to the owner of the itemRenderer and the hierarchy upwards. Following is the list of steps one has to follow.

1.Create the itemRenderer class that implements the IDropInListItemRenderer.

2.Create an instance variable to buffer the listData , namely _listData.

3.Override the set/get methods of the listData instance variable . In the setter, buffer the listData onto the instance variable

Ex:


private var _listData:DataGridListData;
public function set listData(value:BaseListData):void
{
_listData = DataGridListData(value);
}


Note:The importance of this step is that the itemrenderer can use the _listData variable to find out the name of the dataField , using something like _listData.dataField. Once the name of the dataField is acquire, the value for that datfield can be acquired by using data[_listData.dataField]

4.Override the updateDisplyList() method to update the status of the checkBox based on the value of the dataField.

Ex:

override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void {

super.updateDisplayList(unscaledWidth,unscaledHeight);
_instanceCheckBox.selected = Boolean(data[_listData.dataField]);
}

5. Create the datagrid and use the above created item renderer.
Ex:

<mx:DataGridColumn dataField="isMarried" itemRenderer="sampleItemRenderer"/>
<mx:DataGridColumn dataField="isAnimal" itemRenderer="sampleItemRenderer" />




Following is the complete code.

The view:

// View
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var dataP:ArrayCollection = new ArrayCollection(
[{isMarried:true, isAnimal:true,name:"Montgomery"},
{isMarried:false, isAnimal:true,name:"Juneau"},
{isMarried:true, isAnimal:false,name:"Little Rock"},
{isMarried:true,isAnimal:true,name:"Ricky Martin"}]);
]]>
</mx:Script>



<mx:DataGrid dataProvider="{dataP}">
<mx:columns>
<mx:DataGridColumn dataField="isMarried" itemRenderer="sampleItemRenderer"/>
<mx:DataGridColumn dataField="isAnimal" itemRenderer="sampleItemRenderer" />
<mx:DataGridColumn dataField="name"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>



The itemRenderer


package
{
import mx.containers.Canvas;
import mx.controls.CheckBox;
import mx.controls.dataGridClasses.DataGridListData;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.IDropInListItemRenderer;

public class sampleItemRenderer extends Canvas implements IDropInListItemRenderer
{
private var _listData:DataGridListData;
private var _instanceCheckBox:CheckBox = new CheckBox();
private var _currentDataFieldName:String = new String();
public function sampleItemRenderer()
{
super();
}

public function get listData():BaseListData
{
return _listData;
}

public function set listData(value:BaseListData):void
{
_listData = DataGridListData(value);
}
override protected function createChildren():void {
super.createChildren();
addChild(_instanceCheckBox);

}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth,unscaledHeight);
_instanceCheckBox.selected = Boolean(data[_listData.dataField]);
}
}
}

Hope it helps!



Bookmark and Share

16 comments:

David said...

I have been battling for the past 2 days trying to get my checkbox based ItemRenderer to update when the underlying data is updated by the application, without luck.

There are many other examples of creating a custom ItemRenderer but yours was the first one that mentioned overriding the updateDisplayList method. I added this to my code and it now works.

Thank you very much for posting this example.

Vengu said...

Glad am of help.

skrc said...

Hi thanks for the example, where are you located? can I contact you on mail?

Vengu said...

yes. Contact me at vencool@gmail.com.

I am from bangalore.

flagg said...

haaaa, thank you soo much! I had missed the point here and couldn't find how to do that!
thanks a lot!

B said...

Great stuff thanks

Pk said...

Hi,

Your column was very useful. I implemented a different item for each cell depending on the input data.

I am facing a slight problem though, I have different items (LinkButton, Image, Label) in the same column and when I try to scroll everything gets messed up, everything starts to get overlapped, have you faced this before,or any possible solutions that you could think of?

Vengu said...

PK,

Can you post/send your source code? I am not sure why its happening.

Pk said...

I have emailed you the source code.

Oo^sai^oO said...

Hello venki.. Thanks for the post man.. if i had not searched in google, i would had not found this(two days would had been wasted). Thanks once again..

washington DC new homes said...

I have been battling for the past 2 days trying to get my checkbox based ItemRenderer to update when the underlying data is updated by the application, without luck.

varun said...

hello please send me the source code varunkln@gmail.com

thanks

Fabian said...

hi friend, tanks a lot!! you really help me whit my proble adding a HSlider into an AdvancedDataGrid :)

RK said...

Had the same problem but solved it differently (and via MXML):













The only problem with your and my solution is that you can't use "chaining" as usual like: dataField="bla.blub.anotherprop" - although you could write a methode to do that for you

Anonymous said...

Hi is there a way to add event listeners to the check boxes so that when the user makes any selections (check/uncheck)we can capture the changes

Dany Dhondt said...

Brilliant!