Over the past few years the Presentation Model Pattern has picked up a lot of traction in the Flex world as it allows for an abstracted representation of a views model and state which can easily be tested. Core to it’s implementation is the facilitation of data bindings between a PMs model and a corresponding View’s controls. Implementing data bindings between a view and its associated PM is quite straightforward when leveraging data binding in Flex – simply annotate a property, getter or class with [Bindable] metadata. A basic example of which can be seen as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class UserInfoPresentationModel extends EventDispatcher { private var _user:User = null; [Bindable(event="userChangeEvent")] public function get country() : String { return _user.location.country; } private function updateUser(value:User) : void { _user = value; dispatchEvent(new Event("userChangeEvent")); } // .... } |
Then a typical Flex data binding expression can be defined within a particular property of a control where the binding is to take place against the property of the Presentation Model instance:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <!-- Define the view bindings to the Presentation Model --> <?xml version="1.0" encoding="utf-8"?> <s:Group xmlns:fx = "http://ns.adobe.com/mxml/2009" xmlns:s = "library://ns.adobe.com/flex/spark" initialize = "init();" > <fx:Script> <![CDATA[ // Define the views presentation model instance [Bindable] private var _pm:UserInfoPresentationModel = null; privatefunction init() : void { _pm = new UserInfoPresentationModel(); } ]]> </fx:Script> <s:Label text="{ _pm.country}" /> </s:Group> |
As you can see this is quite simple and easy to implement. But how does one accomplish this without the use of Flex’s native data binding facility?
This may seem like a rather moot question as its hard to imagine why someone would choose to not take advantage of Flex data binding to accomplish synchronizing a view with its PM. However, just recently I found myself in need of a solution for this problem…
I have been experimenting with AS3 Signals lately as I find them to be a nice alternative to Flash Player Events. This especially makes sense in the context of Presentation Models as, at least in my experience, event Bubbling within the display list simply isn’t necessary when binding a component to a property of a PM. Furthermore, while I am not particularly biased against Flash Players event model, its implementation is very much a black-box, and AS3 Signals allows for a good level of abstraction and control of the Signaling mechanism. So I contemplated how this may improve a Presentation Models implementation and decided to see how Signals could be implemented with a PM; however I first needed to find a solution which would allow Signals to provide the same functionality as data binding.
Essentially, implementing “pseudo” data bindings with AS3 Signals can be accomplished much the same as can be seen in BindingUtils. I developed a SignalDataBinding
API which will feel somewhat familiar to those who have worked with BindingUtils in the past. SignalDataBinding provides an API allowing for the creation of pseudo data bindings within a Signal
against a property of a host object which is facilitated via the creation of runtime functions which are managed by the API.
For example, suppose you are using AS3Signals and wanted to bind a label’s text property to the value of another object. With the SignalDataBinding API this could be accomplished as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | // Define the object which utilizes the Signal messaging API public class TitleModel { private var _bindings:SignalDataBinding = null; private var _titleChanged:Signal = null; private var _title:String = null; public function get title() : String { return _title; } public function set title(value:String) : void { _title = value; _titleChanged.dispatch( value ); } // Model class provides an API for property specific // bindings while not exposing the underlying binding // mechanism, thus allowing the data binding facility // to be changed transparent to that of a client's // implementation. public function addTitleBinding(host:*, property:*):void { _bindings.addBindableListener(_titleChanged, host, property); } } |
Then, in the view from which the bindings are to be defined you would explicitly add bindings as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?xml version="1.0" encoding="utf-8"?> <s:Group xmlns:fx = "http://ns.adobe.com/mxml/2009" xmlns:s = "library://ns.adobe.com/flex/spark" initialize = "init();" > <fx:Script> <![CDATA[ // Define the views presentation model instance private var _pm:TitleModel = null; private function init() : void { _pm = new TitleModel(); // Add binding between the Model's 'title' // property and the views 'titleLabel.text' // property. Assignments to "title" will now // be reflected in 'titleLabel.text' _pm.addTitleBinding( titleLabel, "text" ); } ]]> </fx:Script> <s:Label id="titleLabel" /> </s:Group> |
And that’s basically it. Additional levels of abstraction could easily be defined in order to provide common base classes which encapsulate the SignalDataBinding instance etc. Additionally, I do not see any reason why the SignalDataBinding API could not be utilized in AS3 projects as well as Flash projects; for the underlying implementation has no dependencies on the Flex Framework. Thus the SignalDataBinding API could be leveraged in any AS3 project as is, or adapted to implement the Flash Player Event model to provide a BindingUtils implementation for AS3 and / or Flash Projects.
You can view a basic example as well as download the SignalDataBinding API source, docs and binary.