Sometimes, when you build a Flex application, you encounter a compiler warning that says, “[Bindable] on a read-only getter is unnecessary and will be ignored.” If you’ve seen that message, and you’re curious what it means, hopefully I can explain it. In short, the compiler is telling you that it can’t actually make that property bindable because it has no way of determining when the property changes.
To understand that better, you should first know a little more about how binding works. Normally, when you make a getter/setter pair bindable, the compiler adds a little extra code for you. Behind the scenes, it dispatches PropertyChangeEvent.PROPERTY_CHANGE
to tell the binding system that your property has changed. Basically, it converts your property functions from something like this:
private var _example:String = "I am the very model of a modern Flex developer"; [Bindable] public function get example():String { return this._example; } public function set example(value:String):void { this._example = value; }
to this:
private var _example:String = "I am the very model of a modern Flex developer"; [Bindable("propertyChange")] public function get example():String { return this._example; } public function set example(value:String):void { this._example = value; this.dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE); }
If you don’t have a setter, there’s nowhere for the compiler to act smart and determine that your property has changed. If you want a getter without a setter to be bindable, you need to specify an event to be fired when the value returned by the getter changes. Your code should look something like this:
private var _example:String = "I am the very model of a modern Flex developer"; [Bindable("exampleChange")] public function get example():String { return this._example; }
Notice the inclusion of the event type in the metadata’s parentheses.
That’s only the first part, though. Next, you need to actually dispatch the exampleChange
event from somewhere in your code. For example, let’s say that we change the _example
variable when an URLLoader
returns a result:
private function urlLoader_completeHandler(event:Event):void { var loader:URLLoader = URLLoader(event.currentTarget); loader.removeEventListener(Event.COMPLETE, completeHandler); this._example = loader.data.toString(); this.dispatchEvent(new Event("exampleChange")); }
Any time you change _example
, you need to dispatch the exampleChange
event specified in the metadata so that the the binding system knows about what you did. If you set _example
in many different places, you might consider making a private or protected setter that sets _example
and dispatches that event, but that’s not required.
In summary, the compiler warning goes away when you specify an event type in the metadata. Simply specifying an event type won’t update bindings though, you also have to dispatch that event when the underlying variable changes. When the binding system receives your event, it knows to update any component to which your getter is bound.
One extra thing worth mentioning is that any property with Bindable metadata that has no event specified will dispatch the same generic propertyChange
event. This means the binding system will have to work harder than needed because it could receive the same event for many different properties. It’s a good idea to a create custom event for each property to avoid this limitation. You can see in the Flex framework source code that Adobe has separate events for most, if not all, bindable properties they create.
Pingback: [Bindable] on a read-only getter is unnecessary and will be ignored. – Josh Talks Flash | Enigmatic Thought
Not only does using a custom event name per property improve performance, it makes it trivial to add some [Event] metadata to your class or MXML document, and then you can trigger off property changes easily using events, without using the MXML binding synax or going through BindingUtil.
good works
I’m with Josh.
Everything you mark bindable should have a custom event that’s fired when the property changes.
To get around this problem I created a setter, but set it private. From an external class this property is still ‘read-only’, but the event does get fired implicitly by the [bindable] private setter function
@seanos I tried the method you suggested, having the getter as public and the setter as protected/private, but it seems that the setter’s namespace is overridden to public. As a result, the property isn’t read-only and I can change it from outside the class.
Here’s a good example of how to truly bind to a read-only getter.