CustomRowColorDataGrid component

In the last 2 projects I've worked on I've needed to change the background row color of items in the datagrid, based on values in the dataProvider.

However the flex DataGrid doesn't allow you to set the row color this way. Turns out in order to do this you need to extend the DataGrid and override the drawRowBackground() method and put your own logic in it. Not fun at all.

So to make it easier for myself, and you, I've abstracted this out in a way that make the new DataGrid re-usable, and I've added it to my growing collection of components that you can download from here.

[Download]

So the syntax to use this new grid is to write a new function, just like the ArrayCollections filterFunction. And the new DataGrid will call this function for every row it renders in the DataGrid, to get the right background row color.

The function signature needs to be this:

f(item:Object, defaultColor:uint):uint

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
   xmlns:mx="http://www.adobe.com/2006/mxml"
   xmlns:nimer="com.mikenimer.components.datagrid.*">

   
   
   <mx:Script>
      <![CDATA[
         import mx.collections.ArrayCollection;
         private function selectTypeColor(item:Object, color:uint):uint
         {
            if( item['type'] == "Warning" )
            {
               return 0xFFFF00;
            }
            else if( item['type'] == "Error" )
            {
               return 0xFF0033;
            }
            return color;
         }
      ]]>
   </mx:Script>

   
   <nimer:CustomRowColorDataGrid
      id="sampleGrid"
      rowColorFunction="selectTypeColor"
      width="100%" height="100%">

      
      <nimer:dataProvider>
         <mx:Array>
            <mx:Object type="Information" message="something good worked"/>
            <mx:Object type="Information" message="something else worked"/>
            <mx:Object type="Information" message="I like flex"/>
            <mx:Object type="Error" message="Opps, something didn't work."/>
            <mx:Object type="Warning" message="flex has a learning curve"/>
            <mx:Object type="Information" message="flex is fun"/>
         </mx:Array>
      </nimer:dataProvider>      
   </nimer:CustomRowColorDataGrid>
   
</mx:Application>

Comments
Jeremy's Gravatar well done, smart use of rowColorFunction, it's very flexible that way.
# Posted By Jeremy | 10/3/06 10:41 PM
Dreamer's Gravatar Great work!! I think I need it. Thanks very much.
# Posted By Dreamer | 10/4/06 8:52 PM
artfact's Gravatar how can i see the source of CustomRowColorDataGrid ? if possible...
# Posted By artfact | 10/6/06 4:42 AM
Vianney's Gravatar Hi,

It looks like a nice component, however i'm currently tying to use it with a XML dataprovider and i'm facing troubles !

Indeed the following :

<nimer:CustomRowColorDataGrid rowColorFunction="selectTypeColor" dataProvider="{memos.memos.memo}">
   <nimer:columns>
      <mx:DataGridColumn headerText="Capital" dataField="@value" width="450"/>
   </nimer:columns>
</nimer:CustomRowColorDataGrid>

Blows a nasty exception:

TypeError: Error #1009:
   at com.mikenimer.components.datagrid::CustomRowColorDataGrid/com.mikenimer.components.datagrid:CustomRowColorDataGrid::drawRowBackground()
   at mx.controls::DataGrid/mx.controls:DataGrid::drawRowBackgrounds()
   at mx.controls::DataGrid/mx.controls:DataGrid::updateDisplayList()
   at com.mikenimer.components.datagrid::CustomRowColorDataGrid/com.mikenimer.components.datagrid:CustomRowColorDataGrid::updateDisplayList()
   at mx.core::UIComponent/validateDisplayList()
   at mx.managers::LayoutManager/::validateDisplayList()
   at mx.managers::LayoutManager/::doPhasedInstantiation()
   at Function/http://adobe.com/AS3/2006/builtin::apply()
   at mx.core::UIComponent/::callLaterDispatcher2()
   at mx.core::UIComponent/::callLaterDispatcher()

It seems the problem comes from the mx:DataGridColumn but as you can see I can't do much debugging !

If you can help me on this one ...

Regards

Vianney
# Posted By Vianney | 10/6/06 5:02 AM
Nits's Gravatar Great work!

What I am trying to do is color specific cells at runtime, say, on a click of some item. Is there any way to achieve this?
Also, I am trying to do something else when the mouse rolls over a header cell. The itemRollOver() method does not recognize this as the 0th row, while itemClick() does. Any way to do this too?

Thanks in advance
# Posted By Nits | 10/6/06 12:18 PM
Mike Nimer's Gravatar Artifact, sorry about that I meant to zip up the source too. I've uploaded a new zip with the source, go ahead and download it again.
# Posted By Mike Nimer | 10/6/06 12:36 PM
Mike Nimer's Gravatar Vianny,
honestly, I have no idea. I just uploaded a new zip with the source can you grab that and use the debugger to find the bug. The code itself is very simple so it's probably just a question of adding an IS check somewhere.
# Posted By Mike Nimer | 10/6/06 12:39 PM
Mike Nimer's Gravatar Nits,
not sure, the trick is getting the datagrid to re-run the drawRowBackgrounds() again. Perhaps a call to invalidate display list will do it. Or setting the dataprovider to null and back to your dataset will do it too.

no idea about the itemclick and roll over. If you have a simple example I'll take a look. But this might be a better question for FlexCoders.
# Posted By Mike Nimer | 10/6/06 12:53 PM
Vianney's Gravatar Hi again,

I checked the source and I can't really find what i'm looking for,
do you think it is possible to use your components with a XML
dataProvider ? I mean have you tried ? And if so could you tell
me how you managed to do it ?

Thanks !

Vianney
# Posted By Vianney | 10/9/06 3:27 AM
Mike Nimer's Gravatar I'm sure it would work. I extended the datagrid and I haven't touched the dataprovider so technically there shouldn't be any problem. The error has to be something simple.

Can you post or email me a simple test case and I'll load up the debugger and take a look.
# Posted By Mike Nimer | 10/9/06 8:03 PM
Vianney Baron's Gravatar Hi again !

Here is a pretty simple case that fails dramatically:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; xmlns="*"
pageTitle="Dashboard" xmlns:nimer="com.mikenimer.components.datagrid.*">

<mx:XML xmlns="" id="myxml">
   <memos>
   <memo>
      <done>true</done>
      <date>06/09/2006</date>
      <subject>Testationnage</subject>
      <content>
      Blablabla
      </content>
   </memo>
   <memo>
      <done>true</done>
      <date>06/09/2006</date>
      <subject>Testationnage</subject>
      <content>
      Blablabla
      </content>
   </memo>
</memos>
</mx:XML>

<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
private function selectTypeColor(item:Object, color:uint):uint
{
   trace(item.toString());
if( item.done == "true" )
{
return 0xFFFF00;
}
else if( item.done == "false" )
{
return 0xFF0033;
}
return color;
}
]]>
</mx:Script>

<nimer:CustomRowColorDataGrid id="test" dataProvider="{myxml.memo}" rowColorFunction="selectTypeColor">
   <nimer:columns>
      <mx:DataGridColumn dataField="done"/>
      <mx:DataGridColumn dataField="date"/>
   </nimer:columns>
</nimer:CustomRowColorDataGrid>

</mx:Application>

Now it's strange since when i don't mention the rowColorFunction the datagrid populates perfectly...

I hope the mistake is on my side !

Thanks again.

Vianney
# Posted By Vianney Baron | 10/10/06 3:10 AM
Jari Huuskonen's Gravatar Excellent job. Just when I needed this.

Thanks again Mike.
# Posted By Jari Huuskonen | 10/10/06 2:54 PM
Jari Huuskonen's Gravatar Hello again,

One question about this. When I'm trying to refence some common properties of dataGrid with AS I keep getting compiler errors and am unable to compile ther project in Flex Builder. For example when trying to set:

myGrid.backgroundAlpha="0.15";

1119: Access of possibly undefined property backgroundAlpha through a reference with static type com.mikenimer.components.datagrid:CustomRowColorDataGrid.

If I put the same setting to nimer:CustomRowColorDataGrid, there is no problem.

Can you help on this?

Thanks,

Jari
# Posted By Jari Huuskonen | 10/10/06 4:27 PM
Mike Nimer's Gravatar I'll have to play with this, I've never seen it complain like this. But I bet it's a problem with the super class. I think that what is happening is that when you define the attributes via mxml, the compiler is smart enough to look in the extended class. However when you use actionscript it only looks in the immediate class. If this is the case, I'd say it's a flex bug.

It should be easy to workaround though. We just need to copy the metadata from the DataGrid into the CustomRowColorDataGrid. I'll give it a try and see if I can update the grid. (But it will be a few days). However in the mean time you can try it to. Grab the [Style...] metadata lines of code and copy them into my CustomRowDataGrid class. Hopefully the as error will go away.
# Posted By Mike Nimer | 10/13/06 9:50 AM
Kevin Ford's Gravatar I was having the same exact problem as Vianney, but I was getting my data provider from a ColdFusion CFC versus XML. I ran debug on the code and found the simple solution... it appears the function was trying to run before the dataProvider got populated. The fix was simply changing line 123 of the CustomRowColorDataGrid.as file from...

if( dataIndex < (this.dataProvider as ArrayCollection).length )

... to this ...

if( (this.dataProvider as ArrayCollection) != null && dataIndex < (this.dataProvider as ArrayCollection).length )

Thanks for the great component! This really helped me a lot!
# Posted By Kevin Ford | 10/18/06 12:57 PM
Mike Nimer's Gravatar Thanks Kevin!

I've updated the code/zip with this fix too. (the latest version is 1.0.4).
# Posted By Mike Nimer | 10/19/06 12:14 AM
Vianney Baron's Gravatar Thanks Kevin !

If anyone's interested I found another nice way to do this (definitly more code to write but it's code I understand hehe).
Here it is http://www.iepl.net/DataGridRowColorSample/DataGri...

Thank you all !

Vianney
# Posted By Vianney Baron | 10/19/06 2:44 AM
PaulH's Gravatar hey mike,

not sure if this is specific to your component (which is pretty slick & darned useful btw but if i try to set the scrollbar to the last added item in a datagrid (resultsPlaceHolder) ala:

resultsPlaceHolder.verticalScrollPosition=resultsPlaceHolder.dataProvider.length;

the row that's colored is thrown off by 1 (too high). i'm calculating some stuff off a map & throwing results into a nimer:CustomRowColorDataGrid & highlighting the summary rows. works a treat but if i try scrolling to the bottom w/the snippet above, the colored row is thrown off.

any ideas?
# Posted By PaulH | 10/27/06 12:07 PM
PaulH's Gravatar ah nevermind, rookie flex mistake about what verticalScrollPosition's units, etc. something like this works fine:

updateComplete="resultsPlaceHolder.verticalScrollPosition = resultsPlaceHolder.maxVerticalScrollPosition + 1;"

where resultsPlaceHolder is a datagrid.
# Posted By PaulH | 10/29/06 12:49 AM
R.G.'s Gravatar Hi!
I tried to understand your code and it seems quite sophisticated. i tried therefor to use the Code from Peter Ent.

http://weblogs.macromedia.com/pent/archives/2006/1...

But this does not work with me. i can not access the dataprovider as it is always null according to my Debugger, even when the output clearly shows data.

Can you perhaps try to explain also his approach to me? It seem to be easier, I just can not access th dataprovider, cast it to ArrayCollection and get the items out of it.
# Posted By R.G. | 11/1/06 3:31 AM
Mike Nimer's Gravatar I'm not sure how writting your own DataGrid extension is better then using mine, but whatever works is what matters. Just be careful not to hard code your business logic in the DataGrid itself (this is why I use a call out function).

As for you having a null dataProvider. Without a running example, there is not much I can do. I'm driving blind ;) Double check your code (case, scope, etc..) If the grid is populated the value can't be null.
# Posted By Mike Nimer | 11/1/06 1:16 PM
Victor's Gravatar Your approach to this little issue is just what I needed. In my case, the client wanted to be able to search the data in the grid and have all 'hits' highlighted. Here's my implementation of your code:
private var Hits:Array = new Array();

private function search() : void{
Hits.length = 0;
var myCursor:IViewCursor = dataGrid1.dataProvider.createCursor();
while(!myCursor.afterLast){
if(myCursor.current.name.indexOf(textCriteria.text) > -1 && textCriteria.text.length > 1)
Hits.push(myCursor.current);
myCursor.moveNext();}
if(Hits.length == 0)
Alert.show("No Matching Entries found");
dataGrid1.invalidateDisplayList(); }

private function selectTypeColor(item:Object, color:uint):uint{
if(Hits.indexOf(item) > -1)
return 0xEBEf80 ;
return color;}

In case anyone else needs :)
# Posted By Victor | 11/13/06 5:17 PM
anthony's Gravatar i have used this custom component together with victors search implemententation.

it works fine however i have noticed that the searches are case sensitive.

is there a way around this?
# Posted By anthony | 11/21/06 11:01 AM
Mike Nimer's Gravatar Not really, Flash is case sensitive. You need to .toLowerCase() the strings before the search
# Posted By Mike Nimer | 11/21/06 12:19 PM
Anthony's Gravatar could you provide an example where i could use the .toLowerCase() on a dataprovider e.g.

i have a datagrid with an array as the dataprovider which is called from a database and populatates the datafields name and email address.

how can i use the .toLowerCase on the name datafield even tho the dataprovider is an array?

sorry im still very new to flex2 and AS3 so any help provided would be of great use
# Posted By Anthony | 11/21/06 2:02 PM
Mike Nimer's Gravatar Technically you can't As you noticed the dataprovider is an array not a string, but the label for the item in the column is a string which you can use toLowerCase() on. Read up on the the labelFunction attribute of <mx:DataGridColumn labelFunction="">, I won't provide an code examaple here because that is just going to repeating the docs. But if you can't get it working let me know.
# Posted By Mike Nimer | 11/22/06 1:03 AM
prashant's Gravatar this control is quite useful.

i want to know how to assign color to particular cell in datagrid?

how to create custom tree control along with check-boxes ?

for each node there should one check box.
# Posted By prashant | 1/19/07 6:27 AM
Becky's Gravatar Thank you so much for this...it's exactly what I needed. You and others who give away these components are providing an invaluable resource to those who are learning Flex and creating real world applications.
# Posted By Becky | 1/19/07 4:01 PM
Mitch Aunger's Gravatar Mike, thank you so much for creating this! Met you in New Orleans at MAX - you've been a wonderful asset for Macromedia/Adobe!
# Posted By Mitch Aunger | 1/19/07 5:06 PM
chicky's Gravatar Mike, thank you so much for creating this
but when I use it,I have a problem, in my application the datagrid's dataprivode get by webservice,and when I use mx:datagrid,I can see the data when it run.
now I use this component,the page is white ,and I can't see other component on my pages.if this component can bind data with webservice?
# Posted By chicky | 2/8/07 4:17 AM
Mike Nimer's Gravatar There is no link between this this component and webservices. Data is data. I would double check the application is compiling right, and there are no errors buried. Delete everything in your bin folder and do a project->Clean->Build All.
# Posted By Mike Nimer | 2/8/07 10:41 AM
chicky's Gravatar thanks
I have resolved it!
# Posted By chicky | 2/8/07 8:26 PM
GM's Gravatar Mike, thanks for creating this..
I'm trying to get it to work within my app and running into problems..
I have this in my code:
      <comp:columns >
         <mx:Array>
            <mx:DataGridColumn width="150"
               headerText="Employee"
               itemRenderer="com.alltel.rapid.aopscheduler.renderers.WSNameCellRenderer" >
            </mx:DataGridColumn>
            <mx:DataGridColumn width="84" headerText="Sunday" >
               <mx:itemRenderer>
                  <mx:Component>
                     <mx:Label toolTip="{outerDocument.toolTipString}"
                        color="{data.sun.isAtAlternateLocation ? 0xFF0000 : 0x000000}"
                        text="{ data.sun.timespan }" />
                  </mx:Component>
               </mx:itemRenderer>
            </mx:DataGridColumn>
            <mx:DataGridColumn width="84" headerText="Monday" >
               <mx:itemRenderer>
                  <mx:Component>
                     <mx:Label toolTip="{outerDocument.toolTipString}"
                        color="{data.mon.isAtAlternateLocation ? 0xFF0000 : 0x000000}"
                        text="{ data.mon.timespan }" />
                  </mx:Component>
               </mx:itemRenderer>
            </mx:DataGridColumn>
         </mx:Array>
      </comp:columns>


when I use the rowColorFunction I get an error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.

Will this even work for me? I'm not using the array of Objects as in your example..

Thanks
# Posted By GM | 2/12/07 12:40 PM
GM's Gravatar my problem was the same as above...
Could you please adjust the code in the download to reflect the
if( (this.dataProvider as ArrayCollection) != null && dataIndex < (this.dataProvider as ArrayCollection).length )

from Kevin above? Thanks
# Posted By GM | 2/15/07 2:21 PM
Rostislav Siryk's Gravatar I guess the same tecnhique could be applied to the rest of list-like components:

- List
- HorizontalList
- TileList
- DataGrid, PrintDataGrid
- Tree
- Menu
# Posted By Rostislav Siryk | 2/17/07 10:06 PM
rxeno's Gravatar Hello... I am just trying to add an item sand then highlite that item in the resulting datagrip....

Do you know of a simple documentation to do this?
Thanks
# Posted By rxeno | 2/20/07 10:32 PM
goingflex's Gravatar Hi
I am reading through all these and since new to Flex am a bit lost.
My need is to colour datagrid rows at RUNTIME on user selection of certain conditions. I do not seem to understand how I can use a function to react as soon as a user clicks a button for example or selects an item in a List. I want rows in the dgrid be coloured if the data respond to cetain conditions.
Can you give me an example.

thanks to all.
# Posted By goingflex | 2/24/07 8:05 AM
Michael Fleet's Gravatar Vianney, Mike, et. al.,

I encountered the same problems as Vianney, Kevin and GM, and was able to fix them by first implementing Kevin's null-check, then by replacing all references to ArrayCollection with ListCollectionView. XMLListCollection and ArrayCollection both extend ListCollectionView. I have a feeling Vianney and GM have been using e4x like myself, which returns an XMLListCollection to the dataProvider, not an ArrayCollection.

Thanks for the tip!
# Posted By Michael Fleet | 3/26/07 5:33 PM
Anthony's Gravatar Hi mike,

is there a way to further extend this wonderful component to filter search results so that only the returned results are displayed on the datagrid. i have seen this example http://udayms.com/flex/cgrid/UseCustomGrid.html which uses the filtering method, however i find it quite difficult to implement becuase it does not extend the datagrid.
# Posted By Anthony | 4/1/07 1:21 PM
mike nimer's Gravatar You wouldn't want to extend a UI component to manipulate the data. Instead you want to use the FILTERFUNCTION property on the data provider (arrayCollection) object. If you modify the data provider this way the rows in the grid will show the new filtered results.

hth,
--nimer
# Posted By mike nimer | 4/2/07 3:32 AM
Randall Thomas's Gravatar Great example, but can a skin be used to highlight a row instead of a background color?
# Posted By Randall Thomas | 4/17/07 2:05 PM
Bryan Bartow's Gravatar Has anyone figured out how to apply this to the rollover instead of the background? I've been banging my head against a desk trying to figure out how to dynamically change the highlight color for each row based on data in the itemrenderer and can't seem to find an answer. Any help would be much appreciated.
# Posted By Bryan Bartow | 6/21/07 9:39 PM
Brian Burttram's Gravatar Hi Mike,

I'm trying to create a custom property editor, very similar to some of the older IDE's made by Borland and Microsoft. Basic premise was to use a DataGrid with the "property" column on the left, and the editable "value" column on the right. I've found how to change the background color of a column (using the backgroundColor property you've used here), however I haven't found a way to assign a CSS class to a particular column (or cell). Ultimately, I'd like to give each cell in the "properties" column a raised effect using this CSS, so that there is some separation between the rows. Have you run across this situation, and if so, how did you go about solving this?
# Posted By Brian Burttram | 8/15/07 12:10 PM
Max Zimet's Gravatar You didn't need to redefine drawRowBackground. I've created a component that does the same thing that yours does with 12 lines of code:

package comps
{
import mx.controls.DataGrid;
import flash.display.Sprite;

public class ColorDataGrid extends DataGrid
{
public function setColor(row:Number, color:Number):void{
drawRowBackground(Sprite(listContent.getChildByName("rowBGs")), row, this.rowInfo[row].y, rowInfo[row].height, color, verticalScrollPosition+row);
}
}
}
# Posted By Max Zimet | 9/15/07 1:24 AM
Mike Nimer's Gravatar Unless I'm reading your code wrong, moving this into the setColor method will change the bg color row once making all of the rows the same color.

However, using the rowColorFunction I added and having it called from the drawRowBackground() method let's you define a different color for each row - based on the actual data of that row at runtime. Which is why I needed to override the drawRowBackground() method.
# Posted By Mike Nimer | 9/15/07 7:58 PM
Max Zimet's Gravatar You are confusing drawRowBackground and drawRowBackgrounds. See the source code for DataGrid (http://tools.assembla.com/flexsdk/browser/mx/contr...). drawRowBackgrounds() draws all rows' backgrounds, while drawRowBackground draws 1 row's background. Notice that I pass it the row number that I want changed. This code is tested, so I know it works.

If you wanted the rows to auto-color based on the data, here's what you would do:

package comps{
import mx.controls.DataGrid;
import flash.display.Sprite;

public class ColorDataGrid extends DataGrid{
private var funct:Function;
public function set func(fun:Function):void{
this.funct=fun;
drawRowBackgrounds();
}
override protected function drawRowBackground(s:Sprite, rowIndex:int, y:Number, height:Number, color:uint, dataIndex:int):void{
if(funct==null){
super.drawRowBackground(s, rowIndex, y, height, color, dataIndex);
return;
}
var actualColor:Number;
var data:Object=dataProvider.source[rowIndex];
var genColor:Number=funct.call(this,data);
if(genColor==-1) actualColor=color;
else actualColor=genColor;
super.drawRowBackground(s, rowIndex, y, height, actualColor, dataIndex);
}
}
}

This way, the user can define a function that will say what the color should be for a row based on the row's data. This code has also been tested and works perfectly. This is a whole lot simpler than redefining tons of functionality.
# Posted By Max Zimet | 9/15/07 10:05 PM
Max Zimet's Gravatar Here's an example using this component:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; layout="absolute" xmlns:comps="comps.*" creationComplete="start()">
<mx:Script>
<![CDATA[
public function start():void{
cdg.func=colorSettor;
}
public function colorSettor:Function=function(data:Object):Number{
if(data==null) return -1;
if(data.Album=="Slanted and Enchanted") return 0xFF0000;
return -1;
}
]]>
</mx:Script>
<comps:ColorDataGrid id="cdg">
<comps:dataProvider>
<mx:Object Artist="Pavement" Price="11.99" Album="Slanted and Enchanted" SalePrice="true"/>
<mx:Object Artist="Pavement" Price="9.99" Album="Brighten the Corners" SalePrice="false"/>
</comps:dataProvider>
<comps:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
<mx:DataGridColumn dataField="SalePrice"/>
</comps:columns>
</comps:ColorDataGrid>
</mx:Application>

This too has been tested.
# Posted By Max Zimet | 9/15/07 10:15 PM
Mike Nimer's Gravatar >This is a whole lot simpler than redefining tons of functionality.
Ok I'm confused, how do you think I did it? What "tons of functionality" do you think I wrote? I have my component posted below - looks pretty simple to me. Besides, you're doing the exact same thing I do, so what are you talking about.

Also your countering yourself in your posts. First you say "You didn't need to redefine drawRowBackground" you can do it another way. BUT in your 2nd post shows that you've removed the setColor() function and you have redefined the "drawRowBackground" method and you are using a callback. Just like I do and just like your said not to in your 1st post. Did you change your mind?

Honestly, It's cool if you find a better way to do something, but telling me I did it wrong and then you post the same basic code as me - that's just wrong. Thanks for stealing my code and calling it your own.

Also with your first post you show a setColor() function on the datagrid itself. Which means to use it you need to call it from outside of your component. So outside of your component you need to loop over the array collection and call the function for each item in the dataProvider. This means that you DOUBLED the time it takes to render the datagrid. First the datagrid loops over the dataprovider and then you do again to set the colors. And what happens when the data in the grid is sorted? (this shouldn't work unless you loop over it twice again and call your setColor function for every row again,)

Overriding the drawRowBackgroud() method and using a callback, limits this looping to 1 time. But I see from your 2nd post that you've figured this out.

As you can see here my component also defines a call back function and overrides the drawRowBackground method. Here is the total code for my component. Notice, that it is the same logic your doing in your 2nd post. And I still don't see the "tons" of functionality you keep talking about. please elaborate.
-----------------------------
public class CustomRowColorDataGrid extends DataGrid
{
private var _rowColorFunction:Function;
public function set rowColorFunction(f:Function):void
{
   this._rowColorFunction = f;
}

public function get rowColorFunction():Function
{
   return this._rowColorFunction;
}

override protected function drawRowBackground(s:Sprite, rowIndex:int,
                        y:Number, height:Number, color:uint, dataIndex:int):void
{
   if( this.rowColorFunction != null )
   {
      if( (this.dataProvider as ArrayCollection) != null && dataIndex < (this.dataProvider as ArrayCollection).length )
      {
          var item:Object = (this.dataProvider as ArrayCollection).getItemAt(dataIndex);
          color = this.rowColorFunction.call(this, item, color);
      }
   }
       
   super.drawRowBackground(s, rowIndex, y, height, color, dataIndex);
}
}
-------------------------------
# Posted By Mike Nimer | 9/16/07 9:27 PM
Max Zimet's Gravatar First of all, I never said you did anything wrong. I didn't call your code bad. I'm simply trying to make a suggestion.

Secondly, when I wrote the first example I was thinking in the mindset of "You wouldn't ever need to change every color value and it is much more efficient to simply call 1 function once than to call it once for each row." Using this mentality, the client for this component would search through the dataProvider once, but the color function would only be called when the color would differ from the default. Later on you mentioned that you wanted each row's color to change based on the data in the row so I showed how you could, in less code, write a component that would do what you wanted.

Thirdly, when I said "tons of functionality" I was mistakened. After I had adapted my code to what you wanted I opened your source code and the little scroll bar on the right side of the window got really tiny (because of all of your comments) and I saw a bunch of imports (Shape, FlexShape, Graphics, AbstractEvent, ArrayCollection, Event) that I hadn't needed so I figured you had redefined the entire display for a DataGrid. To back up this assumption, I saw you had messed with updateDisplayList, which I hadn't needed to do. When I saw you had a pretty big file compared to mine, I didn't want to read through all of your source code. I simply wanted to tell you that there was an easier way.

Still, you did have some extra stuff that simply added to your file size. I just wanted to help.

Anyway, I understand if you think I stole your code because yours and mine do look very similar (although mine dropped some stuff with no functionality loss) and I won't blame you if you don't believe me when I say that I wrote my code myself and saw my file was way smaller than yours and posted it to help you out, because our files are so similar, but I did write my own code.

Lastly, your code includes much more that what you posted. Here's what the source in the zip file linked to at the top of this page says (comments removed):

package com.mikenimer.components.datagrid
{
   import mx.controls.DataGrid;
   import flash.display.Shape;
   import mx.core.FlexShape;
   import flash.display.Graphics;
   import flash.display.Sprite;
   import mx.rpc.events.AbstractEvent;
   import mx.collections.ArrayCollection;
   import flash.events.Event;

   public class CustomRowColorDataGrid extends DataGrid
   {
      private var _rowColorFunction:Function;
      
      public function CustomRowColorDataGrid()
      {
         super();
      }
      
      
      public function set rowColorFunction(f:Function):void
      {
         this._rowColorFunction = f;
      }
      
      public function get rowColorFunction():Function
      {
         return this._rowColorFunction;
      }
      
      
      
      private var displayWidth:Number;

      override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
    {
       super.updateDisplayList(unscaledWidth, unscaledHeight);       
         if (displayWidth != unscaledWidth - viewMetrics.right - viewMetrics.left)
         {
            displayWidth = unscaledWidth - viewMetrics.right - viewMetrics.left;
         }
    }
          override protected function drawRowBackground(s:Sprite, rowIndex:int,
                                    y:Number, height:Number, color:uint, dataIndex:int):void
    {
       if( this.rowColorFunction != null )
       {
          if( dataIndex < (this.dataProvider as ArrayCollection).length )
          {
             var item:Object = (this.dataProvider as ArrayCollection).getItemAt(dataIndex);
             color = this.rowColorFunction.call(this, item, color);
          }
       }
       
       super.drawRowBackground(s, rowIndex, y, height, color, dataIndex);
    }


This is 1 package declaration, 8 imports, 2 functions and 1 private variable more than what you posted. Did your link go to the incorrect version of your component, or did you realize that I was correct and that a lot of the code wasn't doing anything?
# Posted By Max Zimet | 9/16/07 11:17 PM
Mike Nimer's Gravatar Ok this is getting crazy, I appreciate the concept of posting a different way to do things. But what you posted was new functionality for a different use-case which is cool. Not something that "does the same that yours does ".

But next time you want to publically comment on other peoples code and start comparing line numbers (which is pointless, since it's the functionality that matters) make sure you really understand the code your commenting on. People can get defensive about their code (as I did).

Yea I have some extra imports, left over?s, that don't do anything (and don't matter). And I do have a straight copy of the updateDisplayList() function from mx:DataGrid - but that's because when I wrote this component I was running into one of those famous/annoying private scope conflict with updateDisplayList. That must of been fixed in the latest version of flex - which is why you didn't need it. This is also why I didn't include it - I only posted the code that mattered for this functionality.
# Posted By Mike Nimer | 9/17/07 2:26 AM
liuyang's Gravatar i love you Mike Nimer you help me too much!
# Posted By liuyang | 9/21/07 4:43 AM
Alistair's Gravatar Very handy. I have use this.
# Posted By Alistair | 10/2/07 3:25 AM
Min Storage's Gravatar Thanks so much.It's i need it.
# Posted By Min Storage | 10/7/07 4:40 AM
Nick's Gravatar Hi

Thanks for providing the source. It helped me to modify DG further.
# Posted By Nick | 2/10/08 9:06 AM
Mac's Gravatar Mike, great work.

I only wish I had stumbled across this 5 months ago. I search around quite a bit to find this functionality and found only a few partially related implementations. So, of course I had to write my own.

You can see it here: <a href="http://www.macsims.com/blog/?p=20">http://...;

I took basically the same approach that you did in extending DataGrid and overriding drawRowBackground. Because I wanted mine to work with any collection, not just ArrayCollections, I used a cursor to access the collection. There a few other minor differences, but you can look at the code if you are interested.
# Posted By Mac | 2/15/08 7:42 PM
Alex's Gravatar Hi Mike,

is it possible to change background color of an individual cell, not the whole row?

Thanks,
Alex.
# Posted By Alex | 3/7/08 6:22 PM
David's Gravatar Thank you so much for this. I works great and really
saved me time!
# Posted By David | 4/8/08 6:27 PM
fun's Gravatar thanks! It's funny what I thought was a simple function turns out to be almost a simple function. I'm not looking for the exact same behavior as CF, I was just using it as a reference since it does have this ability.

I'm going to update the blog and my util function with your function, since it is more accurate.
# Posted By fun | 4/14/08 12:58 AM
Relocation's Gravatar Thanks so much for this! This is exactly what I was looking for.
# Posted By Relocation | 5/8/08 6:41 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.001.