Lately, I've heard many complaints about horizontal scrolling performance in DataGrid. Vertical scrolling has been optimized, but horizontal has not. I found a bit of time to put together how to subclass DataGrid and try to optimize horizontal scrolling. I'm sure there's bugs and I don't know if I'll have time to fix them and the usual caveats apply.
Hope it helps. It should work with any Flex 3 SDK version.
In the example, the top DataGrid is not optimized, the bottom one is. Make the screen bigger and you'll start to see and feel the difference.

Hi Alex,
I got the following error while testing the bottom one.
TypeError: Error #1010: A term is undefined and has no properties.
at BetterDataGrid/scrollLeftOrRight()
at BetterDataGrid/set horizontalScrollPosition()
at mx.controls::DataGrid/scrollHandler()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()
at mx.controls.scrollClasses::ScrollBar/http://www.adobe.com/2006/flex/mx/internal::dispatchScrollEvent()
at mx.controls.scrollClasses::ScrollThumb/mouseMoveHandler()
--------------------
Alex responds:
I couldn't reproduce this exact stack trace, but I found and fixed a related bug that might fix this one as well. Examples and source were updated around 9:24PM PST
There's a problem with th ebottom one, I think - errors when I vertical scroll...
Jamie.
------------------
Alex responds:
I found and fixed one problem. The examples and source have been updated around 9:24PM PST
I sometimes get this error when scrolling in the bottom grid:
TypeError: Error #1010: A term is undefined and has no properties.
at BetterDataGrid/sumColumnWidths()
at BetterDataGrid/scrollLeftOrRight()
at BetterDataGrid/set horizontalScrollPosition()
at mx.controls::DataGrid/scrollHandler()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()
at mx.controls.scrollClasses::ScrollBar/http://www.adobe.com/2006/flex/mx/internal::dispatchScrollEvent()
at mx.controls.scrollClasses::ScrollThumb/mouseMoveHandler()
I'm using FlashPlayer 10 (debug version). I'm not really sure how to reproduce this, though.
-------------------
Alex responds:
OK, I'll look into it
Thanks for putting this together. It is much appreciated!
What would it take to get this working with the AdvancedDataGrid? I think some of the methods referenced are a little different, but I've got a fairly massive AdvancedDataGrid that is having some scrolling problems.
---------------------------
Alex responds:
AdvancedDataGrid is a different team, but I took a quick look at their code and this example might just work as is
Did you find the solutions?
TypeError: Error #1010: A term is undefined and has no properties.
at BetterDataGrid/scrollLeftOrRight()
at BetterDataGrid/set horizontalScrollPosition()
at mx.controls::DataGrid/scrollHandler()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()
----------------------
Alex responds:
I posted new code a few days back. If you still have this problem, provide some info as to how you got it.
Hello, Alex!
Excellent example, thank you.
Vertical scrolling may have been optimized but I feel there is room for improvement by providing smooth vertical scrolling instead of jumping from one row to the next. Hopefully this is a feature that is getting some attention.
---------------------
Alex responds:
Vertical scrolling should be pixel based in Gumbo
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.controls.dataGridClasses::DataGridBase/addToFreeItemRenderers()
at BetterDataGrid/shiftColumns()
at BetterDataGrid/scrollLeftOrRight()
at BetterDataGrid/set horizontalScrollPosition()
at mx.controls::DataGrid/scrollHandler()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()
at mx.controls.scrollClasses::ScrollBar/http://www.adobe.com/2006/flex/mx/internal::dispatchScrollEvent()
at mx.controls.scrollClasses::ScrollThumb/mouseMoveHandler()
How to reproduce:
----
Hold mouse on vertical scroll, and do some scrolling. Then, (Don't up mouse button, before you'll be on horizontal scroll bar), try to scroll horizontally. Try to do it so fast as possible :)
There's 2 exceptions, but I think source is same.
-------------------------
Alex responds:
Ok thanks.
Alex- What approach would you recommend taking in optimizing the AdvancedDataGrid hScrolling?
---------------------
Alex responds:
The code might work if you subclass ADG instead of DG. Give it a try and let us know
Sorry I should have mentioned that I had done that already. There are a few protected methods in the DG that are not available in the ADG
setupColumnItemRenderer layoutColumnItemRenderer
Also sub classing the ADG, there is no direct access to the header object.
I believe the above methods as well as the header object are fully encapsulated before the ADG class. However i am looking into
override mx_internal function getHeaderInfo(col:AdvancedDataGridColumn):AdvancedDataGridHeaderInfo as a possible way to get the header info yet that still leaves the rendering methods unavailable.
----------------------
Alex responds:
I don't have time to look into it right now. Post on Sameer Bhatt's blog and see if he can help you.
Alex,
Thanks for this fantastic component. I found a bug that you can easily replicate if you make the number of rows less than the vertical visible area. The "null" rows that fill the remaining area under the rows with data create a problem during the addToFreeItemRenderers call. There was a post above with a similar error from Sven. The error is:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.controls.dataGridClasses::DataGridBase/addToFreeItemRenderers()
at BetterDataGrid/shiftColumns()
at BetterDataGrid/scrollLeftOrRight()
at BetterDataGrid/set horizontalScrollPosition()
at mx.controls::DataGrid/scrollHandler()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()
at mx.controls.scrollClasses::ScrollBar/http://www.adobe.com/2006/flex/mx/internal::dispatchScrollEvent()
at mx.controls.scrollClasses::ScrollThumb/mouseMoveHandler()
------------------------------
Alex responds:
OK, thanks. Not sure when I'll get to it. Feel free to post your solution.
Alex,
Thanks for your great work!
I got a Error #1009 message with your example. When I try to move the vertical scrollbar to the end, and then move the horizontal scrollbar to left. This error message occurred. I found the problem might be caused by the source code BetterDataGrid.as in line 104. I just replaced it with 'var rowCount:int = rowInfo.length - 1;'. So far, it works fine!
--------------------
Alex responds:
OK, thanks!
Hello Alex,
Thanks for putting this example together, the performance improvements are remarkable. I thought I'd share a number of small fixes I've added:
1. as some previous posters noted, 'null' renderers in empty rows cause an error #1009 to be thrown. I fixed this with these handful of lines in scrollLeftOrRight():
if (scrollUp)
{
...
for (i = 0; i {
numCols = listItems[i].length;
if(numCols == 0) //empty row
continue;
...
}
...
for (i = 0; i {
if(iterator == null || iterator.afterLast || !iteratorValid)
continue;
...
}
}
else
{
...
for (i = 0; i {
numCols = listItems[i].length;
if(numCols == 0)
continue;
...
}
...
for (i = 0; i {
if(iterator == null || iterator.afterLast || !iteratorValid)
continue;
...
}
}
The solution posted by another reader (changing line 104 to 'var rowCount:int = rowInfo.length -1;') gets rid of the errors, but also causes the last row to not be updated correctly when scrolling.
2. When the first itemRenderer of a row is freed via freeItemRenderer() (which happens when the rows get moved to the left), the listContent.visibleData entry for that row is deleted, which prevents the row highlight from rendering when the mouse cursor moves over a row. To fix this, I modified the shiftColumns() function as follows:
var uid:String = itemToUID(listItems[rowIndex][0].data);
for (var i:int = 0; i {
item = listItems[rowIndex].shift();
addToFreeItemRenderers(item);
}
//rebuild the listContent.visibleData map entry
listContent.visibleData[uid] = listItems[rowIndex][0];
3. The horizontal scrollbar doesn't get updated properly if the table contains variable column widths. This one-liner in set horizontalScrollPosition() fixed this for me:
// if the flag got tripped run our new technique
if (canUseScrollH)
{
scrollLeftOrRight();
configureScrollBars();
}
4. In some situations where there are columns of varying width, the (updated) value of visibleColumns.length can become smaller than deltaPos by time we get to scrollLeftOrRight(). For example, if you can currently see 10 narrow columns and the previous 10 columns are significantly wider such that only 2 fit at a time, then if you drag the scrollthumb over such that deltaPos = 3, the initial check passes (since deltaPos scrollLeftOrRight():
if(scrollUp)
{
...
}
else
{
numCols = listItems[0].length;
if(deltaPos > visibleColumns.length)
deltaPos = visibleColumns.length;
moveBlockDistance = sumColumnWidths(deltaPos, false);
...
}
5. This one I'm not actually sure if it's necessary, but I slightly modified the lines in scrollLeftOrRight() that toss excess columns so that the number of itemRenderers in a row always matches visibleColumns.length:
if(scrollUp)
{
...
for (i = 0; i {
...
//toss excess columns
while (listItems[i].length > visibleColumns.length) //instead of 'if'
{
addToFreeItemRenderers(listItems[i].pop());
}
}
}
else
{
...
for (i = 0; i {
...
//toss excess columns
while (listItems[i].length > visibleColumns.length) //instead of 'if'
{
addToFreeItemRenderers(listItems[i].pop());
}
}
}
It seems to run pretty robustly now. Hope this information is useful!
--------------------------
Alex responds:
Thanks!
Hi ALex,
I see one strange issue with your components.The issue is data of one column gettting REPLICATED on another column adjacent to it.Please have a look in to it as i am using this components in a critical application and my client was the performace.Now I became dependent on this componets. I will also create a sample to demotrate this defact and post to you.
To Reroduce it you have to put at least 100 object into dataptovider
------------------------
Alex responds:
These examples are unsupported. I cannot guarantee a fix. Others are using this component so maybe they can offer help. Try posting on an Adobe forum or FlexCoders.
Alex,
Thanks for this very interesting and useful component. Do you have donation count? I want to send you some money.
-----------------
Alex responds:
Currently, Adobe does not allow us to make extra money from our blog content. Go spend it on the needy.
Hi Alex,
thx for this example.
I tried to use your component, but unfortunately it doesen't work with variable DataGridColumns. I added the methode "configureScrollbars" posted by XinYu. But even this doesen't work reliable. The ScrollBar changes each time its width. If you scroll to right, it gets shorter and vice versa. I would be glad to get some advice ;)
--------------------------------
Alex responds:
Not sure what you mean by "variable" DataGridColumns. It is normal for the scrollBar to changes its thumb width depending on how many visible columns there are on screen.
Hi Alex,
The code you provided works great but if we have locked rows and try to scroll the grid horizontally, the grid messes up. The lockes rows stays still and unlocked rows only move. Can you please tell me how to fix this?
There is a separate container of locked rows. You'll have to perform the same operatiosn on that other container.
Hi Alex
Could you please guide me a little bit more w.r.t code. I mean which container i should write the operation etc. I really appreciate your help in this regards.
The other container should be lockedRowContent
Hi Alex,
First, thanks for this great code. I was able to to do a lot of work using this code as a starting point. Unfortunately, I have run into a problem. I recently upgraded to the 3.4 SDK and now when I run my datagrid, the rightmost column header (usually it is partially visible) is missing its title. I went back and ran your original source and see the same issue when I scroll to the last column. As one final confirmation, I compiled the code in 3.3 and the issue disappeared. Any ideas? Thanks in advance for any time or support you can give with this item.
In 3.4 header renderers are recycled. This means that you can no longer use the same DataGridColumn in two different DG's which the example does.
Hi Alex,
I've got the same issue as the Carlo's one.
To reproduce the issue, from your example:
1- I've just kept the 'BetterDataGrid' Datagrid with width="500"
2- I modified
private const NUM_COLS:int = 5;
3- I added :
for (j = 0; j {
cols[j] = new DataGridColumn("col" + j);
DataGridColumn(cols[j]).width = j*100;
}
If you run this test and scroll right one time, you will see the 'col3' headerText disappear.
Do you know how I can fix this bug?
Thanks a lot.
Try the 3.5 nightly builds.
It works fine with the 3.5 nightly builds !! Thanks a lot Alex!
Do you know if the horizontal scrolling optimization will be implemented in flex4?
Hi Alex,
We're using 3.2 sdk and we have detected serious performance problems with the Datagrid horizontal scrolling. Profiling the application, we can see a lot more itemRenderers created than needed. This problem is magnified as soon as more columns are added to the datagrid. Of course, itemRenderers are not being recycled correctly by the Datagrid.
I've also downloaded and tried the 3.5 nightly build with similar results.
So the question is: Is there any way to optimize this horizontal scrolling and reduce the number of item renderers created and make them recycle correctly and in an optimized way? In the profiling, I can see a correct number of DataGridListData instances created but always wrong and non-recyclable item renderers created, even using default of custom blank renderers extending from uicomponent. The point is, there should be equal number of item renderers than DataGridListData.
Alex, we all need a patch for this because Datagrid is so important in almost every project. I can live with coding custom uicomponents for my item renderers but I need a good recycling strategy on the sdk side.
What's your opinion?
Thanks in advance.
No changes for horizontal scrolling in DataGrid in Flex 4. After Flex 4, we'll work on a Spark-based DataGrid and hopefully have better scrolling then.
There can be more renderers that DataGridListData's. Some are kept off-screen for measurement or for scrolling. Shouldn't be more than one or two per column though, so if you're seeing continued growth, file a bug.
Make sure the renderers are as lightweight as possible.
Hi Alex,
I believe I big amount of people is waiting for a better and optimized Datagrid control since since years ago. I've seen so many bugs and performance complaints on this control that is hard for me to understand why Adobe has not already reacted on this issue.
It's not a workaround to code our item renderers from uicomponent and following optimized display rules if this control is not recycling them correctly. The number of renderer instances grows erratically depending on the columns and rows showed and we just can't do anything to fix it.
I really encourage you to put a great effort on the new spark components because it's so important that the core component set is light, secure and performant...
Thanks
It works, no error. Excellent work, thanks alot.
Hello Alex,
Is there any workaround for AdvanceDataGrid??? Please suggest if it can be resolve wit that.
Thanks,Vikram
AdvancedDataGrid is developed by a different team, but I would think that the same principles would apply to it.