I have a List component using multiple item renderers determined by the itemRendererFunction. When I set the data the first time, it works as expected. Then, when I set the data a second time with new data, it doesn't call the itemRendererFunction and tries to reuse the current renderers even though they don't match the data. Once I scroll, the function is called and the correct renderers are used. I tried calling invalidateDisplayList and such prior to setting the data, but that didn't fix the problem. Any ideas?
It turns out this is a Flex SDK bug. Peter DeHaan provided me with a workaround (re-setting the itemRendererFunction property after the dataProvider is set) and is filing it for a future release of the SDK.
Here's just some ideas:
Try invalidateProperties? Looking at the source I have a hunch it could be that, otherwise, perhaps just start calling every invalidate method you can find till you get the right one.
Another sorta hacky solution might be to take not of current scrolling position (via the scroller on the List) pass in a new array as dataprovider (which will definitely recreate the item renderers) then set the scroll position to the same as it was before the refresh.
Or you could abstract out the selection of the different item renderer into the item renderer itself. :/
FWIW: Here's the link to the Flex bug:
https://bugs.adobe.com/jira/browse/SDK-32018
Related
I have a spark List in which I am adding custom components manually (without an item renderer). Everything is working fine except when I add hundreds of items in the list (based on several calculations), the render time increases to several seconds.
My questions are:
Does flex automatically delay the rendition of components that are added to a list?
If not then, how can I tell the spark list to only render the components once everything is added.
I hope what I am asking makes sense. I am pretty sure the render time is increasing because I have quite a few components inside the custom component. I just need a simple answer to my questions.
One more thing to know is that,
ActionScript 3 runs on flash player based on even-driven. It means that if you run a chunk of code in blocking, anything else, including rendering, will not be executed until the code ends.
This design sometimes causes issues: If a developer adds too much job in one blocking function, the player looks frozen and unresponsive momentarily. (If the code is an infinite loop, it stops until the player detects and throws ScriptTimeoutError, or possibly forever.)
However, for your question, yes, anything will be delayed until the adding job is done. Flex components doesn't basically split the job automatically.
Flex components are rendered in the list according to the Flex lifecycle: http://help.adobe.com/en_US/flex/using/WS460ee381960520ad-2811830c121e9107ecb-7fff.html
There are two reasons your List may be running slow, your components may not be following the Flex lifecycle correctly and the second because virtual layouts are not enabled on your List.
First the hard one:
Your first step should be to ensure you are following the correct phases in your custom components for commitProperties(), measure() and updateDisplayList(unscaledWidth:Number, unscaledHeight:Number).
So long as you are not calling any method named validateNow() on either your UIComponent subclasses or the LayoutManager then your components should follow this just fine.
The second may be that your list layout is not using virtual layout. This is enabled by default in a Spark List component but if you're overriding the layout you should ensure that useVirtualLayout is set to true on whatever layout you're using.
This is the property to enable it:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/components/List.html#useVirtualLayout
This is what it does to speed up rendering many items in a Spark DataGroup component (which a List is):
http://help.adobe.com/en_US/flex/using/WSc2368ca491e3ff92-1483ec4a12136246e76-8000.html#WS685c4ccbb85d340c6617851e121d4b8abae-8000
It's very very frustrating. I am using a singleton class (popup, which means it doesn't forget the last used variables) which contains a datagrid. I am making various columns visible/invisible, setting the widths and headers in accordance to data received from a database call. Everything works fine except that when I put the breakpoints before and after the point where I change width of columns, I do not see the change in width of datagrid at all! Instead I see some values totally out of sync as widths of datagrid column! However, since it is a singleton class, the next time I call this popup, I see widths which I did set up in last call.
I must be messing up in calling the setWidth() function (which is my custom function which changes the width of datagrid in action script). What should be the point where I should call this function? I tried in creationComplete, show and in the setter of dataprovider. Doesn't help...
I have kept horizontal scroll policy as 'off' (turning it on totally messes it up).
If I do datagrid.validateNow(), it doesn't help! And why the hell I don't see the width change reflected immediately if I put the breakpoints before and after the change. Somebody please advise me about what I am doing wrong here.
Thanks.
First of all you are indicating yourself what might be wrong here.
1) When you update the width when the component is visible => no change
2) When you close the popup and reopen this it is ok, this also means that the item has been re-rendered whereas it was not the first time. This means that you indeed have to try and trigger this yourself.
Here are some usefull links concerning flex component lifecycle. These should help you figure out which methods to call and / or override.
http://weblog.mrinalwadhwa.com/2009/06/21/flex-4-component-lifecycle/
http://www.slideshare.net/rjowen/adobe-flex-component-lifecycle-presentation
Furthermore, you should never call validateNow() directly, but use invalidation methods instead.
I guess in this case you need to trigger the measurement of your component so a call to
invalidateSize() should do just fine.
Cheers
The key is to set the horizontalScrollPolicy="on" before you set the widths. See
fixed row width in DataGrid quirk
or Flex 3 DataGrid Column Width Problem
I have a custom component as an item renderer.
In this renderer there is an item called dlFirstChoice.
Now when I add more items to this list and force the list to rebuild itself something odd happens.
Part of the creation of the renderer I set a default selection for the DropDownlist as follows: dlFirstChoice.selectedIndex=0
The problem is once I have more than one item to render from my dataset this property stops working.
So if my dataset has only 1 item to render the drop downlist sets itseld up properly, the momment I need to render more than 1 copy of my item renderer, all of a sudden nothing gets set for dlFirstChoice.selectedIndex. Its almost as if the namespace fails partially.
This is very odd behavior any ideas?
Please and thank you.
Craig
Turns out using DataChange is a very bad Idea, I moved my functions to creationComplete as the initilisiasing event then all of a sudden it took :)
Thanks for all those who looked or tried to help.
I have a List component from which I'd like to be able to remove items using drag & drop, but without having a specific target. If you use the mac, the behaviour I'm looking for is something like what the Dock uses; when you drag something out of the bounds of the control it should get an icon that indicates that it'll be deleted (OSX uses a cloud or something?) and then if you release it it will be removed from the list.
How can I do this?
(If I need to provide a more clear description, please comment; I'll fill in what I can)
In my experience with drag/drop in Flex, you cannot simply drag something out and handle that. There is no dragOut event (unfortunately), so that would leave you up to the task of writing dragOver and dragDrop listeners on all the containers surrounding your dragInitiator and handling the process accordingly.
It's more time consuming and can become complicated if any of these controls already have specific dragOver and dragDrop event handlers.
Hope this helps.
Having no Flex experience all I can offer is some psuedo code which resembles how I implemented a similar effect in JavaScript, but hopefully it will get you started.
Essentially what you'll want to do is during your drag event measure the current coordinates of the object you're dragging to see if they intersect the original container and when they fall outside of its bounds call the logic to update the icon in order to indicate it will be removed. Then, on the drop event, check the coordinates once more and delete the item if needed.
I have a DataGrid, populated with objects in an ArrayCollection. After updating one of the objects' fields, I want the screen to update. The data source is not bindable, because I'm constructing it at runtime (and I don't understand how to make it bindable on the fly yet -- that's another question).
In this situation, if I call InvalidateDisplayList() on the grid nothing seems to happen. But if I call invalidateList(), the updates happen. (And it's very smooth too -- no flicker like I would expect from invalidating a window in WIN32.)
So the question: what is the difference between InvalidateList and InvalidateDisplayList? From the documentation it seems like either one should work.
invalidateList tells the component that the data has changed, and it needs to reload it and re-render it.
invalidateDisplayList tells the component that it needs to redraw itself (but not necessarily reload its data).
invalidateDisplayList() merely sets a flag so that updateDisplayList() can be called later during a screen update. invalidateList() is what you want.
http://livedocs.adobe.com/flex/2/langref/mx/core/UIComponent.html#invalidateDisplayList()