在Cairngorm架構中,view層發送自訂事件,command層再根據事件做相應的處理,View層中的資料通過綁定ModelLocator中的屬性實現自動更新。現有的問題是,有時除了更新資料意外,使用者需要更多的資訊,比如,我需要判斷後台返回的資料是否正確,或者,我需要更具返回的資料做下一步的處理。
簡單的例子,如果擷取的資料不符合使用者的需要,我可能需要一個提示框給使用者一個提示。提示框應該屬於View層的。當然在command層也可以直接import mx.controls.Alert; 調用Alert.show()方法。
但如果,使用者在擷取到資料後,要執行View層的另外一個方法,那就比較棘手了。比如,我需要在view層DataGrid刪除一個資料,我在view層發送一個刪除的事件,command層處理事件會返回一個結果,此時,我在view層就要根據不同的結果往下執行不同方法,比如,失敗了我執行一個doFail()的,成功了我doSuccess()。
command如何讓View去執行下一步的方法呢?
1.傳統的做法(command操縱view的引用)
方法A:將view存入ModelLocator中的屬性中,而後在command就可以拿到該view的引用,從而執行view的方法。
這種方法可行,但view與command的耦合在了一起,嚴重破壞了MVC的松耦合度的要求
private function onResult_delete(e:ResultEvent):void{if (e.result != null){var result:String=e.result.code as String;if (result == "success"){ Alert.show("刪除成功!"); (_model.userManagerModel.view as Object).doSuccess();} }else{Alert.show("修改失敗!"); (_model.userManagerModel.view as Object).doFail();}}
將view存入ModelLocator的_model.userManagerModel.view中,在command強制轉換為Object從而拿到view的引用
方法B:用到架構中的ViewHelper和ViewLocator這兩個類。
ViewHelper類實現介面IMXMLObject,首先自訂一個ViewHelper,然後在視圖中引用它。
package domain.app.view{ import com.adobe.cairngorm.view.ViewHelper; public class LoginViewHelper extends ViewHelper{ public function doSomething(){ //do something with the protected property view. } }}
在視圖中執行個體化這個ViewHelper
<helper:LoginViewHelper id="loginViewHelper"/>
然後就可以在Command中使用這個ViewHelper。
但方法同樣存在耦合度高的問題,故 Cairngorm 3版本中已經廢棄
2.現有做法(事件通訊)
既然Flex基於事件驅動的,既然,view可以發事件給command ,那為什麼command 不可以發事件通知給view呢?
當view監聽到該事件後,自然就可以繼續執行view的其他方法了。那view由誰來做這個command發送過來的事件呢?
此時,CairngormEventDispatcher.getInstance()出場。
首先,在CairngormEvent的子類中MyEvent定義2個事件,一個是處理事件DEL,一個是處理事件的事件DEL_COMPLETE,另外添加一個code變數用來儲存DEL結果
public class MyEvent extends CairngormEvent{public static const DEL:String = "DEL"; //刪除public static const DEL_COMPLETE:String = "DEL_COMPLETE"; //刪除資料 處理完後處理事件/*返回參數類型 "success""exist""fail"*/public var code:String =""; /*事件類型*/public var event_type:String="";public function MyEvent(type:String){this.event_type=type;super(type);}}
其中DEL是交給command處理的,所以要在FrontController中做一個綁定;DEL_COMPLETE則不需要
this.addCommand(MyEvent.DEL, UserManagerCommand);
我們在view發事件DEL給command後,立馬用CairngormEventDispatcher.getInstance()做一個DEL_COMPLETE事件的監聽
command 在處理完DEL後,就發送一個DEL_COMPLETE事件,此時,view在監聽這個事件的CairngormEventDispatcher.getInstance()就可以執行相應的方法了
下面是commad的操作
private function onResult_delete(e:ResultEvent):void{var event:MyEvent = new MyEvent(MyEvent.DEL_COMPLETE);if (e.result != null){var result:String=e.result.code as String;if (result == "success"){ event.code = "success";}else{event.code = "fail"} }else{event.code = "fail"}/*發送處理事件*/event.dispatch();}
下面是view的操作
private function init():void{ var e :MyEvent = new MyEvent(MyEvent.DEL);e.dispatch();/* 監聽 資料返回 */CairngormEventDispatcher.getInstance().addEventListener(MyEvent.DEL_COMPLETE, del_compelete);}}/************************************************************** * 函數:command處理完成後執行方法 */private function del_compelete(e:MyEvent):void{CairngormEventDispatcher.getInstance().removeEventListener(MyEvent.EDIT_COMPLETE, del_compelete);if (e.code =="success"){Alert.show("刪除成功!"); doSuccess();} else if (e.code =="fail"){Alert.show("刪除失敗!"); doFail();}}
這樣,view和command耦合性的問題得到解決。