Flex Examples: Adding invalidation to non-visual components

Problem: How do you implement invalidation in a non-visual class?

Solution: Use an instance of UIComponent to proxy the invalidation.

Explanation:
The invalidation mechanism in the Flex framework is a very powerful feature but in order to participate in it your class needs to extend UIComponent. Invalidation is a way to mark a components properties, size or display as dirty and then synchronize the updating of these. This is done in visual components that extend UIComponent by calling invalidateProperties, invalidateSize or invalidateDisplayList. The framework (or more precisely the LayoutManager) then handles calling the appropriate update methods. These calls are grouped so they are only called once on a component instance per screen update. To help with this UIComponent has a method named ‘callLater’ that lets you delay a method call until the next screen update. But how do you accomplish this when you class doesn’t extend UIComponent?

The answer is to simply create an instance of UIComponent and use it to proxy the callLater. I came across this method in the LayoutManager class while reading through the framework and at first I wasn’t sure how I liked it. Instantiating a UIComponent didn’t seem ideal but after thinking about it for a while and reading though the UIComponent class I decided that this is a really simple and easy solution. The trick to this is not to attach the UIComponent instance to the stage (don’t call ‘addChild’). If a UIComponent is created and not attached to the stage not much happens in it.

The reason this blog post came about is because I just ran into this problem and needed a solution. I am building a calendar component and decided to separate out the functionality of calculating the rows, columns and cells into a separate class. This Grid class is responsible for calculating the rows, colums and cells every time the size or row or column count changes (along with a few other properties). The problem I had was that since this was a non visual class I couldn’t use invalidateProperties to group these updates so each time a property changed the layout method is sometimes being called 4 times in a row. So I just borrowed the code from LayoutManager.

When a property gets set I call invalidateLayout

public function set columnCount(value:uint):void
{
if(isNaN(value) || value == _columnCount)
{
return;
}
_columnCount = value;
invalidateLayout();
}

The invalidateLayout and waitAFrame methods borrowed from LayoutManager

calendar_internal function invalidateLayout():void
{
if(!callLaterPending)
{
if(!callLaterObject)
{
callLaterObject = new UIComponent();
callLaterObject.systemManager = ApplicationGlobals.application.systemManager;
callLaterObject.callLater(waitAFrame);
}
else
{
waitAFrame();
}
callLaterPending = true;
}
}

private function waitAFrame():void
{
callLaterObject.callLater(layout);
}

Basically what this does is check if there is another call already registered and if not it checks if the proxy UIComponent has been created. This only gets created once. The callLater method in UIComponent needs to have systemManager set in order to work. The method that ultimately gets called in my case is ‘layout’. This method recalculates the rows, columns and cells. The ‘layout’ method also resets the ‘callLaterPending’ flag to false. The only problem I did run into with this is when the calendar component is first initialized the rowCount and columnCount properties are set in commitProperties and then the size of the gird is set in updateDisplayList. This causes the layout method in this class to get called twice. The way I fixed this is to put a conditional statement in the layout method to wait until the size of the grid is set before doing any calculations.

This solution works great in my case and it provides a simply way to add invalidation to non-visual classes.

Comments

Re: Flex Examples: Adding invalidation to non-visual components

Hi. Just being curious, isnt it more lightweight to use the already existing Application.application instead of instanciating a new UIComponent?

Re: Flex Examples: Adding invalidation to non-visual components

hmm.... interesting thought. I never think of using Application.application in that way. I don't see there being a problem with this since I am accessing the application object to get the systemManager anyways.

Thanks