June 24, 2007

Practicing Flex Binding

הנה טיוטת מצגת שכתבתי להבהיר את נושא ה-Binding והשימוש בו. מקווה שתמצאו את זה יעיל עבורכם (צר לי על האנגלית, זה נכתב לצרכי עבודה):

What is "Binding"?
Binding is a Flex mechanism that let us "bind" a property of any sort to a destination. The destination can be a control attribute, a setter function on so forth…

How do I implement binding?
There are 3 main methods to create binding relationships:
1. Use the curly braces inline of the control or object we wish to bind to a source.
2. Use the Binding tag which can enable us to bind many sources to one destination.
3. Use the BindingUtils.bindProperty() method which needs to manually be set. It creates a ChangeWatcher instance that can be used later to control the binding. This method is more elegant than using the ChangeWatcher directly, but basically does the same.

What triggers the Binding?
In the case of curly braces, what first triggers the Binding is the life cycle of the document, like so:

createChildren ()
createComponentsFromDescriptors ()
BindingManager.ExecuteBinding ()
Binding.execute ()

This is different when using the BindingUtils.bindProperty(). When using the BindingUtils.bindProperty(), it should be invoked within a method such as the control initialize phase. This method gives us more control on when to switch the Binding on.

What are the drawbacks of binding?
As apparent the benefits of the Binding mechanism are, there are some big drawbacks to this method of developing.
A lot of code is being executed behind the Binding mechanism and part of it is to prevent runtime exceptions from being thrown when not all the binding conditions are met. This fact mean that a lot of "if" and "try… catch" statements are made in the Binding.as and BindingManager.as classes to ensure that all is good for performing a valid binding process, here are some of the cases that fail silently when using Binding:

// Error #1006: Call attempted on an object that is not a function.
// Error #1009: null has no properties.
// Error #1010: undefined has no properties.
// Error #1055: - has no properties.
// Error #1069: Property - not found on - and there is no default value

Only when an error which is not one of the above occurs that an exception is thrown.
The most common error we get is when setting Binding with curly braces. What happens is the control has binding set to it before it was even initialized. The Binding mechanism tries to bind a property to a destination, but the destination is not valid since its owner (the control itself) is not yet fully created. This causes error #1009 - "null has no properties".
When the Binding mechanism reaches this error it stops from performing the binding but does not alert about it. When we have several properties bound like so, you can see how going through this "if" and "try… catch" statements can effect the application's performance.

What is the best practice for working with Binding?
The best practice is to use the BindingUtils.bindProperty() method when dealing with large components that need to render many objects according to the information received. In this manner we can control the instantiation of the ChangeWatcher to prevent as many "silent failures" as we can and later control it better (switching it on and off). This method also provides a better and more elegant access to setter methods using the bindSetter() method.
When dealing with simple controls attributes, such as Label's text and so on, using the curly braces (or Binding tag) should do fine but still we need to keep an eye on what happens behind the scenes.
Another thing to remember is that once a component is bound to properties, as long as it is alive, the binding will keep working within it even if the component is not visible (!). When dealing with components that draw much data this can mean a real performance slowdown to the application. What you need to do is make sure that once the component is not viewable, stop watching after the bound properties that relate to it. This is simply done using the ChangeWatcher.unWatch(). Since BindingUtils.bindProperty() creates an instance of ChangeWatcher this can be easily done. When the component is up and visible again we can reset the ChangeWatcher instance to the source again, and set the current value for the first time, retrieved from ChangeWatcher. getValue() method.

How to debug and monitor the Binding?
1. Debug the Binding.as and BindingManager.as. This is not very trivial to do since those classes are not reachable, so what you need to do is to set a break point on the control you're binding to and using the "drill down" option of the debugger, reach the classes mentioned above. Once there you can set break points to monitor methods entry points and such.
2. Use the BindingManager.debugBinding() method. Don't bother searching, this jewel is not documented and can't be reached. What it does is to output the errors the Binding Mechanism is throwing. You can look at it as a mere flag to whether trace or not. This method works only on binding with curly braces. What you do is call the method where the single argument is a string made of the control name and the destination within it, like so: BindingManager.debugBinding ("myTextControl.text");

1 comment:

Atarsh said...

אמנם בדיליי של ארבע שנים.. אבל תודה :)