Like today, at band camp I was trying my best to be a good Flex developer and use ChangeWatcher carefully to watch changes made to a public property. But, I could not for the life of me get it to work. After several hours of debugging and head scratching, I asked Twitter-verse and also some of my co-workers. One of them, (giving credit where credit is due) Jay Proulx made a comment that led me down the road to victory.
Before I go any further, let me clarify the problem. I had written a class with a very simple public property and annotated it with the [Bindable] metadata tag. However, as I normally do, I specified my own event. Being a good Flex developer, I typically follow this practice as shown below.
By specifying my own event type, the Flex compiler will not generate any binding code on my behalf. However, what I did not realize was that doing so would prevent my ability to use a ChangeWatcher to watch changes to this property (as shown below). The code that was attempting to watch changes to the “name” property was not causing a ChangeWatcher to do anything. Specifically, my event handler was not being invoked when the property was being changed. In summary, ThisClass was watching a property on ThatClass, but it wasn’t working and I could not figure out why.
I noticed that when I removed the event parameter in the metadata, suddenly my code began working (as shown below). But why?
I know that the Flex compiler generates code on my behalf when it encounters a [Bindable] metadata tag. An example of what it generates and compiles is shown below. Essentially, you can tell that the compiler renames the public property (and prefixes it with some unique value) and generates a public getter and setter.
The interesting code here is in the setter. The compiler generates code to conditionally dispatch a PropertyChangeEvent if the new property value is different than the original value. Fair enough, but why won’t the ChangeWatcher work when I have an event type in my metadata?
Before I tell you, have a look at my final solution.
After discovering what the problem is, I settled on this solution. It was a tad more work than I wanted, but it works. Personally, I would consider this a bug in the Flex ChangeWatcher code (mx.binding.BindabilityInfo to be specific).
It turns out that the ChangeWatcher code will only hookup a ChangeWatcher if the [Bindable] metadata tag is annotating an accessor (getter) or a method. In this case, the new code annotates the getter, which is an accessor. My original code did not work because the [Bindable] metadata tag was annotating a variable (not an accessor or method). And we already know that the compiler does not generate code on your behalf when you specify an event parameter in the metadata tag. Consequently, the ChangeWatcher that was created was not hooked up and didn’t respond to any changes made to the “name” property I thought it was watching. It was not watching.
In my opinion, the ChangeWatcher code should hook itself up properly whether the [Bindable] metadata tag is annotating a variable, accessor or method.
Make a mental note of this in case you run across it in your Flex travels. It might just save you a few hours of work.
For those of you that want to tell me that I shouldn’t use ChangeWatchers or that my sample code has holes in it, I already know this. I know the dangers of ChangeWatchers and I use them sparingly. I also know to unhook them when I’m done because not doing this potentially results in memory leaks. Feel free to leave me comments….unless you’re going to tell me about the evils of ChangeWatchers or that my sample code has all sorts of holes in it