You want data binding to occur based on a custom event rather than relying on the default propertyChange event.
Set the event attribute of the [Bindable] metadata tag and dispatch an event by using that event string as the type argument.
The data-binding infrastructure of the Flex Framework is an event-based system. The default event type dispatched from a binding is the
propertyChange event. Internally, updates to destination property values are made without your having to dispatch this event directly from the source of the binding. You can specify a custom event type to be associated with a data-binding expression by using the
event property of the
[Bindable] metadata tag. For example:
[Bindable(event="myValueChanged")]
When you override the default event attribute within a
[Bindable] tag definition, you must dispatch the specified event in order for binding to take effect.
The following example uses custom binding events to update destination property values:
<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/mx">
<fx:Script>
<![CDATA[
private var _firstName:String;
private var _lastName:String;
private static const FN_EVENT_TYPE:String = "fnChanged";
private static const LN_EVENT_TYPE:String = "lnChanged";
private function submitHandler():void
{
firstName = fnInput.text;
lastName = lnInput.text;
}
[Bindable(event="fnChanged")]
public function get firstName():String
{
return _firstName;
}
public function set firstName( value:String ):void
{
_firstName = value;
dispatchEvent( new Event( FN_EVENT_TYPE ) );
}
[Bindable(event="lnChanged")]
public function get lastName():String
{
return _lastName;
}
public function set lastName( value:String ):void
{
_lastName = value;
dispatchEvent( new Event( LN_EVENT_TYPE ) );
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:BorderContainer borderStyle="solid">
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:HGroup verticalAlign="bottom">
<s:Label text="First Name:" />
<s:TextInput id="fnInput" />
</s:HGroup>
<s:HGroup verticalAlign="bottom">
<s:Label text="Last Name:" />
<s:TextInput id="lnInput" />
</s:HGroup>
<s:Button label="submit" click="submitHandler();" />
</s:BorderContainer>
<s:VGroup>
<s:Label text="You Entered-" />
<s:HGroup>
<s:Label text="First Name:" />
<s:RichText text="{firstName}" />
</s:HGroup>
<s:HGroup>
<s:Label text="Last Name:" />
<s:RichText text="{lastName}" />
</s:HGroup>
</s:VGroup>
</s:Application>
When a user submits entries for his first and last name, the
firstName and
lastName properties are updated. Within each respective setter method, the corresponding event defined in the
[Bindable] tags is dispatched to invoke updates on all destination properties.
A valuable aspect of creating customized bindable properties is that you can dictate when a destination property within the data-binding expression is updated. Because data binding is based on an event model, using customized binding affords you control over when or if the data binding is triggered.
The following example adds a timer to defer dispatching a bindable property event:
<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/mx"
creationComplete="handleCreationComplete();">
<fx:Script>
<![CDATA[
private var _timer:Timer;
private var _firstName:String;
private var _lastName:String;
private static const FN_EVENT_TYPE:String = "fnChanged";
private static const LN_EVENT_TYPE:String = "lnChanged";
private function handleCreationComplete():void
{
_timer = new Timer( 2000, 1 );
_timer.addEventListener( TimerEvent.TIMER_COMPLETE, handleTimer );
}
private function handleTimer( evt:TimerEvent ):void
{
dispatchEvent( new Event( FN_EVENT_TYPE ) );
}
private function submitHandler():void
{
firstName = fnInput.text;
lastName = lnInput.text;
}
[Bindable(event="fnChanged")]
public function get firstName():String
{
return _firstName;
}
public function set firstName( value:String ):void
{
_firstName = value;
_timer.reset();
_timer.start();
}
[Bindable(event="lnChanged")]
public function get lastName():String
{
return _lastName;
}
public function set lastName( value:String ):void
{
_lastName = value;
dispatchEvent( new Event( LN_EVENT_TYPE ) );
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:BorderContainer borderStyle="solid">
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:HGroup verticalAlign="bottom">
<s:Label text="First Name:" />
<s:TextInput id="fnInput" />
</s:HGroup>
<s:HGroup verticalAlign="bottom">
<s:Label text="Last Name:" />
<s:TextInput id="lnInput" />
</s:HGroup>
<s:Button label="submit" click="submitHandler();" />
</s:BorderContainer>
<s:VGroup>
<s:Label text="You Entered-" />
<s:HGroup>
<s:Label text="First Name:" />
<s:RichText text="{firstName}" />
</s:HGroup>
<s:HGroup>
<s:Label text="Last Name:" />
<s:RichText text="{lastName}" />
</s:HGroup>
</s:VGroup>
</s:Application>
The event type is still defined on the implicit getter for the
firstName attribute, but dispatching the event is deferred to the completion of a
Timer instance. If you run this program, data binding to the
lastName property will happen instantaneously as the custom event is dispatched within the setter method for that attribute. Updates on the binding destination of the
firstName property, however, are performed after 2 seconds because a
Timer instance is set to dispatch the custom event
fnChanged.
This recipe was originally contributed by Todd Anderson as part of O'Reilly's Flex 4 Cookbook.
+