I have created binding metadata called [TurboBinding], which provides performance advantage in addition to new features in comparison with the Binding metadata. To use the metadata, see the implementation example below (right click and select view source).

The code is maintained under eladlib code base.
Example of a simple tag:
[TurboBinding(destination="simpleText.text")]
Background
Data binding is one of the most used processes when building Flex applications. it allows rapid development of Flex applications. Data binding allows you to pass data between different layers of the application automatically and makes development of Flex applications easy, fast and enjoyable. As Data binding contain tremendous value, there is also disadvantages: without understanding exactly how data binding works and ensuring it is being used correctly, and when needed, data binding can create overhead and memory leaks, which will cause your application to suffer in terms of performance.
There are five techniques for using Data Binding:
- Using curly brackets in MXML tags
- Using the fx:Binding tag
- Using the BindingUtils class
- Implicit and explicit data binding
I am not going to expand too much about the techniques available to bind properties but you can pre-order a new book I am co-authoring that will have a whole chapter devoted to data binding and all the techniques in Flex 4: Amazon link.
The overhead can cause an application with thousands of Binding tags to choke for even half a second, which I will expand in more detail below. The alternative up until today was to use some of the other methods such as ChangeWatchers and BindingUtils class, however, they require management to avoid memory leaks and are not as easy as using the [Binding] metadata tag. Large Flex applications needs all the help they can get to get better performance and in my opinion, a half a second delay during initialization is not acceptable.
TurboBinding metadata
I completed an open source binding utility called [TurboBinding].
TurboBinding is a lightweight binding class with a speed close to the BindingUtils class but with the ease of setting your binding as a metadata tag, just as you do with the Binding metadata. Here’s an example of using the TurboBinding metadata tag:
[TurboBinding(destination="simpleText.text")]
Remove binding
In addition to performance gain [TurboBinding] provides additional functionality. For instance, let’s say you want to avoid memory leaks. since you don’t need to bind a property anymore, you can set the unwatchCounter property and it will remove the listener and avoid memory leaks. For instance, let’s say you are making a service call to retrieve customer information and once you receive the information you don’t need to bind anymore, you can set the unwatchCounter property to 1 and after the information is retrieved, it will clean up.
[TurboBinding(source="textInputOne.text", destination="textInputTwo.text", unwatchCounter=5)]
Two-way data binding
Data binding process allows tying one object data with another object. The concept of data binding is connecting a source object with a destination object and once the source object changes, the destination object changes automatically. Additionally Flex 4 offers a two-way data binding, which is also known as bidirectional which allows two objects to be tied to each other allowing data to be changed when either object changes.
In [TurboBinding] metadata I added the ability to bind two properties together. Add twoWay=”true” to add the two-way data binding. Note that once you use the twoWay property with unwatchCounter the binding will be removed from both binding instances.
[TurboBinding(source="textInputOne.text", destination="textInputTwo.text", twoWay="true", unwatchCounter=5)]
public function callBackFunction(newValue:String):void
{
trace(newValue);
}
Call back method
As you saw in the example before, I set a method next to the [TurboBinding] metadata. what it will do is call back the method once the change is recognized, which is a great feature for times when you want to do an additional task after binding.
Implementation example
To use the utility you need to call the setup method, since the code is not generated using the mxmlc as in the [Binding] tag. The examples below includes example of using the unwatchCounter property, which removes the binding after 5 times the data changes, simple data binding and two way binding for two text input.
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
minWidth="1024" minHeight="768"
creationComplete="TurboBinding.setup(this);">
<fx:Script>
<![CDATA[
import mx.utils.ObjectProxy;
import com.elad.framwork.binding.TurboBinding;
[TurboBinding(destination="btn1.label", unwatchCounter=5, callback="onPropertyChangeHandler")]
public var customer1:ObjectProxy = new ObjectProxy(new CustomerVO());
[TurboBinding(destination="btn2.label")]
public var customer2:ObjectProxy = new ObjectProxy(new CustomerVO());
[TurboBinding(source="textInputOne.text", destination="textInputTwo.text", twoWay="true", unwatchCounter=5)]
public function callBackFunction(newValue:String):void
{
trace(newValue);
}
public function onPropertyChangeHandler(val:String):void
{
trace("onPropertyChangeHandler:"+val);
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:Button id="btn1" label="change" click="customer1.customerID++" />
<s:Button id="btn2" label="change" click="customer2.customerID++" />
<mx:TextInput id="textInputOne" width="150" />
<mx:TextInput id="textInputTwo" width="150" />
</s:Application>
I used an open source test class created by Manfred Karrer and plugged in the [TurboBinding] tag and I am seeing some major performance gains. See results here:
Data Binding Using Curly brackets overhead
Why is using the binding tag in MXML is so performance costly? The binding tag is not magically happening. After opening the hood you will realize that there is a lot of overhead associated with this magic. Data binding using the curly brackets works since the Flex compiler and frameworks add code on your behalf. The code consists of:
- Generated code
- Event listeners and handlers
- Error catching
- Meta data
To understand how the magic works, you need to better understand how the compiler works. The compiler runs the compilation in two steps:
- mxmlc – the mxmlc compiler generates many action script classes
- compc – The compc compiler compiles the mxmlc
Generated classes and your classes to create a swf file.
These steps are not visible to you since these classes are not stored in your project, however, you can instruct the compiler to keep these files by adding a compiler argument –keep or –keep-generated-actionscript=true.
To take a look create a new project and call it; DataBindingUnderTheHood. Paste the following code:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
minWidth="1024" minHeight="768">
<fx:Script>
<![CDATA[
[Bindable]
private var text:String;
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:TextInput id="textInput1" text="@{textInput2.text}" />
<s:TextInput id="textInput2" text="{text}" />
</s:Application>
Select the project DataBindingUnderTheHood -> right click and select Properties. Under Flex Compiler in Additional compiler arguments add: –keep-generated-actionscript=true.
Under src/generated package you will find all the files that got created and are normally invisible to you.
Take a look at some of the code that gets generated to create the binding. _DataBindingUnderTheHoodWatcherSetupUtil class
// writeWatcher id=3 shouldWriteSelf=true class=flex2.compiler.as3.binding.PropertyWatcher shouldWriteChildren=true
watchers[3] = new mx.binding.PropertyWatcher("textInput1", { propertyChange: true } , // writeWatcherListeners id=3 size=1 [ bindings[2] ], propertyGetter);
// writeWatcher id=4 shouldWriteSelf=true class=flex2.compiler.as3.binding.PropertyWatcher shouldWriteChildren=true
watchers[4] = new mx.binding.PropertyWatcher("text", { textChanged: true, change: true }, // writeWatcherListeners id=4 size=1 [ bindings[2] ], null);
// writeWatcher id=0 shouldWriteSelf=true class=flex2.compiler.as3.binding.PropertyWatcher shouldWriteChildren=true
watchers[0] = new mx.binding.PropertyWatcher("textInput2", { propertyChange: true }, // writeWatcherListeners id=0 size=1 [ bindings[0] ], propertyGetter);
// writeWatcher id=1 shouldWriteSelf=true class=flex2.compiler.as3.binding.PropertyWatcher shouldWriteChildren=true
watchers[1] = new mx.binding.PropertyWatcher("text", { textChanged: true, change: true }, // writeWatcherListeners id=1 size=1 [ bindings[0] ], null);
// writeWatcher id=2 shouldWriteSelf=true class=flex2.compiler.as3.binding.PropertyWatcher shouldWriteChildren=true
watchers[2] = new mx.binding.PropertyWatcher("text", { propertyChange: true }, // writeWatcherListeners id=2 size=1 [ bindings[1] ], propertyGetter);
The mxmlc 4.0 compiler creates dataBindingUnderTheHood-generated.as and using IWatcherSetupUtil interface class and call the setup method which enableS data binding
if (_watcherSetupUtil == null)
{
var watcherSetupUtilClass:Object = getDefinitionByName("_DataBindingUnderTheHoodWatcherSetupUtil");
watcherSetupUtilClass["init"](null);
}
_watcherSetupUtil.setup(this,
function(propertyName:String):* { return target[propertyName]; },
function(propertyName:String):* { return DataBindingUnderTheHood[propertyName]; },
bindings,
watchers);
mx_internal::_bindings = mx_internal::_bindings.concat(bindings);
mx_internal::_watchers = mx_internal::_watchers.concat(watchers);
dataBindingUnderTheHood-generated.as also sets the binding through the mx.binding.BindingManager, which calls the UIComponent executeBindings to ensure binding is done through the life cycle of the component.
private function _DataBindingUnderTheHood_TextInput1_i() : spark.components.TextInput
{
var temp : spark.components.TextInput = new spark.components.TextInput();
temp.id = "textInput1";
temp.id = "textInput1";
if (!temp.document) temp.document = this;
textInput1 = temp;
mx.binding.BindingManager.executeBindings(this, "textInput1", textInput1);
return temp;
}
private function _DataBindingUnderTheHood_TextInput2_i() : spark.components.TextInput
{
var temp : spark.components.TextInput = new spark.components.TextInput();
temp.id = "textInput2";
temp.id = "textInput2";
if (!temp.document) temp.document = this;
textInput2 = temp;
mx.binding.BindingManager.executeBindings(this, "textInput2", textInput2);
return temp;
}
// binding mgmt
private function _DataBindingUnderTheHood_bindingsSetup():Array
{
var result:Array = [];
result[0] = new mx.binding.Binding(this,
function():String
{
var result:* = textInput2.text;
return (result == undefined ? null : String(result));
},
null,
"textInput1.text"
);
result[1] = new mx.binding.Binding(this,
function():String
{
var result:* = (text);
return (result == undefined ? null : String(result));
},
null,
"textInput2.text"
);
result[2] = new mx.binding.Binding(this,
function():*
{
return textInput1.text;
},
function(_sourceFunctionReturnValue:*):void
{
textInput2.text = _sourceFunctionReturnValue;
},
"textInput2.text"
);
result[2].twoWayCounterpart = result[0];
result[0].twoWayCounterpart = result[2];
return result;
}
/**
* @private
**/
public static function set watcherSetupUtil(watcherSetupUtil:IWatcherSetupUtil2):void
{
(DataBindingUnderTheHood)._watcherSetupUtil = watcherSetupUtil;
}
dataBindingUnderTheHood-binding-generated.as creates a class to behave as a wrapper for the UIComponent property.
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import mx.core.IPropertyChangeNotifier;
import mx.events.PropertyChangeEvent;
import mx.utils.ObjectProxy;
import mx.utils.UIDUtil;
import spark.components.TextInput;
class BindableProperty
{
/**
* generated bindable wrapper for property textInput1 (public)
* - generated setter
* - generated getter
* - original public var 'textInput1' moved to '_1559985460textInput1'
*/
[Bindable(event="propertyChange")]
public function get textInput1():spark.components.TextInput
{
return this._1559985460textInput1;
}
public function set textInput1(value:spark.components.TextInput):void
{
var oldValue:Object = this._1559985460textInput1;
if (oldValue !== value)
{
this._1559985460textInput1 = value;
this.dispatchEvent(mx.events.PropertyChangeEvent.createUpdateEvent(this, "textInput1", oldValue, value));
}
}
/**
* generated bindable wrapper for property textInput2 (public)
* - generated setter
* - generated getter
* - original public var 'textInput2' moved to '_1559985461textInput2'
*/
[Bindable(event="propertyChange")]
public function get textInput2():spark.components.TextInput
{
return this._1559985461textInput2;
}
public function set textInput2(value:spark.components.TextInput):void
{
var oldValue:Object = this._1559985461textInput2;
if (oldValue !== value)
{
this._1559985461textInput2 = value;
this.dispatchEvent(mx.events.PropertyChangeEvent.createUpdateEvent(this, "textInput2", oldValue, value));
}
}
}
As you can see the magic is actually a lot of code that the mxmlc creates and is an overhead that’s not always worth it. Creating one data binding using mxml code doesn’t make any difference in terms of performance, however, when you have a thousand binding tags in an application, it can cost you even half a second when the user starts the applications.
I am not saying that using data binding with the curly bracket is evil but you must be aware of the overhead and especially when creating applications that performance is important. This is the first round and hasn’t been tested fully so I consider the code beta. The TurboBinding class will be maintained under the eladlib library so you can keep track of changes there.























awesome! i just had an issue where i needed to “unbind” after the data was received once. this is great!
one problem with databinding i run into is binding the direct value to the target. what i need is to process and format the data before it it is passed to the target. for example, i have HTML being returned from a db. i need to run a few filters on it to replace certain tags flash can’t display and so on. there are some ways around it but in the graphics world you can apply a set of filters to an image in a non-destructive process. is there something like that possible in this class?
thanks
You can set a call back method through, by placing a method after the [TurboBinding] tag or add callback property. Once the results have changed you can filter the results.