Need Flex Migration Help?
- Adobe ends Flash player support in 2020
- Flex apps will no longer function
- We can help migrate your app
Notice we have now defined a variable called carProxy which holds an instance of the CarPreferenceProxy class (coming up next). This class takes an instance of our old CarPreferenceManager as a parameter to the constructor.
Now look at the Labels. Where we used to say carPrefs.getPreference(‘name’), we now say carProxy.name, in other words we are pretending that the old parameters to getPreference are now properties of our new CarPreferenceProxy object. You will see how to do this shortly. Also note the buttons, as opposed to calling the setDriver method of the CarPreferenceManager, we are now simply setting a ‘driver’ property on the CarPreferenceProxy.
The real work to make all of this possible happens in CarPreferenceProxy:
package components { import flash.utils.*; import mx.utils.ObjectProxy; import mx.events.PropertyChangeEvent; import mx.events.PropertyChangeEventKind; use namespace flash_proxy; /** * CarPreferenceProxy is a dynamic class, * meaning that its properties are not * necessarily all defined at compile time * and extends ObjectProxy **/ dynamic public class CarPreferenceProxy extends ObjectProxy { /** * manager variable stores an instance * of the CarPreferenceManager that is * passed in via the constructor **/ protected var manager:CarPreferenceManager; /** * PropertyMap is going to keep a simple * hashmap of properties that are requested * from this Object. There are several ways * to handle this. For our first example, * this is the most basic **/ protected var propertyMap:Object = new Object(); /** * Each time we attempt to read a property of * this dynamic class, the getProperty method * will be called * * So saying trace( carProxy.blah ) will call * getProperty with 'blah' as the name parameter. * When this method is called, it will check to * ensure we have a version of the * CarPreferenceManager to work with. * * If we do, we call the getPreference method * of this manager and retrun the result * * If we do not, we return a blank string for * now.... more on this later * * We also store the requested property in the * propertyMap, a simple hashmap object. Later * on we will use this map to update those * listening for a change rather efficiently. * If our CarPreferenceManager contains 5,000 * unique preferences, but our developers are * only listening for 5 of them to change, * we only deal with those 5 **/ flash_proxy override function getProperty(name:*):* { var prefValue:*; if ( manager ) { prefValue = manager.getPreference( name ); } else { prefValue = ""; } /** * There are several ways to approach saving the * object's properties. let's just keep it simple * and obvious for now **/ propertyMap[ name ] = true; return prefValue; } /** * Each time we attempt to assign a property of * this dynamic class, the setProperty method * will be called. So saying carProxy.blah=7; * will call setProperty with 'blah' as the * name parameter and 7 as the value. * * In a rather hackish way right now, we are * enforcing access control. We are only allowing * the developer to set a single property called * 'driver'. If they attempt to access any other * property, we throw an error. Yes, there are * better ways. * * When the name is 'driver', we call the * setDriver method of our manager. * * Afterwards we call a method called * updatePropertyListeners(). **/ flash_proxy override function setProperty(name:*, value:*):void { if ( name != 'driver' ) { throw new Error( 'Attempting to set inaccessible property of Object'); } else { if ( manager ) { manager.setDriver( value ); updatePropertyListeners(); } } } /** * After we set the driver, our CarPreferenceManager * has new values we can read. We are now going to * tell everyone listening for one of these preferences * to change, that they should re-read that value * * We do this by sending a PropertyChange event for * each preference that a control is bound to. * * Effectively, this tells each of those controls * through the magic of the framework to re-reread * the property. In this case, that will cause them * to call the getProperty method and hence * manager.getPreference() * **/ protected function updatePropertyListeners():void { var b:PropertyChangeEvent for ( var pref:String in propertyMap ) { dispatchEvent( PropertyChangeEvent.createUpdateEvent( this, pref, "", this[pref] ) ); } } /** * In our very simple constructor, we accept * a CarPreferenceManager which we will proxy. **/ public function CarPreferenceProxy( manager:CarPreferenceManager ) { this.manager = manager; } } }
If you haven’t read the comments in the above code yet, go do that now or this won’t make a bit of sense.
Using this class we glue together the extra logic needed to participate with the Flex framework binding. When the developer sets our driver parameter, we call setDriver in the CarPreferenceManager and then instruct all of the labels on the UI page to re-read their values. As each label attempts to re-read its fictitious property, we read the real value from the original manager and return it. The result is a seamless integration with Flex Databinding, regardless of the fact that the original manager class was never written to do so. How cool is that?
There is some ugliness here, and actually a small place where we hardcode a blank string instead of finding the old value (property change event), but it works as a starting point and in this circumstance. Going forward we will build on this idea to create simple lazy loading schemes and demonstrate a few other tricks and tips.
Code Enclosed. Now go show ObjectProxy love.
labriola Download
Best posting I’ve seen on this subject! I’ve been looking for the answer to my binding problems with ArrayCollections that contain objects for about four days. Thanks for the great work. Any idea when you’ll post the follow-up articles?
Hoping for sometime this week
Brilliant Mike. I can’t wait for the update!
Very nice article! Can’t wait next one))
By the way, why we couldn’t define CarPreferenceManager as singleton?
Thanks a lot!
Very interesting! Please post new updates (as promised 🙂 )
Really appreciates Michael Labriola for such to the point ObjectProxy example. Was searching something just like this, bindable ObjectProxy. Great example. Thanks!
One more thing is kicking into me with the provided demonstration, if the ‘CarPreferenceManager’ wouldn’t have any setDriver function, I guess this is only a SET function, if I’m not wrong? If in the case I’ve a totally dynamic object, which I’ve assined into the CarPreferenceProxy object, then Its possible I won’t have any GET SET function. , then how it would work with the data binding?
Santanu:
Look at the basic implementation for ObjectProxy. That is what it does. It proxies dynamic objects by default.
Mike