Home >
When I was first learning Flex, I really struggled with using the component life cycle. I was really lucky, since I was asked to provide the "newbie eyes" for an article in Flex Authority magazine. I learned a lot from providing feedback on the article, but since I haven't done Flex work on a regular basis for several months, I recently ran into an issue with the Panel component that reminded me of a few of the finer points of the invalidation part of the life cycle. Often, articles on the life cycle focus on how everything works in an ideal world where the developer gets everything perfect the first time, but I thought it might be helpful to share an experience where I had to reason my way through the process in order to solve what at first seemed a puzzling bug.
Before I get started, I'd like to share my own personal take on writing a custom component. I'm going to focus on how I use the invalidation cycle, because it can potentially come into play any time you set a property on your component (or style, but for simplicity, I am going to look only at properties). The other parts of the component life cycle happen only once, so they are relatively easy to understand.
First, I nearly always use getter and setter functions for my properties, instead of variables. This enables me to set a flag that the property has changed and kick off the invalidation cycle. Here are my rules about what I do with the invalidation cycle based on what property has changed and how.
- If the property needs to change a property on a subcomponent, I call invalidateProperties() and override commitProperties()
- If the property needs to change something visual in the current component, I call invalidateDisplayList() and override updateDisplayList()
- If the property affects the size of the component, I call invalidateSize() and override measure()
In practice, this usually works out that the property change calls invalidateProperties() and the logic there determines if updateDisplayList() needs to run, which in turn will decide if measure() needs to run.
Let's look at my starting point logic for my custom Panel
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:Script>
<![CDATA[
private var _panelTitle:String;
private var _panelTitleChanged:Boolean;
public function get panelTitle():String {
return _panelTitle;
}
public function set panelTitle(value:String):void {
if (value != _panelTitle) {
_panelTitle = value;
_panelTitleChanged = true;
invalidateProperties();
}
}
override protected function commitProperties():void {
super.commitProperties();
if (_panelTitleChanged) {
title = 'Panel ' + _panelTitle;
_panelTitleChanged = false;
}
}
]]>
</mx:Script>
</mx:Panel>
If you use it in this Application
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:view="com.magnoliamultimedia.view.*"
layout="vertical" width="100%" height="100%">
<view:TitlePlusPanel panelTitle="foo" width="300" height="200" id="myPanel" />
<mx:Button label="Change title" click="{myPanel.panelTitle='bar'}" />
</mx:Application>
what you get is a panel that looks like this:
When you click the button, it looks like this:
Clearly, the visual display of the changed panel title is lagging behind what I'm expecting.
So let's open the debugger and see what we can figure out about why this is happening. I'm going to put a break point on the line where I set the title property on the panel component and step through.
So it looks like all my custom variables are set correctly. Let's press the "step over" buttonand see whether the title property on the component is set correctly.

You can see that the Title variable contains "Panel foo," but I'd like to call your attention to the "titleTextField" protected property (the yellow icon signifies that it is protected) of the Panel class. If we open that up, we can see that its text property is still an empty string.
The titleTextField is a property of the Panel component, but it is also a subcomponent of Panel, a UITextField. Thinking back on how I write components myself, I am reminded that I set subcomponent properties in commitProperties. In writing my first draft of the logic, I was starting from the premise that my logic should be after the existing commitProperties() logic. But once I got deeper into how the Panel component is written, I could see that the Panel component was written in the way I like to write components myself—the properties on subcomponents are being set in commitProperties(). The main problem is that I was providing the information needed to change the component properties after the logic that should have changed them had run.
This is a relatively trivial example, but I think that looking at what the potential solutions for the problem are can help shed light on what to do in a situation which is not trivial.
- Instead of manually setting the title using a setter and commitProperties(), just go with a single bindable public variable, and bind the panel title to 'Panel ' + panelTitle. This has the advantage of simplicity—you can eliminate the override of commitProperties()—but of course winds up with the extra overhead of using binding. In addition, sometimes it's not possible (or at least easy) to bind to some things, like for instance a property of an object not defined as bindable.
- Set the title property directly in the setter function, again eliminating the commitProperties() override. Since the title property is a getter/setter pair and uses the invalidation cycle itself, this appears to be a good option. However, this approach can have a couple of disadvantages:
- If your component is being used as an item renderer, the subcomponent whose properties you are trying to set might not exist when the setter is called. The fact that the Panel component uses the invalidation cycle will insulate you from problems in this instance, but it's not a good habit to get into.
- Sometimes you need to look at a combination of several custom properties in order to determine what the property on the subcomponent should be set to. There is no way to know what order the properties will be set in. If you defer processing until commitProperties(), you can be sure that any properties that are going to be set have been set.
- Move the logic for setting the title property so that it runs before super.commitProperties(). This has the advantage that it is going to be useful in a broader variety of situations than the other options, but it is less intuitive, especially if there are less experienced developers on your team.
What would you choose?




Facebook Application Development
I'd move the super.commitProperties() call to be after I change any subcomponent properties, since in this case the title property belongs to the superclass. I think.. I'm still fairly new to the UIComponent lifecycle, and its not exactly intuitive.
"In practice, this usually works out that the property change calls invalidateProperties() and the logic there determines if updateDisplayList() needs to run, which in turn will decide if measure() needs to run."
The intended order of validation is commitProperties(), followed by measure(), followed by updateDisplayList(). The reason for this is because the parent component needs to know the measured size before it can set unscaledWidth and unscaledHeight through setActualSize(), and these variables are used in updateDisplayList().
I did say it had been several months since I did Flex regularly :-). Thanks for your comment
Hi,
you can also call invalidateSize and invalidateDisplayList directly in your setter. In this way you gain a validation cycle. You can also invalidate on the textefield itself.
In my experience, using binding or setting the subcomponents properties directly in the setter will come back to bite you.
bye
Ariel