14.9.绑定到一个动态类的属性

14.9.1. 问题
你需要绑定一个目标的属性到一个目标并不明确的动态类对象的一个属性上。
14.9.2. 解决办法
创建一个mx.utils.Proxy 的字类,实现mx.events.IEventDspatcher 接口,覆盖flash_proxy 名字空间的setProperty 方法,来分发propertyChange 事件。
14.9.3. 讨论
Proxy 类允许你使用点标语法来存取属性。为了能有效的与动态属性的引用进行工作,在你的子类的实现中重写flash_prox 名字空间中的方法getProperty 和setProperty。如果类中的这些方法被定义为共有的类,则你可以自定义来存取这些属性。然后,动态的属性引用不足以创建绑定,因为数据绑定是基本事件系统的。

因为绑定是通过事件来触发的,创建一个Proxy 类是适合来进行数据绑定的,你必须同时实现IEventDispatcher 以及它们的接口。为了使动态属性的引用能被进行绑定,类需要用关键字dynamic 来进行声明,同时使用[Bindable]标记来进行定义,且设置标签的event 属性值为propertyChange:
+展开
-ActionScript
[Bindable(event="propertyChange")]
dynamic public class Properties extends Proxy implements IEventDispatcher {}


一个不错的例子,当你需要创建一个自定义的Proxy 类用来存取一个从内部源加载的数据,通过在重载的setProperty 和getProperty 方法创建一定的规则,而不是去编写一个分析器,会填充属性在一个自定义的对象从加载的数据中。

例如,一个程序加载下面的XML 数据,且这些XML 数据的属性是能进行存取和修改的:
+展开
-XML
<properties>
<property id="name"><![CDATA[Tom Waits]]></property>
<property id="album"><![CDATA[Rain Dogs]]></property>
<property id="genre"><![CDATA[Rock]]></property>
</properties>

你可以创建一个mx.utils.Proxy 的子类,同时在重载的setProperty 和getProperty 方法中使用E4X,允许一个客户端来存取和修改XML 中的属性的值。
+展开
-ActionScript
override flash_proxy function getProperty( name:* ):*
{
return xml..property.(@id == String( name ) );
}
override flash_proxy function setProperty( name:*, value:* ):void
{
var index:Number = xml..property.(@id == String( name )).childIndex();
xml.replace( index, '<property id="' + name + '">' + value +'</property>' );
}

数据绑定的事件当一个属性的值被修改时会被触发。在这个例子中的重载的setProperty 方法,虽然它更新了一个属性的值,但是并没有分发一个更新的通知。为了能绑定到一个动态的属性引用上,你必须通过Proxy 子类分发一个PropertyChange 的事件。
+展开
-ActionScript
override flash_proxy function setProperty( name:*, value:* ):void
{
var oldVal:String = xml..property.(@id == String( name ) );
var index:Number = xml..property.(@id == String( name )).childIndex();
xml.replace( index, '<property id="' + name + '">' + value +'</property>' );
var evt:Event = PropertyChangeEvent.createUpdateEvent( this,
name,oldVal, value );
dispatchEvent( evt );
}

类PropertyChangeEvent 中的静态createUpdateEvent 方法返回一个属性被设置为propertyChange 的PropertyChangeEvent 的实例,propertyChange 是默认用来进行绑定的事件类型,被设置为这个类中[Bindable]的属性。

在接下来的例子中,是一个完整的Proxy 子类的实现,适合于进行数据绑定:
+展开
-ActionScript
package com.oreilly.flexcookbook{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.utils.Proxy;
import flash.utils.flash_proxy;
import mx.events.PropertyChangeEvent;
[Event(name="complete", type="flash.events.Event")]
[Bindable(event="propertyChange")]
dynamic public class Properties extends Proxy
implements IEventDispatcher{
private var _evtDispatcher:EventDispatcher;
private var _data:XML;
private var _loader:URLLoader;
public static const COMPLETE:String = "complete";
public function Properties(){
_evtDispatcher = new EventDispatcher();

// load external xml.
public function loadProperties( fnm:String ):void{
_loader = new URLLoader();
_loader.addEventListener( Event.COMPLETE, loadHandler );
_loader.load( new URLRequest( fnm ) );

// set data property and dispatch 'complete' notification.
private function loadHandler( evt:Event ):void{
data = XML( _loader.data );
dispatchEvent( new Event( Properties.COMPLETE ) );
}
public function get data():XML{return _data;}
public function set data( xml:XML ):void{_data = xml;
// use E4X to return property value held on xml.
override flash_proxy function getProperty( name:* ):*{
if( _data == null ) return "";
else return _data..property.(@id == String( name ) );
}
 // use E4X to modify property value on xml. Dispatch'propertyChange'
override flash_proxy function setProperty( name:*, value:*):void{
var oldVal:String = _data..property.(@id == String( name) );
var index:Number =_data..property.(@id == String( name )).childIndex();
_data.replace( index, '<property id="' + name + '">' +value + '</property>' );
var evt:Event =PropertyChangeEvent.createUpdateEvent( this, name, oldVal,value );
dispatchEvent( evt );
}
// IEventDispatcher implementation.
public function addEventListener( type:String,listener:Function,useCapture:Boolean = false,priority:int = 0,useWeakReference:Boolean =false):void
{
_evtDispatcher.addEventListener( type, listener,
useCapture,priority, useWeakReference );

// IEventDispatcher implementation.
public function removeEventListener( type:String,listener:Function,useCapture:Boolean = false):void{
_evtDispatcher.removeEventListener( type, listener,useCapture );
}
 // IEventDispatcher implementation.
public function dispatchEvent( evt:Event ):Boolean
{
return _evtDispatcher.dispatchEvent( evt );

// IEventDispatcher implementation.
public function hasEventListener( type:String ):Boolean
{
return _evtDispatcher.hasEventListener( type );
}
 // IEventDispatcher implementation.
public function willTrigger( type:String ):Boolean
{
return _evtDispatcher.willTrigger( type );
}
}
}

你可以存取和修改这个加载的XML 的元素,被放置在Properties proxy 中,通过点连接语法:
+展开
-ActionScript
var myProxy:Properties = new Properties();
myProxy.load('properties.xml' );
..
var name:String = myProxy.name;
myProxy.album = "Blue Valentine";

虽然你可以使用点连接语法与动态的属性引用进行工作,你确不能在花括号中使用点连接语法,或者在MXML 中使用<mx:Binding>进行的数据绑定。如果你想使用点连接语法的话,在进行编译的时候会得到一个警告提示:

因为这些XML 数据是在运行的时候进行加载的,这样可以理解为当你是在数据加载后再创建绑定的。为了达到这点,使用mx.utils.BindingUtils 类来强制更新和确认数据绑定到proxy。

下面的代码片断创建一个程序,使用上面的Properties 代理的一个实例来创建一个数据绑定到一个制件的属性
+展开
-XML
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxmllayout="verticalcreationComplete="initHandler();">
<mx:Script>
<![CDATA[
import mx.binding.utils.BindingUtils;
import com.oreilly.flexcookbook.Properties;
private var _properties:Properties;
// create proxy and load xml.
private function initHandler():void
{
_properties = new Properties();
_properties.addEventListener( Event.COMPLETE,propertiesHandler );
_properties.loadProperties( "data/properties.xml" );

// xml data loaded. establish data binding.
private function propertiesHandler( evt:Event ):void
{
BindingUtils.bindProperty( nameOutput, "text",_properties, "name" );
BindingUtils.bindProperty( albumOutput, "text",_properties, "album" );
BindingUtils.bindProperty( genreOutput, "text",_properties, "genre" );

// change properties of proxied data.
private function changeHandler():void
{
_properties.name = nameField.text;
_properties.album = albumField.text;
_properties.genre = genreField.text;
}

]]>
</mx:Script>
<mx:Label text="Data Loaded." />
<mx:Form>
<mx:FormItem label="Name:">
<mx:Text id="nameOutput" />
</mx:FormItem>
<mx:FormItem label="Album:">
<mx:Text id="albumOutput" />
</mx:FormItem>
<mx:FormItem label="Genre:">
<mx:Text id="genreOutput" />
</mx:FormItem>
</mx:Form>
<mx:HRule width="100%" />
<mx:Form>
<mx:FormItem label="Name:">
<mx:TextInput id="nameField" />
</mx:FormItem>
<mx:FormItem label="Album:">
<mx:TextInput id="albumField" />
</mx:FormItem>
<mx:FormItem label="Genre:">
<mx:TextInput id="genreField" />
</mx:FormItem>
<mx:FormItem label="Submit Changes">
<mx:Button label="okclick="changeHandler();" />
</mx:FormItem>
</mx:Form>
</mx:Application>

在propertiesHandler 事件处理器中,当XML 数据通过Properties 实例加载后,通过使用BindingUtils.bindProperty 方法能进行熟练的数据绑定。第一个表单的各个文本控件的text 属性被绑定到了对应的XML 元素上。在类Properties 中的重载的getProperty 使用E4X,一个绑定的更新被创建,该值也被复制。

属性的值的更新是通过changeHandler 事件处理器中使用点连接的语法来进行操作的,它在Properties 实例中引入了setProperty 方法,同时分发一个事件通知,通过使用PropertyChangeEvent 对象来引入数据绑定。

加支付宝好友偷能量挖...


评论(0)网络
阅读(97)喜欢(0)flash/flex/fcs/AIR