2010-02-04 45 views
1

我正在構建一個複雜的Flex應用程序,現在我處於導航成爲問題的地步。我使用Viewstack與菜單欄,但我不知道如何清晰地構造這個。在Flex中處理複雜的導航

根據登錄的用戶和用戶選擇的公司,他可以看到不同的頁面。現在我限制了它隱藏菜單欄中的相應按鈕。但是,不僅僅是菜單欄,而且應用程序中的按鈕/鏈接都應該能夠導航到每個現有頁面。

當我加載一個現有的頁面時,它需要一些初始化(取決於從它加載的上下文)。另外,選擇公司時,我需要從後端加載狀態,並且根據此狀態,可能會顯示特定的頁面。

是否有任何指導方針如何解決Flex中更復雜的導航/網站層次結構?

現在,我在應用程序的viewstack中擁有所有視圖,並將其與Application.application.appViews.selectedChild - >引用,但這顯然不是最佳實踐,因爲它違反了封裝。

正在考慮實施某種狀態機,它負責處理所有這些事情,但不太清楚這是否合理,或者是否有更好的方法。

謝謝你們, 馬丁

回答

1

如果它真的複雜,你可能要考慮將您的應用程序成模塊。

此外,Mate是一個偉大的Flex框架,用於處理複雜的通信和導航。 Mate的EventMaps可以幫助您集中組件,模塊等之間的通信和邏輯。並且,它使您遠離可怕的Application.application引用。

即使您不使用像Mate這樣的框架,也可以通過讓組件調度自定義事件,使其引發到應用程序的頂層,從而避免引用Application.application。應用程序的頂層可以監聽並捕獲這些事件並對其執行操作。我發現這是一個更靈活的方法。儘可能避免Application.application!

如果你有一個複雜的菜單欄需要啓用/禁用很多不同的邏輯條件的按鈕或選項,狀態模式是一個體面的方式來處理它。我構建了一個企業級應用程序,在頂部有一個「類似於Word的」按鈕欄......並且有太多不同的條件影響了按鈕的狀態,我必須將邏輯集中在一個位置。起初我沒有使用國家模式,維護代碼是一件困難的事情。有一天,我咬緊牙關,重新將所有的條件邏輯分解成一個StateManager類。從那裏開始,它絕對讓生活更輕鬆。

+0

嗨布賴恩, 謝謝你的答案。伴侶聽起來有趣 - 對於這個項目,儘管我可能會堅持國家模式。然而,你是如何設法擺脫狀態管理器中的Application.application引用的(我創建了一個Singleton類)? 我的菜單和我的ViewStack位於應用程序文件中,狀態管理器經常引用它們。 謝謝, Martin – martin 2010-02-05 08:55:42

0

同樣,您可能需要考慮使用自定義事件嚮應用程序廣播重要事件。您可以使這些事件起泡到應用程序級別。然後,通過在應用程序級別添加事件偵聽器,您可以捕獲並響應這些事件並從應用程序級別定位組件或模塊。這爲您提供處理事件和「指揮交通」的中心位置。它還可以防止Application.application方法的緊密結合。 (隨着應用程序的增長和擴展,這很快就會變成一場噩夢!)

例如,您的StateManager可以包含用於決定您的應用程序需要處於哪種狀態的case語句。一旦確定了有關當前狀態的決定,會派遣一個自定義的StateEvent。(它可能具有像StateEvent.STATE_CHANGED和StateEvent.CURRRENT_STATE這樣的屬性)此事件可以冒泡到應用程序級別並被偵聽器捕獲。偵聽器然後調用加載/更改狀態的方法。

這是否爲您澄清?如果沒有,也許我可以花一兩個小時放一些樣品。

讓我知道,

=布萊恩=

0

我可以給你我用你的一些小問題的方法,在運行時初始化頁面,如何封裝導航的問題。

對於頁面初始化,我遇到的問題是,一旦您導航到頁面時,並不總是知道是否應該顯示某些元素,因爲它不僅取決於整體用戶權限,還取決於當前用戶的權限,選定的數據。如果需要確定這些信息必須從服務器加載,則在加載信息時無法顯示該頁面。所以我們創建了一個名爲LoadPanel的控件,它是一個容器,它可以用一個加載指示符覆蓋內容,直到收到其他信息。下面是ActionScript中的一個縮短的版本:

[DefaultProperty("children")] 
public class LoadingPanel extends ViewStack 
{ 
    public function LoadingPanel() 
    { 
     this.resizeToContent = false; 
     super(); 
    } 

    public function get children():Array { return _children }   
    public function set children(value:Array):void { _children = value; } 

    public function get loadingImageStyle():String { 
     return _loadingImgStyle; } 
    public function set loadingImageStyle(value:String):void { 
     _loadingImgStyle = value; 
     if (_loadingIndic) 
      _loadingIndic.loadingImageStyle = value; 
    } 

    public function showLoadingIndicator():void 
    { 
     if (_loadingIndic) 
     { 
      super.selectedChild = _loadingIndic; 
     } 
     else 
     { 
      _pendingLoadingIndic = true; 
      var me:LoadingPanel = this; 
      var listener:Function = function(event:Event):void 
      { 
       if (me._pendingLoadingIndic) 
        me.showLoadingIndicator(); 
      } 
      addEventListener(FlexEvent.CREATION_COMPLETE, listener); 
     } 
    } 

    public function hideLoadingIndicator():void 
    { 
     _pendingLoadingIndic = false; 
     if (_content) 
     { 
      super.selectedChild = _content; 
     } 
     else 
     { 
      var me:LoadingPanel = this; 
      var listener:Function = function(event:Event):void 
      { 
       me.hideLoadingIndicator(); 
      } 
      addEventListener(FlexEvent.CREATION_COMPLETE, listener); 
     } 
    } 

    public function waitForEvent(target:EventDispatcher, event:String):void 
    { 
     _eventCount++; 
     showLoadingIndicator(); 
     var me:LoadingPanel = this; 
     target.addEventListener(
      event, 
      function(evt:Event):void 
      { 
       me._eventCount--; 
       if (!me._eventCount) 
       { 
        me.hideLoadingIndicator();       
       } 
      } 
     ); 
    } 

    override public function addChild(child:DisplayObject):DisplayObject 
    { 
     var result:DisplayObject = child; 
     if (_content) 
     { 
      result = _content.addChild(child); 
      invalidateDisplayList(); 
     } 
     else 
     { 
      if (!_children) 
      { 
       _children = []; 
      } 
      _children.push(child); 
     } 
     return result; 
    } 

    override protected function createChildren():void 
    { 
     super.createChildren(); 

     if (!_content) 
     { 
      _content = new Box(); 
      _content.percentWidth = 1.0; 
      _content.percentHeight = 1.0; 
      super.addChild(_content); 
     } 

     if (!_loadingIndic) 
     { 
      _loadingIndic = new LoadingIndicator(); 
      _loadingIndic.percentWidth = 1.0; 
      _loadingIndic.percentHeight = 1.0; 
      _loadingIndic.loadingImageStyle = _loadingImgStyle; 
      super.addChild(_loadingIndic); 
     } 

     if (_children) 
     { 
      for each (var child:DisplayObject in _children) 
      { 
       _content.addChild(child); 
      } 
     } 
    } 

    private var _loadingImgStyle:String = "loadingIndicatorDark"; 

    private var _loadingIndic:LoadingIndicator = null; 
    private var _content:Box = null; 
    private var _children:Array = null; 
    private var _pendingLoadingIndic:Boolean = false; 
    private var _eventCount:int = 0; 
} 

我們通常會通過包裝一個LoadingPanel圍繞內容然後調用面板的waitForEvent方法使用這些。通常情況下,我們要等待的事件是爲了提供Web服務響應。該類還允許您在多個事件顯示其子級之前等待多個事件。

我會爲您的項目提出的另一個建議是,您將看到Flex中的深層鏈接。我們的用戶讚賞能夠在複雜的Flex應用程序中爲資源/位置添加書籤,並且能夠在瀏覽器中進行刷新並返回到他們所在的相同「頁面」。但是實施深度鏈接也幫助我解決了你提到的其中一個問題。你如何以封裝的方式將UI發送到特定頁面?我們這樣做的方式是通過引發包含目標「URL」的冒泡導航事件。頂級導航「經理」然後處理解釋URL並將用戶「發送」到適當的區域。

希望這會給你一些你面臨的挑戰的想法。