现在要在项目中要实现界面上布局的更改,就像FlashIDE中那些面板,它能拖动与其他面板合并,也能单独出来接受用户交互。比如:项目中主程序有3个模块,分别是聊天,视频,用户列表,写了三个组件分别为Chat.MXML,Video.MXML,UserList.MXML,在主程序初始化后,Chat组件(模块)是镶嵌于主界面里假设主界面有一个HBox,即Chat是HBox的一个子对象,现在新的要求要在主程序初始化后Chat组件是一个浮动状态,可以拖动。将Chat组件变为浮动后,Chat组件中中用标签建立的绑定就会出问题,代码如下:
Chat.MXML---继承于Canvas,里面放了一个TextArea组件用于显示调试消息,一个标签建立的绑定,用于设置消息。
<?xml version="1.0" encoding="utf-8"?> <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300" creationComplete="init()"> <mx:Script> <![CDATA[ import vo.MessageVo; import model.BindingModel; import mx.managers.PopUpManager; import mx.core.Application; import mx.containers.TitleWindow; import mx.binding.utils.BindingUtils; [Bindable]private var _text:String=""; private var _titleWindow:TitleWindow; private var _count:int = 0; private function init():void { trace("init"); } [Bindable] public function get message():MessageVo { return null; } public function set message(msgVo:MessageVo):void { _count++; _text+=(_count+" : "+msgVo.msg+"\n"); } /* * 利用TitleWindow弹出Chat组件,使之处于浮动状态 **/ public function popWindow():void { trace(_titleWindow,"A"); if(!_titleWindow)_titleWindow = new TitleWindow(); _titleWindow.title = "Test"; _text+=("popuping..."+"\n"); trace(_titleWindow.contains(this),"B"); if(!_titleWindow.contains(this)) { trace("C"); _titleWindow.addChild(this); trace(this,"AAAA"); PopUpManager.addPopUp(_titleWindow,Application.application as DisplayObject); } _text+=("popuped!"+"\n"); } ]]> </mx:Script> <!--绑定到Chat的message属性--> <mx:Binding source="BindingModel.getInstance().messageVo" destination="message"/> <mx:TextArea x="40" y="10" height="182" width="320" id="ta" text="{_text}"/> </mx:Canvas>
主界面BindingTest.MXML---主界面有两个状态,第一个状态放一个按钮,用于点击进入第二个状态。
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:components="components.*" creationComplete="init()" > <mx:Script> <![CDATA[ import vo.MessageVo; import vo.PersonVo; import model.BindingModel; private function init():void { } private function onClick():void { chat.popWindow(); } /* 向Model中写入数据,显示在Chat组件中 */ private function setVo():void { var msg:MessageVo = new MessageVo(); msg.msg = new Date().time.toString(); BindingModel.getInstance().messageVo = msg; } /* 进入主状态 */ private function enterMain():void { this.currentState='main'; chat.popWindow(); } private function chatInit():void { } ]]> </mx:Script> <mx:Button x="293" y="287" label="进入主界面" id="enterBtn" click="enterMain()" fontSize="12"/> <mx:states> <mx:State name="main"> <mx:AddChild position="lastChild"> <mx:VDividedBox width="100%" id="vbox" height="332"> <mx:TextInput id="ti" height="22"/> <components:Chat id="chat" height="217" creationComplete="chatInit()"/> </mx:VDividedBox> </mx:AddChild> <mx:AddChild position="lastChild"> <mx:Button x="83" y="340" label="弹出" id="btn" click="onClick()" fontSize="12"/> </mx:AddChild> <mx:AddChild position="lastChild"> <mx:Button x="10" y="340" label="发消息" id="setBtn" click="setVo()" fontSize="12"/> </mx:AddChild> <mx:RemoveChild target="{enterBtn}"/> </mx:State> </mx:states> </mx:Application>
进入主界面后,Chat组件是嵌入在一个VDividedBox中的,除了Chat,VDividedBox里面还有一个TextInput,TextInput没有其他作用,只是放里面让VDividedBox显示分隔符。
下面是一个model,一个vo,代码如下:
package model { import vo.MessageVo; import vo.PersonVo; [Bindable] public class BindingModel { private static var _instance:BindingModel; public static function getInstance():BindingModel { if(_instance==null) { _instance = new BindingModel(); } return _instance; } public function BindingModel() { } public var personVo:PersonVo = new PersonVo(); public var messageVo:MessageVo = new MessageVo(); } } package vo { public class MessageVo { public var msg:String = "oh,yeah!"; public var time:Number; public function MessageVo() { } } }
运行效果如下:
点击进入主界面后,你会发现在titleWindow中有两条输出,也就是说Chat组件的属性message被赋值了两次,而Chat中只有BindingModel.getInstance().messageVo是它的源,且问题不仅如此。进入主界面后,点击发消息按钮执行主界面上的setVo函数,改变BindingModel.getInstance().messageVo,继而设置了Chat组件的属性message,但一次设置,Chat中TextArea中居然会有两次输出...问题出在哪里?
从进入主界面的按钮来找,发现enterMain函数中在设置了主界面的状态为"main"后,立即调用Chat来弹出自己,设置浮动。问题就出在此处,因为此时Chat并没有初始化完成就完成了弹出(添加到显示列表),同时Chat中的标签建立的绑定将BindingModel.getInstance().messageVo与message绑定,而初始化后又一次将添加到显示列表,再次将BindingModel.getInstance().messageVo与message绑定,虽然这两个绑定的源和目的都是相同,但Flex却把它当成两个绑定,一旦设置BindingModel.getInstance().messageVo就会有两次赋值个message属性,即有两次输出。
解决办法:
下面的init函数为Chat的creationComplete事件处理函数。
1。可以将弹出Chat组件的方法延时调用,即可以监听Chat的creationComplete事件,在此事件的处理函数中执行chat.popWindow();
private function init():void
{
trace("init");
this.popWindow();
}
2。还是在进入主界面时弹出窗口,但要将Chat中标签建立的绑定改为As动态建立绑定,并且也得是在creationComplete处理函数中处理。
private function init():void
{
trace("init");
BindingUtils.bindProperty(this,"message",BindingModel.getInstance(),["messageVo"]);
}