Cairngorm开发框架

视频课:https://edu.csdn.net/course/play/7621

本章简介

Cairngorm是由adobe公司推出的一个轻量级的Flex RIA程序开发框架。目的是提高程序的可扩展性、可维护性,其本身并不是一个完整的企业应用,它只是提供了一个开发骨架,Adobe称之为体系。 Cairngorm主要就是对开发Flex应用程序应用了一系列的设计模式,从而使开发出来Flex程序可扩展性,可维护性都大大提高。代价就是异常繁琐的文件书写。往往为了完成一个简单的功能需要修改n个文件。所以小项目不建议使用。

Cairngorm也意识到到这个问题,因此也升级为Cairngorm3.0。这次cairngorm的升级,改动非常大,比flex3升级到flex4的改动大的多。不仅仅是个mvc框架了,应该算是一个工具包,提供了很多个swc,通过parsley这个ioc框架纳入了很多种的工具包,总得来讲,cairngorm3已经跟javaspring框架类似了。

核心技能部分

 

Cairngorm是一种开源框架,由Adobe开发团队设计。使用Cairngorrn框架能快速地建立起RIA应用程序,适用于开发大中型应用程序。Cairngorrn框架不但能提高开发效率,也有利于团队合作。本章将介绍Cairngorrn框架的基础知识、运行原理和机制、使用方法等。通过Cairngorrn实例的学习,掌握Cairngorrn框架的特点及使用方法。

1.1 Cairngorm简介

   Cairngorm框架是开发RIA应用程序的轻量级框架,可应用于企业级的软件开发,也可结合J2EE.Net等开发技术。

    由于Flex4.0技术是由事件驱动的,所以事件处理函数很多。假设一个应用程序中存在大量事件,若每个事件的处理函数都定义于一个MXML文件或AS文件中,代码就会很混乱、不利于修改。Cairngorm框架将每个事件处理封装为一个类。这样,不但代码整洁了,而且也提高了重用性。

    Cairngorm提供了一种类似于MVC的框架,将设计视图与代码分离,因此有利于团队开发。Cairngorm框架运行过程的简单描述如下所示。

Ø 前台控制器监听事件。

Ø 当事件发生时,前台控制器调用相应命令执行。

Ø 命令类中的execute方法执行相关处理。Onresult方法处理结果集。onFault方法处理异常信息。

Ø 组件视图绑定至相关数据集。若数据集发生改变,视图自动改变。

1.2  Flex4.0中添加Cairngorm框架

Flex4.0中添加Cairngorm框架的步骤如下所示。

Ø 在浏览器中输入http://labs.adobe.com/wiki/index.php/Cairngorm",打开Cairngorrn框架的下载页面。

Ø 单击Downloads“ 标签下的”here“链接,下载Cairngorrn框架。

Ø 解压缩Cairngorm包。Cairngorm框架的源文件在com”文件夹中,已编译的Cairngorrn库文件“Cairngorm.swc”在“bin”文件夹下。

Ø 在需要添加Cairngorrn框架的Flex工程上右击,弹出快捷菜单,如图6.1.1所示。

 

6.1.1 添加 Cairngorrn

Ø 选择"Properties”命令,打开工程属性对话框如图6.1.2所示。

 

6.1.2 添加 Cairngorrn

 

Ø 单击Add swc …”按钮,弹出选择swc文件对话框,如图6.1.3所示。

 

6.1.3 添加 Cairngorrn

 

Ø 在文本框中输入Cairngorrn.swc”文件路径。单击“oK”按钮,完成添加Cairngorrn框架。

 

1.3 Cairngorrn框架中的基础类

 Cairngorrn框架的运行机制是以类为基础,因为Cairngorrn框架是由ActionScript3.0语言编写的,而ActionScript3.0语言是一种面向对象的语言。本小节将介绍Cairngorrn框架中基础类的作用和定义。大部分基础类不能直接使用,用户需要继承基础类来完成特定的功能。

有关如何使用基础类将在后续章节中介绍。

1.3.1 类的文件组织结构

Cairngorrn框架中的类不是杂乱无章地存放,而是以特定的文件组织结构存放的。每个

文件夹有特殊的含义,存放不同意义的基础类。Cairngorm框架的文件结构如图6.1.4所示。

 

6.1.4 Cairngorm框架的文件结构

business”文件夹中存放有关服务器端的类。“commands”文件夹存放命令类。“control”文件夹存放前台控制器类。“model”文件夹存放应用程序模型类;view”文件夹存放视图类及MXML文件; vo”文件夹存放数据模型类。

1.3.2 处理正常或异常结果的Responder

Responder类是一个接口类,用以处理正常或异常结果。Responder类定义了两个抽象的

方法:onResult()方法和onFault()方法。onResult()方法用于操作正常时的处理,onFault()方法

用于操作异常时的处理。    

一般在command类中实现Responder接口类有两个方法。有关Responder接口类的实现

将在后续章节中介绍。

以下代码是Responder类的定义代码。

package com.adobe.cairngorm.business

{

   

   public interface Responder

   {

      

      [Deprecated(replacement="mx.rpc.IResponder.fault")]

      function onResult( event : * = null ) : void;

      [Deprecated(replacement="mx.rpc.IResponder.result")]

      function onFault( event : * = null ) : void;

   }   

}

1.3.3 查找服务的ServiceLocator

ServiceLocator类用于查找服务,如<mx:HTTPService>, <mx:WebService>等。ServiceLocator类可以查找不同类型的服务,因此每种类型的服务都有对应的方法,其中,getService()方法的优点是可获取任何类型服务,缺点是效率不高。以下代码是getService方法的定义代码。

public function getService( serviceId : String ) : AbstractService

      {

         return AbstractService( getServiceForId( serviceId ) );

      }      

1.3.4 处理事件的Command

Command类继承于ICommand接口类,用于处理某一事件。ICommand类中定义了execute

抽象方法,用于执行相应处理。以下代码是ICommand类的定义代码。

package com.adobe.cairngorm.commands

{

   import com.adobe.cairngorm.control.CairngormEvent;

 

  

   public interface ICommand

   {

      

      function execute( event : CairngormEvent ) : void;

   }

}

1.3.5 创建新事件CairngormEvent

CairngormEvent类用于自定义用户事件。包含一个成员变量data和一个构造函数。data

变量可存储任何类型的数据。以下代码是CairngormEvent类的定义代码。

package com.adobe.cairngorm.control

{

   import flash.events.Event;

 

   

   public class CairngormEvent extends Event

   {

      public var data : *;

      

     

      public function CairngormEvent( type : String, bubbles : Boolean = false, cancelable : Boolean = false )

      {

         super( type, bubbles, cancelable );

      }

      

     

      public function dispatch() : Boolean

      {

         return CairngormEventDispatcher.getInstance().dispatchEvent( this );

      }

   }

}

 

1.3.6 管理事件的CairngormEventDispatcher

CairngormEventDispatcher类用于管理事件。CairngormEventDispatcher类中的方法说明

如表5-1-1所示。

5-1-1 CairngormEventDispatcher的方法

方法名

说明

getInstance

获取类的一个实例

adEventListener

添加事件监听

removeEventListener

移除事件监听

dispatchEvent

广播事件  

hasEventListener

是否有事件监听

willTrigger

是否可以触发

其中dispatchEvent方法是最常使用的方法。一旦广播事件,FrontController类就能收到

消息。以下代码是CairngormEventDispatcher类的定义代码。

package com.adobe.cairngorm.control

{

   import flash.events.IEventDispatcher;

   import flash.events.EventDispatcher;

   

   public class CairngormEventDispatcher

   {

      private static var instance : CairngormEventDispatcher;  

      private var eventDispatcher : IEventDispatcher;

      

     

      public static function getInstance() : CairngormEventDispatcher

      {

         if ( instance == null )

            instance = new CairngormEventDispatcher();

          

           return instance;

      }

      

      

      public function CairngormEventDispatcher( target:IEventDispatcher = null )

      {

         eventDispatcher = new EventDispatcher( target );

      }

      

      

      public function addEventListener( type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false ) : void

      {

         eventDispatcher.addEventListener( type, listener, useCapture, priority, useWeakReference );

      }

      

    

      public function removeEventListener( type:String, listener:Function, useCapture:Boolean = false ) : void

      {

         eventDispatcher.removeEventListener( type, listener, useCapture );

      }

 

     

      public function dispatchEvent( event:CairngormEvent ) : Boolean

      {

         return eventDispatcher.dispatchEvent( event );

      }

      

     

      public function hasEventListener( type:String ) : Boolean

      {

         return eventDispatcher.hasEventListener( type );

      }

    

      public function willTrigger(type:String) : Boolean

      {

         return eventDispatcher.willTrigger( type );

      }

   }

}

1.3.7 监听事件的FrontController

FrontControllr类用于监听事件。一旦事件发生,前台控制器找到事件的相应处理命令

类执行。FrontControllr类中的方法说明如表5-1-2所示。

5-1-2 FrontControllr类的方法

方法名

说明

addCommand

监听事件 并添加事件的处理命令

executeCommand

执行命令

getCommand

获得命令

以下代码是FrontControllr类的定义代码。

package com.adobe.cairngorm.control

{   

   import com.adobe.cairngorm.CairngormError;

   import com.adobe.cairngorm.CairngormMessageCodes;

   import com.adobe.cairngorm.commands.ICommand;

   

   import flash.utils.Dictionary;

 

   public class FrontController

   {

    

      protected var commands : Dictionary = new Dictionary();

 

    

      public function addCommand( commandName : String, commandRef : Class, useWeakReference : Boolean = true ) : void

      {

         if( commands[ commandName ] != null )

            throw new CairngormError( CairngormMessageCodes.COMMAND_ALREADY_REGISTERED, commandName );

         

         commands[ commandName ] = commandRef;

         CairngormEventDispatcher.getInstance().addEventListener( commandName, executeCommand, false, 0, useWeakReference );

      }

      

   

      public function removeCommand( commandName : String ) : void

      {

         if( commands[ commandName ] === null)

            throw new CairngormError( CairngormMessageCodes.COMMAND_NOT_REGISTERED, commandName);  

         

         CairngormEventDispatcher.getInstance().removeEventListener( commandName, executeCommand );

         commands[ commandName ] = null;

         delete commands[ commandName ];

      }

      

    

      protected function executeCommand( event : CairngormEvent ) : void

      {

         var commandToInitialise : Class = getCommand( event.type );

         var commandToExecute : ICommand = new commandToInitialise();

 

         commandToExecute.execute( event );

      }

      

    

      protected function getCommand( commandName : String ) : Class

      {

         var command : Class = commands[ commandName ];

         

         if ( command == null )

            throw new CairngormError( CairngormMessageCodes.COMMAND_NOT_FOUND, commandName );

            

         return command;

      }      

   }   

}

1.3.8 存储数据模型的ModelLocator

ModelLocator类是一种接口类,用于应用程序的数据模型。可将应用程序需要显示的数

据及状态变量都定义于ModelLocator类中。ModelLocator类相当于应用程序的“数据库”,

方便修改与删除。

1.3.9 辅助操作视图的ViewHelper

ViewHelper类用于辅助操作视图。使用ViewHelper类可在AS文件中修改其他MXML文件中的视图。ViewHelper类中定义了两个成员变量:viewid  View变量为Object类型,存储了使用ViewHelper类的MXML文件的全部组件视图,id变量为ViewHelper类的标识符,ViewHelper类中的方法说明如表5-1-3所示。

5-1-3 ViewHelper类中的方法

方法名

说明

Initialized

初始化ViewHelper,包括viewid变量

registerView

注册视图

unregisterView

撤销注册视图

以下代码是ViewHelper类的定义代码。

 

package com.adobe.cairngorm.view

{

   import flash.events.Event;

   import mx.core.IMXMLObject;

 

   

 

   public class ViewHelper implements IMXMLObject

   {

     

      protected var view : Object;

      

 

      protected var id : String;      

      public function initialized( document : Object, id : String ) : void

      {

         this.view = document;

         this.id = id;

         

         view.addEventListener( Event.ADDED, registerView );

         view.addEventListener( Event.REMOVED, unregisterView );

      }

      

    

      private function registerView( event : Event ) : void

      {

         if ( event.target == view )

           {

              ViewLocator.getInstance().register( id, this );

           }

      }

      

     

      private function unregisterView( event : Event ) : void

      {

         if( event.target == view )

         {

            ViewLocator.getInstance().unregister( id );

         }

      }

   }

}

1.3.10  查找视图的ViewLocator

ViewLocator类用以查找视图,即查找ViewHelper类实例。ViewLocator类中的方法说明

如表5-1-4所示。

5-1-4 ViewLocator类的方法

方法名

说明

getInstance

获取ViewLocator实例

Register

注册视图

Unregister

撤销注册

GetViewHelper

根据ViewHelperid获取ViewHelper实例

registrantionExistsFor

视图是否已注册

以下代码是ViewLocator类的定义代码。

package com.adobe.cairngorm.view

{

   import com.adobe.cairngorm.CairngormError;

   import com.adobe.cairngorm.CairngormMessageCodes;

   

   import flash.utils.Dictionary;

   public class ViewLocator

   {

      private static var viewLocator : ViewLocator;

      private var viewHelpers : Dictionary;      

      

    

   

      public static function getInstance() : ViewLocator

      {

         if ( viewLocator == null )

            viewLocator = new ViewLocator();

   

         return viewLocator;

      }

 

     

      public function ViewLocator()

      {

         if ( ViewLocator.viewLocator != null )

         {

            throw new CairngormError(

               CairngormMessageCodes.SINGLETON_EXCEPTION, "ViewLocator" );

         }

         

         viewHelpers = new Dictionary();      

      }

 

     

      public function register( viewName : String, viewHelper : ViewHelper ) : void

      {

         if ( registrationExistsFor( viewName ) )

         {

            throw new CairngormError(

               CairngormMessageCodes.VIEW_ALREADY_REGISTERED, viewName );

         }

   

         viewHelpers[ viewName ] = viewHelper;

      }

      

     

      public function unregister( viewName : String ) : void

      {

         if ( !registrationExistsFor( viewName ) )

         {

            throw new CairngormError(

               CairngormMessageCodes.VIEW_NOT_FOUND, viewName );

         }

         

         delete viewHelpers[ viewName ];

      }

      

    

      public function getViewHelper( viewName : String ) : ViewHelper

      {

         if ( !registrationExistsFor( viewName ) )

         {

            throw new CairngormError(

               CairngormMessageCodes.VIEW_NOT_FOUND, viewName );

         }

         

         return viewHelpers[ viewName ];

      }

      

    

      public function registrationExistsFor( viewName : String ) : Boolean

      {

         return viewHelpers[ viewName ] != undefined;

      }

   }

}

1.3.11 定义数据模型的ValueObject

ValueObject类继承于IValueObjet类,而IValueObjet接口类,主要用于定义数据模型。例如,注册信息包括用户名和密码,用户可将用户名和密码封装在ValueObject类中。定义数据模型的好处是使应用程序更简洁、重用性更高。

 

1.4 使用Cairngorm框架开发应用

Cairngorm框架以事件为驱动,所以一个完整的运行过程从事件触发开始。本节将讲解Cairngorm的工作流程并以CairngormDemo应用为例讲解如何使用Cairngorm框架开发应用。

1.4.1 Cairngorm的工作流程

Cairngorm的工作流程很清晰,即以事件为驱动,一个完整的运行过程从事件触发开始:

Ø View根据诸如鼠标点击,按钮按下之类的用户动作,产生相应的Event

Ø Front 即前端的控件监听用户的行为。注意它只是监听,并不会做任何反应。

Ø 控件监听以后调用Commands来做相应的事情,Command做了所有工作。

Ø 把服务器端的业务逻辑委托到 Bussiness Delegates中。因为很多时候command需要获得服务器端数据,所以这样一来它可以直接调用Bussiness Delegates而不用关注如何连接数据的细节,实现了信息隐藏。

Ø Command调用Business Delegate 后,Business Delegate 通过Service Locator来找到相应的RPC services,然后执行实现从服务器端取数据。

Ø 把传输过来的数据存储为Value Objects。这点大家应该都很熟悉,比如想要查询一个公告,就必定创建一个公告类,来存储每一个公告的标题等信息。

Ø Model Locator 保存状态并且能使Model检测到View的变化。这样一来用户操作就能直接影响Model,比如添加物品到购物车,Model中的购物商品就会自动增加。

1.4.2 使用Cairngorm重构CairngormDemo

运行CairngormDemo效果如图6.1.5所示:

 

6.1.5 CairngormDemo

使用RemoteObject进行开发实现上例并不困难,现在我们使用Cairngorm框架对CairngormDemo进行重构。

(1) 定义服务Service
business文件夹下建立Services.mxml来定义服务。

package domain.app.service

{

import com.adobe.cairngorm.business.ServiceLocator;

import mx.rpc.remoting.mxml.RemoteObject;

 

[Bindable]

public class ProService extends ServiceLocator

{

protected static var instance:ProService;   

//必须是单例, 否则将出现重复注册的错误。

public static function getInstance():ProService{   

if(!instance) instance=new ProService();   

return instance;   

}   

 

public var ro:RemoteObject;

public function ProService(){

ro=new RemoteObject("biz");

ro.endpoint="http://localhost:8080/CairngormDemo/messagebroker/amf";

ro.showBusyCursor=true;

}

}

 

}

 

2创建模型Model

    一般来说,模型Model是一个单例。这时需要自己写这个模型,模型只是用来存储数据。在model文件夹下建立你自己的Model,模型可以实现Cairngorm框架中的接口IModelLocator,但是这个动作是多余的。将模型中需要提供给视图View的数据设置成[Bindable],也可以将Model设置成[Bindable],这样模型变化后,视图会自动更新。

package domain.app.model

{

import mx.collections.ArrayCollection;

 

//[Bindable]   

public class CustomModel

{

[Bindable]   

public var products:ArrayCollection;   

   [Bindable]   

  public var data:*;

    

  protected static var instance:CustomModel;   

  public static function getInstance():CustomModel{   

  if(!instance) instance=new CustomModel;   

  return instance;   

  }   

 

public function CustomModel()

{

}

}

}

 

3绑定视图View到模型Model

  在视图中需要变更的部分,绑定模型中的数据。

<mx:AdvancedDataGrid x="21" y="10" id="adg1" designViewDataType="flat" dataProvider="{CustomModel.getInstance().products}">
  

 

4定义事件。
Cairngorm框架中的事件CairngormEvent继承自Event,它有一个新的功能,就是自己把自己发送出去。比如应用需要登陆,那就应该创建一个登陆事件LoginEvent

package domain.app.events

{

import com.adobe.cairngorm.control.CairngormEvent;

import mx.controls.Alert;

public class FindEvent extends CairngormEvent

{

public static const Find:String="find";

public var cate:String;   

 

 

public function FindEvent(cate:String)

{

super(Find);   

  this.cate=cate;   

}

}

}

5)服务代理
Cairngorrn应用中需要使用一个Delegate来进行服务器的交互。在business文件夹下创建类文件ServiceDelegate。

package domain.app.business

{

import com.adobe.cairngorm.business.ServiceLocator;

import domain.app.service.ProService;

import flash.utils.getDefinitionByName;

import mx.rpc.IResponder;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;

import mx.rpc.remoting.RemoteObject;

 

public class ServiceDelegate

{

private var service:RemoteObject;   

    

  public function ServiceDelegate(responder:IResponder){   

service=ProService.getInstance().getRemoteObject("ro");  

service.getByCate.addEventListener(ResultEvent.RESULT,responder.result);

   service.getByCate.addEventListener(FaultEvent.FAULT,responder.fault);   

  }   

    

  public function doFind(cate:String){   

  service.getByCate(cate);   

  }

 

}

}

 

6处理事件

 创建一个Event后,应用程序需要监听到这个Event并作出相应的处理。例如我已经创建了一个FindEvent,然后还需要创建一个ICommand来处理这个Event。在command文件夹下新建文件FindCommand

package domain.app.command

{

import com.adobe.cairngorm.commands.ICommand;

import com.adobe.cairngorm.control.CairngormEvent;

import com.adobe.cairngorm.view.ViewLocator;

import domain.app.business.ServiceDelegate;

import domain.app.events.FindEvent;

import domain.app.model.CustomModel;

import domain.app.view.ProViewHelper;

import mx.collections.ArrayCollection;

import mx.controls.Alert;

import mx.rpc.IResponder;

public class FindCommand implements ICommand,IResponder

{

public function FindCommand()

{

}

public function execute(event:CairngormEvent):void{   

 var evt:FindEvent = event as FindEvent;   

var delegate:ServiceDelegate =new ServiceDelegate(this);   

delegate.doFind(evt.cate);   

}   

public function result(result:Object):void{   

CustomModel.getInstance().products=result.result as ArrayCollection;   

}   

public function fault(info:Object):void{   

Alert.show(info.toString());

}  

}

}

 

7注册事件到命令Command
Cairngorm框架中有个前端控制器FrontController,它的作用是把Event映射到ICommand。这样某个事件发出后,相应的ICommand会执行。现在需要做的是在controller文件夹中新建一个自定义Controller来继承FrontController

package domain.app.controller

{

import com.adobe.cairngorm.control.FrontController;

import domain.app.command.FindCommand;

import domain.app.events.FindEvent;

public class CustomController extends FrontController

{

public function CustomController()

{

initialize();   

}

private function initialize():void {   

 addCommand(FindEvent.Find, FindCommand);   

 }  

 

}

}

这个CustomController将事件FindEventFindCommand注册在一起,那么FindEvent发出后会创建一个FindCommand来执行业务逻辑。

8初始化框架
框架的好处就是让整个程序体系变得透明,便于扩展和代码重用。现在整个Cairngorm框的实施基本完成,现在需要把它整合到Flex应用当中去。在程序的入口,即Flex的主应用程序Caidemo.mxml中实例化Controller

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   xmlns:s="library://ns.adobe.com/flex/spark"

   xmlns:service="domain.app.business.*"    

 xmlns:controller="domain.app.controller.*"

 xmlns:view="domain.app.view.*"

   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:service1="service.*" viewSourceURL="srcview/index.html">

<fx:Script>

<![CDATA[

import domain.app.events.FindEvent;

import domain.app.model.CustomModel;

import mx.controls.Alert;

 

protected function button1_clickHandler(event:MouseEvent):void

{

 var cate:String=this.catetext.text;   

var b:Boolean= new FindEvent(cate).dispatch();

}

 

]]>

</fx:Script>

<fx:Declarations>

<controller:CustomController id="controll"/>

</fx:Declarations>

<s:Panel width="336" height="265" horizontalCenter="0" verticalCenter="0">

<mx:AdvancedDataGrid x="21" y="10" id="adg1" designViewDataType="flat" dataProvider="{CustomModel.getInstance().products}">

<mx:columns>

<mx:AdvancedDataGridColumn headerText="商品编号" dataField="id"/>

<mx:AdvancedDataGridColumn headerText="商品名称" dataField="pname"/>

<mx:AdvancedDataGridColumn headerText="价格" dataField="price"/>

</mx:columns>

</mx:AdvancedDataGrid>

<s:Button x="228" y="195" id="but1" label="查询" click="button1_clickHandler(event)"/>

<s:TextInput id="catetext" x="75" y="195"/>

</s:Panel>

</s:Application>

运行程序,效果如图6.1.5所示。

 整体上Cairngorm的框架就是这样,你可能发现在ICommand处理一个CairngormEvent时,没有办法获得一个View的引用。没错,这就是它的MVC机制,因为你不应该把业务逻辑和视图View挂钩,但是有时候必须要和View挂钩,那就得用到框架中的ViewHelperViewLocator这两个类了。
ViewHelper类实现接口IMXMLObject,首先自定义一个ViewHelper,然后在视图中引用它。

package domain.app.view

{

import com.adobe.cairngorm.view.ViewHelper;

 

public class ProViewHelper extends ViewHelper

{

public function ProViewHelper ()

{

super();

}

public function update(){   

this.view.but1.label="删除";

  }   

 

}

}

这样,结合ViewLocator类就可以实现对视图的修改。

修改MXML文件如下,请注意加粗的部分。

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   xmlns:s="library://ns.adobe.com/flex/spark"

   xmlns:service="domain.app.business.*"    

 xmlns:controller="domain.app.controller.*"

 xmlns:view="domain.app.view.*"

   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:service1="service.*" viewSourceURL="srcview/index.html">

<fx:Script>

<![CDATA[

import domain.app.events.FindEvent;

import domain.app.model.CustomModel;

import mx.controls.Alert;

 

protected function button1_clickHandler(event:MouseEvent):void

{

 var cate:String=this.catetext.text;   

var b:Boolean= new FindEvent(cate).dispatch();

}

 

]]>

</fx:Script>

<fx:Declarations>

<controller:CustomController id="controll"/>

         <view:ProViewHelper id="pv"/>

</fx:Declarations>

<s:Panel width="336" height="265" horizontalCenter="0" verticalCenter="0">

<mx:AdvancedDataGrid x="21" y="10" id="adg1" designViewDataType="flat" dataProvider="{CustomModel.getInstance().products}">

<mx:columns>

<mx:AdvancedDataGridColumn headerText="商品编号" dataField="id"/>

<mx:AdvancedDataGridColumn headerText="商品名称" dataField="pname"/>

<mx:AdvancedDataGridColumn headerText="价格" dataField="price"/>

</mx:columns>

</mx:AdvancedDataGrid>

<s:Button x="228" y="195" id="but1" label="查询" click="button1_clickHandler(event)"/>

<s:TextInput id="catetext" x="75" y="195"/>

</s:Panel>

</s:Application>

修改FindCommand.as 注意加粗的部分。

package domain.app.command

{

import com.adobe.cairngorm.commands.ICommand;

import com.adobe.cairngorm.control.CairngormEvent;

import com.adobe.cairngorm.view.ViewLocator;

import domain.app.business.ServiceDelegate;

import domain.app.events.FindEvent;

import domain.app.model.CustomModel;

import domain.app.view.ProViewHelper;

import mx.collections.ArrayCollection;

import mx.controls.Alert;

import mx.rpc.IResponder;

public class FindCommand implements ICommand,IResponder

{

public function FindCommand()

{

}

public function execute(event:CairngormEvent):void{   

var evt:FindEvent = event as FindEvent;   

var delegate:ServiceDelegate =new ServiceDelegate(this);   

delegate.doFind(evt.cate);   

}   

public function result(result:Object):void{   

CustomModel.getInstance().products=result.result as ArrayCollection;   

var pv:ProViewHelper = ViewLocator.getInstance().getViewHelper("pv") as ProViewHelper;

pv.update();

}   

public function fault(info:Object):void{   

Alert.show(info.toString());

}  

}

}

 

运行应用 效果如图6.1.6所示。

 

6.1.6  使用ViewHelper

在上例中,查询完毕,查询按钮的文字就变成了删除,通过ViewHelper ViewLocator的结合使用,就可以在Command中获取视图的引用。

1.5 分析经典实例CairngormStore

CairngormStore实例是Adobe开发团队提供的一个关于如何应用Cairngorm框架的实例。对于初学Flex开发和Cairngorm框架的人员有很人的帮助。本节将详细介绍CairngormStore实例的原理、代码实现过程。

CairngormStore实例实现的是一个在线商店网站,功能包括浏览货物、购买货物、统计金额等。编译运行实例。运行效果如图6.1.7所示。

 

6.1.7 CairngormStore实例的运行效果

1.5.1 CairngormStore实例代码分析

CairngormStore实例的代码比较多,这是因为Adobe开发团队提倡的Cairngorm框架本身的结构层次就比较多,再加上作者模块化编程习惯所致。本节将详细分析CairngormStore实例中一些重要的类和文件。通过分析这些类和文件,将有助于理解和学习Cairngorm框架的使用。

(1)使用Product类建立商品数据模型

CairngormStorer实例实现的是一个在线购物的网站,所以商品是最重要的数据之一。CairngormStore实例中使用Product类建立商品数据模型。以下代码是Product类的定义代码。

package com.adobe.cairngorm.samples.store.vo

{

import com.adobe.cairngorm.vo.IValueObject;

import com.adobe.cairngorm.samples.store.util.Comparable;

 

[RemoteClass(alias="com.adobe.cairngorm.samples.store.vo.ProductVO")]

public class ProductVO implements IValueObject, Comparable

{

public function get identifier() : String

{

return String( id );

}

public function toString() : String

{

    var s : String = "ProductVO[id=";

    s += id;

    s += ", name=";

    s += name;

    s += ", description=";

    s += description;

    s += ", price=";

    s += price;

    s += ", image=";

    s += image;

    s += ",thumbnail=";

    s += thumbnail;

    s += " ]";

    return s;

}

[Bindable]

public var id : Number;

[Bindable]

public var name : String;

[Bindable]

public var description : String;

[Bindable]

public var price : Number;

[Bindable]

public var image : String;

[Bindable]

public var thumbnail : String;

}

 

}

本程序中使用RemoteClass语句声明此ProductVO类对应Java中的com.adobe.cairngorm.samples.store.vo.ProductVO类。声明对应关系后的ActionScript数据类型在与Java语言交互时,com.adobe.cairngorm.samples.store.vo.ProductVO类就能识别Flex中定义的ProductVO类。

定义基础的数据模型时应根据客观实际定义模型的属性,并且遵循最小够用原则。ProductVO类中只包括货品id,货品名字、货品描述、货品价格、货品图片、货品动态图片六项属性。

(2) 使用ShoppingCartElement类建立购物条目数据模型

购物车中有消费者选购的每个商品的购买信息,如商品数量、此商品总金额等信息。

CairngormStore实例中使用ShoppingCartElement类建立购物条目数据模型。

以下代码是ShoppingCartElement类的定义代码。

package com.adobe.cairngorm.samples.store.model

{

import com.adobe.cairngorm.samples.store.vo.ProductVO;

public class ShoppingCartElement

{

public function ShoppingCartElement( element : ProductVO )

{

this.element = element;

}

public var element : ProductVO;

public var quantity : Number;

public var name : String;

public var price : Number;

public var totalProductPrice : Number;

}

 

}

(3)使用ShoppingCart类建立购物车数据模型

购物车数据模型包括多个购物条目、总金额等信息。CairngormStore实例中使用shoppingCart类建立购物车数据模型。

以下代码是ShoppingCart类的定义代码。

package com.adobe.cairngorm.samples.store.model

{

import mx.collections.ArrayCollection;

import mx.events.CollectionEvent;

import com.adobe.cairngorm.samples.store.vo.ProductVO;

[Bindable]

public class ShoppingCart

{

public function addElement( element : ProductVO, quantity : Number = 1 ) : void

{

if( quantity <= 0 )

{

quantity = 1;

}

for( var i : uint = 0; i < elements.length; i++ )

{

var shoppingCartElement : ShoppingCartElement = elements[ i ];

if( shoppingCartElement.element.id == element.id )

{

shoppingCartElement.quantity += quantity;

shoppingCartElement.totalProductPrice = shoppingCartElement.price * shoppingCartElement.quantity;

totalProductPrice += shoppingCartElement.price * quantity;

elements.dispatchEvent( new CollectionEvent( CollectionEvent.COLLECTION_CHANGE ) );

return;

}

}

addNewElementToCart( element, quantity );

}

public function deleteElement( element : ProductVO ) : Boolean

{

var deleted : Boolean = false;

var i : int;

for( i = 0; i < elements.length; i++ )

{

var shoppingCartElement : ShoppingCartElement = elements[ i ];

if(shoppingCartElement.element.id === element.id)

{

totalProductPrice -= shoppingCartElement.totalProductPrice;

elements.removeItemAt( i );

deleted = true;

break;

}

}

return deleted;

}

public function getElements() : ArrayCollection

{

return elements;

}

private function addNewElementToCart( element : ProductVO, quantity : Number ):void

{

var shoppingCartElement : ShoppingCartElement = new ShoppingCartElement( element );

shoppingCartElement.quantity = quantity;

shoppingCartElement.name = element.name;

shoppingCartElement.price = element.price;

shoppingCartElement.totalProductPrice = element.price * quantity;

elements.addItem( shoppingCartElement );

totalProductPrice += shoppingCartElement.totalProductPrice;

}

public var elements : ArrayCollection = new ArrayCollection();

public var totalProductPrice : Number = 0;

 

public var shippingCost : Number = 0;

}

 

}

ShoppingCart类中定义了购物条目集、总金额、消费金额三个属性。

addElement()方法用以添加商品。deietElement方法用以删除某一条商品条目。addNewElementToCart方法用以添加新的条目。

(4)使用ShopModelLocator类建立应用程序数据模型

ShopModelLocator类定义了整个应用程序的数据模型,包括购物车实例、当前选择的商品、货币格式、各种状态变量等。

以下代码是ShopModelLocator类的定义代码。

package com.adobe.cairngorm.samples.store.model

{

   import mx.collections.ICollectionView;

   import mx.formatters.CurrencyFormatter;

   

   import com.adobe.cairngorm.model.ModelLocator;

   import com.adobe.cairngorm.samples.store.model.ShoppingCart;

   import com.adobe.cairngorm.samples.store.util.Comparator;

   import com.adobe.cairngorm.samples.store.view.assets.CairngormStoreAssets;

   import com.adobe.cairngorm.samples.store.vo.ProductVO;

   import com.adobe.cairngorm.samples.store.view.checkout.PaymentInformationModel;

   import com.adobe.cairngorm.samples.store.view.checkout.GeneralInformationModel;

   import mx.collections.ArrayCollection;

   

   [Bindable]

   public class ShopModelLocator implements ModelLocator

   {

      private static var modelLocator : ShopModelLocator;

      

      public static function getInstance() : ShopModelLocator

      {

       if ( modelLocator == null )

       {

       modelLocator = new ShopModelLocator();

       }

      

       return modelLocator;

      }

      

      //Constructor should be private but current AS3.0 does not allow it yet (?)...

      public function ShopModelLocator()

      {

         if ( modelLocator != null )

         {

          throw new Error( "Only one ShopModelLocator instance should be instantiated" );

         }

         

         shoppingCart = new ShoppingCart();

         productComparator = new Comparator();

         currencyFormatter = getInitialisedFormatter();

         assets = new CairngormStoreAssets();

      }

   

      private function getInitialisedFormatter() : CurrencyFormatter

      {

         var formatter:CurrencyFormatter = new CurrencyFormatter();

         formatter.currencySymbol = "$";

         formatter.precision = 2;

          

         return formatter;

      }

      

      public var products : ICollectionView;

        

      public var selectedItem : ProductVO;

        

      public var shoppingCart : ShoppingCart;

        

      public var productComparator : Comparator;

        

      public var currencyFormatter : CurrencyFormatter;

        

      public var assets : CairngormStoreAssets;

        

      public var orderConfirmed : Boolean;

      public var creditCardInvalid : Boolean;

      public var cartEmpty : Boolean;

      public var formIncomplete : Boolean;

        

      public var generalInfo : GeneralInformationModel = new GeneralInformationModel();

      

      public var paymentInfo : PaymentInformationModel = new PaymentInformationModel();

        

      public var paymentValidators : ArrayCollection = new ArrayCollection();

      public var generalInfoValidators : ArrayCollection = new ArrayCollection();

      public var workflowState : Number = VIEWING_PRODUCTS_IN_THUMBNAILS;

        

      public static var VIEWING_PRODUCTS_IN_THUMBNAILS : Number = 0;

      public static var VIEWING_PRODUCTS_IN_GRID : Number = 1;

      public static var VIEWING_CHECKOUT : Number = 2;

   }

 

}

建议用户将数据、资源、状态变量都存储于一个类中,这将使得应用程序更简洁和可管理。

(5)使用ShopController类监听事件

ShopController类继承Cairngorm框架的FrontController类,用以监听CairngormEVent

件。以下代码定义了ShopController类。

package com.adobe.cairngorm.samples.store.control

{

import com.adobe.cairngorm.control.FrontController;

import com.adobe.cairngorm.samples.store.command.*

import com.adobe.cairngorm.samples.store.event.UpdateShoppingCartEvent;

import com.adobe.cairngorm.samples.store.event.FilterProductsEvent;

import com.adobe.cairngorm.samples.store.event.GetProductsEvent;;

import com.adobe.cairngorm.samples.store.event.SortProductsEvent;

import com.adobe.cairngorm.samples.store.event.ValidateOrderEvent;

import com.adobe.cairngorm.samples.store.event.ValidateCreditCardEvent;

import com.adobe.cairngorm.samples.store.event.PurchaseCompleteEvent;

/**

 * @version $Revision: $

 */

public class ShopController extends FrontController

{

public function ShopController()

{

initialiseCommands();

}

public function initialiseCommands() : void

{

addCommand( GetProductsEvent.EVENT_GET_PRODUCTS, GetProductsCommand );   

   addCommand( UpdateShoppingCartEvent.EVENT_ADD_PRODUCT_TO_SHOPPING_CART, AddProductToShoppingCartCommand );

  addCommand( UpdateShoppingCartEvent.EVENT_DELETE_PRODUCT_FROM_SHOPPING_CART, DeleteProductFromShoppingCartCommand );   

       addCommand( FilterProductsEvent.EVENT_FILTER_PRODUCTS, FilterProductsCommand );        

       addCommand( SortProductsEvent.EVENT_SORT_PRODUCTS, SortProductsCommand );        

       addCommand( ValidateOrderEvent.EVENT_VALIDATE_ORDER, ValidateOrderCommand );      

       addCommand( ValidateCreditCardEvent.EVENT_VALIDATE_CREDIT_CARD, ValidateCreditCardCommand );          

       addCommand( PurchaseCompleteEvent.EVENT_COMPLETE_PURCHASE, CompletePurchaseCommand );

}

}

}

ShopController类监听全部的CaimgormEvent事件。一旦事件发生,ShopController类将很快找到对应的命令类执行。

addCommand方法是FrontController类中定义的方法,用以添加对CaimgormEvent事件的监听,并确定事件类与命令类的对应关系。

要使ShopController类监听全部事件,需要将其添加到主程序中。以下代码在主程序中添加ShopController组件。

<control:ShopController id="controller" />

(6)ServiceLocator类中定义服务

CairngormStrore实例中使用<mx:RemoteObject>组件调用Java类。Cairngorm框架中建议在ServiceLoator类中定义各种服务,这样通过ServiceLocator类的getService()方法就可在任何文件中调用服务。ServiceLocator类通常在MXML文件中被定义为组件。

以下代码是Services.mxml”文件的定义代码。

<?xml version="1.0" encoding="utf-8"?>

<cairngorm:ServiceLocator

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:cairngorm="http://www.adobe.com/2006/cairngorm">

 

    <mx:RemoteObject id="productService" destination="productServiceImpl"

endpoint="http://localhost:8400/store/messagebroker/amf"

      showBusyCursor="true">

    </mx:RemoteObject>

 

    <mx:RemoteObject id="creditCardService" destination="creditCardServiceImpl"

showBusyCursor="true">

    </mx:RemoteObject>

   

 

</cairngorm:ServiceLocator>

<mx:RemoteObject.组件的destination属性指明调用的Java服务名。Java服务名对应的

Java类在“WEB-INF/flex”下的“remoting-config.xml”文件中定义。

以下代码是remoting-config.xml”文件的定义代码。

<?xml version="1.0" encoding="UTF-8"?>

<service id="remoting-service"

    class="flex.messaging.services.RemotingService">

 

    <adapters>

        <adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>

    </adapters>

 

    <default-channels>

        <channel ref="my-amf"/>

    </default-channels>

<destination id="productServiceImpl">

<properties>

<source>com.adobe.cairngorm.samples.store.business.ProductDelegate</source>

</properties>

</destination>

<destination id="creditCardServiceImpl">

<properties>

<source>com.adobe.cairngorm.samples.store.business.CreditCardDelegate</source>

</properties>

</destination>

</service>

定义Services.mxml“文件后,同样需要将“Services.mxml”作为组件嵌入主程序中。

以下代码在主程序中添加Services组件。

<business:Services id="services" />

7)创建自定义事件

CairngormStrore实例中定义了不少事件。本小节以GetProductsEvent事件为例,介绍如

何创建自定义事件。其他事件的定义大同小异。

GetProductsEvent类继承于Cairngorm框架的CairngormEvent类,用以表示获得商品数

据事件。

以下代码定义了GetProductsEvent类。

package com.adobe.cairngorm.samples.store.event

{

import flash.events.Event;

import com.adobe.cairngorm.control.CairngormEvent;

 

public class GetProductsEvent extends CairngormEvent

{

public static var EVENT_GET_PRODUCTS : String = "getProducts";

 

public var position : int;

/**

 * Constructor.

 */

public function GetProductsEvent()

{

super( EVENT_GET_PRODUCTS );

}

     

      /**

       * Override the inherited clone() method, but don't return any state.

       */

override public function clone() : Event

{

return new GetProductsEvent();

}

}

}

 一个事件类中一般包括事件的标识字符串,事件可携带的数据、构造函数等。使用Cairngorm框架中的CairngormEventDispatcher类可广播事件,其语法如下:

CairngormEventDispatcher.getInstance().dispatchEvent(CaurbgirnEvent 事件变量);

以下代码使用CairngormEventDispatcher类广播GetProductsEvent事件。

Var evt: GetProductsEvent = new GetProductsEvent();

evt.position=3;

CairngormEventDispatcher.getInstance().dispatchEvent(evt);

(8)创建自定义命令

命令一般对应一个事件,所以两者的取名很相似。例如,GetProductsEvent事件的对应

命令为GetProductsCommand

命令类必须实现Cairngorlm框架的ICommand接口类,但不一定要实现IResponder接口类。若命令执行后有返回结果或后续动作,那么需要实现IResponder接口类。若命令执行后

没有返回结果或后续动作,那么只需要实现ICommand接口类。

以下代码定义了GetProductsCommand命令类。GetProductsCommand类执行后是有返回

结果的。

package com.adobe.cairngorm.samples.store.command

{

import com.adobe.cairngorm.commands.ICommand;

import com.adobe.cairngorm.control.CairngormEvent;

import com.adobe.cairngorm.samples.store.business.ProductDelegate;

import com.adobe.cairngorm.samples.store.model.ShopModelLocator;

import com.adobe.cairngorm.samples.store.util.Comparator;

import mx.collections.ICollectionView;

import mx.collections.Sort;

import mx.collections.SortField;

import mx.controls.Alert;

import mx.rpc.IResponder;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;

import mx.utils.ArrayUtil;

/**

 * @version $Revision: $

 */

public class GetProductsCommand implements ICommand, IResponder

{

   public function GetProductsCommand()

{  

}

public function execute( event : CairngormEvent ): void

{

if( ShopModelLocator.getInstance().products == null )

{

   var delegate : ProductDelegate = new   ProductDelegate( this );

delegate.getProducts();

}

else

{

Alert.show( "Products already retrieved!" );

return;

}

}

public function result( event : Object ) : void

{

 

var products : ICollectionView = ICollectionView( event.result );

var model : ShopModelLocator = ShopModelLocator.getInstance();

// sort the data

var sort :Sort = new Sort();

   sort.fields = [ new SortField( "name", true ) ];

   products.sort = sort;

   products.refresh();

   

    // set the products on the model

model.selectedItem = products[ 0 ];

model.products = products;

model.workflowState = ShopModelLocator.VIEWING_PRODUCTS_IN_THUMBNAILS;

}

public function fault( event : Object ) : void

{

var faultEvent : FaultEvent = FaultEvent( event );

Alert.show(faultEvent.fault.toString());

Alert.show( "Products could not be retrieved!" );

}

}

 

}

“class GetProductsCommand implements ICommand, IResponder”表示GetProductsCommand类完成了ICommand接口和IResponder接口。

execute方法是命令类的执行函数。result方法是命令类的正确返回处理函数。fault方法是命令类的异常返回处理函数。需要说明的是,在Cairngorm。框架2.2版本之前,正确返回处理函数和异常返回处理函数分别为。onResultonFault

本程序中在命令执行函数中使用了ProductDelegate类,称之为业务代理类。习惯上,在远程调用服务或复杂逻辑时会使用业务代理类。这样有利于简化代码和提高重用性。

以下代码是ProductDelegate类的定义代码。

package com.adobe.cairngorm.samples.store.business

{

import com.adobe.cairngorm.business.ServiceLocator;

import mx.controls.Alert;

import mx.rpc.AbstractOperation;

import mx.rpc.IResponder;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;

 

/**

 * @version $Revision: $

 */

public class ProductDelegate

{

public function ProductDelegate( responder : IResponder )

{

this.service = ServiceLocator.getInstance().getRemoteObject( "productService" );

this.responder = responder;

}

public function getProducts() : void

{

Alert.show(service+'');

var call : Object = service.getProducts();

call.addResponder( responder );

}

private var responder : IResponder;

private var service : Object;

}

 

}

ProductDelegate类在构造时将“productService”服务赋值给service变量,所以“service.getProducts();”语句就能调用相应Java类的getProducts()方法。

GetProductsCommand类中调用ProductDelegate类的语句为“var delegate: ProductDelegate

=new ProductDelegate(this);”,此处this代表GetProductsCommand类本身。

ProductDelegate类的构造函数中“this.responder=responder;”,此处第一个responder变量表示ProductDelegate类的成员变量,第二个responder变量表示传递来的参数。结合上述两声语句就不难发现,ProductDelegate类的成员变量responder就表示GetProductsCommand类的实例。

Call变量接收了调用getProduts()方法的数据。“call.addResponder(respibder);”语句将call变量中的数据返还给responder变量,即GetProductsCommand类。

(9)视图外观分析

CairngormStore实例的视图外观(MXML文件)存储于“view”文件夹中。不同视图外观根据功能不同又存储于不同的子文件夹下。“view”文件夹下的文件组织结构如图6.1.8所示。

 

6.1.8 view”文件夹下的文件组织结构

assets”文件夹存放了图标资源。“checkout”文件夹存放了用户结算时的视图。“productchooser”文件夹存放了商品过滤器视图(改变拖动条的值过滤不同价格的商品)。“productdetails”文件夹存放了商品详细信息视图。“productview”文件夹存放了商品显示的两种模式视图。“shoppingcart”文件夹存放了购物车视图。

CairngormStore实例的主程序(Main.mxml)视图包括了“BodyPanel.mxml,productDetails.mxml”,“ShoppingCartView.mxml”,“CopyrightButton.mxml”四个自定义组件。

main.mxml”视图分解说明如图6.1.9所示。

 

6.1.9 main.mxml”视图分解

自定义组件,如BodyPanel.mxml”又由更小的自定义组件构成。CairmgormStore实例的视图关系如图6.1.10所示。

 

6.1.10 CairmgormStore实例的视图关系

CairmgormStore实例的视图比较复杂,但也很精妙。下面将详细分析“BodyPanel.mxml

组件的视图。学员可以举一反三,分析其他组件的视图。以下代码是BodyPanel.mxml”的MXML代码。

<?xml version="1.0" encoding="utf-8"?>

<mx:Panel

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:view="com.adobe.cairngorm.samples.store.view.*"

xmlns:chooser="com.adobe.cairngorm.samples.store.view.productchooser.*" >

 

<view:ProductsAndCheckoutViewStack />

<view:ProductsAndCheckoutControlBar />

</mx:Panel>

显然,BodyPanel.mxml”组件只包含“ProductsAndCheckoutViewStack.mxml“组件和”ProductsAndCheckoutControlBar”组件。“ProductsAndCheckoutViewStack.mxml“组件定义了三种显示模式:图片、文字、结算页面。

以下代码是“ProductsAndCheckoutViewStack.mxml“组件的主要MXML代码。

<mx:ViewStack

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:view="com.adobe.cairngorm.samples.store.view.*"

xmlns:productview="com.adobe.cairngorm.samples.store.view.productview.*"

xmlns:checkout="com.adobe.cairngorm.samples.store.view.checkout.*"

width="100%" height="100%"

selectedIndex="{ model.workflowState }" >

 

<productview:GraphicalProductList

id="graphicalProductList"

products="{ model.products }"

select="model.selectedItem = event.target.selectedItem;" />

 

<productview:TextualProductList

id="textualProductList"

products="{ model.products }"

selectedItem="{ model.selectedItem }"

select="model.selectedItem = event.target.selectedItem"

currencyFormatter="{ model.currencyFormatter }" />

  

<checkout:Checkout

id="checkout"

shoppingCart="{ model.shoppingCart }"

currencyFormatter="{  model.currencyFormatter }" />

 

</mx:ViewStack>

<rnx: ViewStack>组件可存储多个视图页面,当前页面与selectedIndex属性直接相关。本

程序中selectedIndex属性绑定至“model.workflowState“。workflowState正是ShopModelLocator类中存储的显示模式状态。其中,0表示图片模式,1表示文字模式,2表示结算页面。所以用户只需要修改“model.workflowState”的值就可以更改视图。

"GraphicalProductList.mxml”组件是图片模式下的显示视图,.主要MXML代码如下:

<mx:Canvas

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:productview="com.adobe.cairngorm.samples.store.view.productview.*"

width="100%" height="100%" >

<mx:TileList id="tileListComp"

   width="100%"

   height="100%"

dataProvider="{ShopModelLocator.getInstance().products}"

itemRenderer="com.adobe.cairngorm.samples.store.view.productview.ProductThumbnail"

columnWidth="122" rowHeight="118"

dragEnabled="true"

change="updateSelectedProduct( event );"

borderStyle="none" />

</mx:Canvas>

本程序中最重要的部分在于itemRenderer属性。<mx:TileList>组件是一个列表,其中每

一项的显示形式由itemRenderer属性指定。

“com.adobe.cairngorm.samples.store.view.productview.ProductThumbnail“表示每一项的显示视图由“ProductThumbnail.rnxmL”组件决定。

以下代码是“ProductThumbnail.rnxmL”组件的主要MXML代码。

<mx:VBox

xmlns:mx="http://www.adobe.com/2006/mxml"

width="100%"

height="100%"

styleName="outerProductThumbnail">

 

    <mx:VBox

     id="thumbComp"

     width="100%"

     height="100%"  

clipContent="false"

styleName="innerProductThumbnail"

visible="false"

creationComplete="addComparable( event );">

<mx:Image

id="image"

source="{ data.image }"

width="75"

height="70"

complete="thumbComp.visible = true;" />

<mx:Label

text="{ data.name }"

height="20" />

<mx:Label

text="{ model.currencyFormatter.format( data.price ) }"

height="20"

styleName="priceThumb" />

</mx:VBox>

 

</mx:VBox>

本程序就是图片模式下单个商品的显示视图。data成员变量存储了上一级视图传递来的数据,即上一级视图datarovider属性的单条数据。

本章详细介绍了CairngormStore实例的代码分析。CairngormStore实例涉及的技术包括Flex技术、Java技术、Cairngorm框架等,是应用Flex的经典范例。通过本章实例的学习,学员应该能够举一三地应用Flex技术开发大中型应用程序,同时也能更好地理解Flex如何与Java进行通信。


任务实训部分 

 

实训任务1:完成BodyPanel.mxml的基本功能

训练技能点

Ø 控件的综合运用

Ø RemotingObject

Ø Cairngorm框架

需求说明

在理论课基础上,根据6.1.10所描述的视图关系,开发BodyPanel.mxml界面并实现基本功能

实现思路

1)创建Flex项目,将此项目的服务器技术选择为J2EE服务器(无需使用远程对象访问服务) 并添加Cairngorm.swc

2)切换到MyEclipese  java 开发视图,开始服务器端开发。

创建一个POJO类用于描述商品信息。

package com.adobe.cairngorm.samples.store.vo;

 

public class ProductVO

{

private int id;

 

private String name;

 

private String description;

 

private float price;

 

private String image;

 

private String thumbnail;

public int getId()

{

return id;

}

 

public void setId( int id )

{

this.id = id;

}

 

public String getName()

{

return name;

}

 

public void setName( String name )

{

this.name = name;

}

 

public String getDescription()

{

return description;

}

 

public void setDescription( String description )

{

this.description = description;

}

 

public int getDescriptionLength()

{

return (description == null) ? 0 : description.length();

}

 

public float getPrice()

{

return price;

}

 

public void setPrice( float price )

{

this.price = price;

}

 

public String getImage()

{

return image;

}

 

public void setImage( String image )

{

this.image = image;

}

 

public String getThumbnail()

{

return thumbnail;

}

 

public void setThumbnail( String thumbnail )

{

this.thumbnail = thumbnail;

}

 

 

}

 

创建ProductDao.java Dao.java类,在该类中模拟商品的数据库操作。

Dao.java

package com.adobe.cairngorm.samples.store.dao;

 

public abstract class DAO

{

 

public DAO()

{

}

 

protected abstract String getEntityName();

 

 

}

 

ProductDao.java

package com.adobe.cairngorm.samples.store.dao;

 

import java.util.LinkedList;

import java.util.List;

 

import com.adobe.cairngorm.samples.store.dao.DAO;

import com.adobe.cairngorm.samples.store.vo.ProductVO;

 

public class ProductDAO extends DAO

{

 

private List products = new LinkedList();

 

 

public ProductDAO()

{

}

 

public String getEntityName()

{

return "Product";

}

 

public List listProducts() throws Exception

{

return createProducts();

}

 

public void addProduct( ProductVO product ) throws Exception

{

 

products.add( product );

}

 

//模拟数据库数据

private List createProducts() throws Exception

{

products = new LinkedList();

ProductVO product1 = new ProductVO();

 

product1.setId( 1 );

product1.setName( "USB Watch" );

product1

.setDescription( "So, you need to tell the time of course, but you also need a way to carry your valuable data with you at all times (you know - your MP3 files, favorite images, your ThinkGeek shopping list). This watch can handle the mission for you and do it in style. It can store up to 256 Megs of data." );

product1.setPrice( 129.99f );

product1.setImage( "assets/products/usbwatch.jpg" );

product1.setThumbnail( "assets/products/usbwatch_sm.jpg" );

products.add( product1 );

 

ProductVO product2 = new ProductVO();

product2.setId( 2 );

product2.setName( "007 Digital Camera" );

product2

.setDescription( "There is finally a hi-tech gadget from Q''s laboratory that can be had by the measly (albeit smart) masses who are not fortunate enough to carry a license to kill. This inconspicuous Zippo look-alike actually contains a digital camera capable of holding over 300 images." );

product2.setPrice( 99.99f );

product2.setImage( "assets/products/007camera.jpg" );

product2.setThumbnail( "assets/products/007camera_sm.jpg" );

products.add( product2 );

 

ProductVO product3 = new ProductVO();

product3.setId( 3 );

product3.setName( "2-Way Radio Watch" );

product3

.setDescription( "The only wristwatch with a 2-way radio available to date. It features a built-in 22-channel FRS walkie talkie with a 1.5-mile range. The voice-activated feature allows you to speak into the microphone and your words will be beamed directly to the speaker of any other FRS walkie talkie user." );

product3.setPrice( 49.99f );

product3.setImage( "assets/products/radiowatch.jpg" );

product3.setThumbnail( "assets/products/radiowatch_sm.jpg" );

products.add( product3 );

 

ProductVO product4 = new ProductVO();

product4.setId( 4 );

product4.setName( "USB Desk Fan" );

product4

.setDescription( "Some people are addicted to fans. They have one running when they sleep (the background noise can be soothing) and they have one on their desk at all times. Other people just like to have a little moving air. Whether you are a fan addict or just a casual user, we have just the device for you." );

product4.setPrice( 19.99f );

product4.setImage( "assets/products/usbfan.jpg" );

product4.setThumbnail( "assets/products/usbfan_sm.jpg" );

products.add( product4 );

 

ProductVO product5 = new ProductVO();

product5.setId( 5 );

product5.setName( "Caffeinated Soap" );

product5

.setDescription( "Tired of waking up and having to wait for your morning java to brew? Are you one of those groggy early morning types that just needs that extra kick? Introducing Shower Shock, the original and world''s first caffeinated soap. When you think about it, ShowerShock is the ultimate clean buzz ;)" );

product5.setPrice( 19.99f );

product5.setImage( "assets/products/soap.jpg" );

product5.setThumbnail( "assets/products/soap_sm.jpg" );

products.add( product5 );

 

ProductVO product6 = new ProductVO();

product6.setId( 6 );

product6.setName( "Desktop Rovers" );

product6

.setDescription( "Inspired by NASA''s planetary exploration program, this miniature ''caterpillar drive'' rover belongs officially in the ''way too cool'' category. These mini remote controlled desktop rovers with tank treads are only 4 inches long and ready to explore the 'Alien Landscapes' around your home or office." );

product6.setPrice( 49.99f );

product6.setImage( "assets/products/rover.jpg" );

product6.setThumbnail( "assets/products/rover_sm.jpg" );

products.add( product6 );

 

ProductVO product7 = new ProductVO();

product7.setId( 7 );

product7.setName( "PC Volume Knob" );

product7

.setDescription( "The coolest volume knob your computer has ever seen and so much more. Use it to edit home movies or scroll through long documents and web pages. Program it to do anything you want in any application. Customize it to your own needs and get wild." );

product7.setPrice( 34.99f );

product7.setImage( "assets/products/volume.jpg" );

product7.setThumbnail( "assets/products/volume_sm.jpg" );

products.add( product7 );

 

ProductVO product8 = new ProductVO();

product8.setId( 8 );

product8.setName( "Wireless Antenna" );

product8

.setDescription( "A Cantenna is simply an inexpensive version of the long-range antennas used by wireless internet providers and mobile phone companies. Now, with your own Cantenna you can extend the range of your wireless network or connect to other wireless networks in your neighborhood." );

product8.setPrice( 49.99f );

product8.setImage( "assets/products/cantena.jpg" );

product8.setThumbnail( "assets/products/cantena_sm.jpg" );

products.add( product8 );

 

ProductVO product9 = new ProductVO();

product9.setId( 9 );

product9.setName( "TrackerPod" );

product9

.setDescription( "TrackerPod is a small robotic tripod on which you mount a webcam, and TrackerCam is Artificial Intelligence software to control camera movement from your computer. Together they perform the function of a robotic camera-man for your webcam." );

product9.setPrice( 129.99f );

product9.setImage( "assets/products/trackerpod.jpg" );

product9.setThumbnail( "assets/products/trackerpod_sm.jpg" );

products.add( product9 );

 

ProductVO product10 = new ProductVO();

product10.setId( 10 );

product10.setName( "Caffeinated Sauce" );

product10

.setDescription( "After months of sleepless nights, we finally came up with something we could bottle up and sell to the masses. A hot sauce (extremely hot btw) that tastes great and has caffeine in it!" );

product10.setPrice( 6.99f );

product10.setImage( "assets/products/hotsauce.jpg" );

product10.setThumbnail( "assets/products/hotsauce_sm.jpg" );

products.add( product10 );

 

ProductVO product11 = new ProductVO();

product11.setId( 11 );

product11.setName( "Thinking Putty" );

product11

.setDescription( "The Ultimate Stress Reduction office toy is here. Of course you remember playing with putty as a kid. Welp, this aint your kids putty. Adult sized, and as feature-rich as your favorite Operating System, the Smart Mass putty from ThinkGeek makes living life fun all over again." );

product11.setPrice( 11.99f );

product11.setImage( "assets/products/putty.jpg" );

product11.setThumbnail( "assets/products/putty_sm.jpg" );

products.add( product11 );

 

ProductVO product12 = new ProductVO();

product12.setId( 12 );

product12.setName( "Ambient Orb" );

product12

.setDescription( "The Ambient Orb is a device that slowly transitions between thousands of colors to show changes in the weather, the health of your stock portfolio, or if your boss or friend is on instant messenger. It is a simple wireless object that unobtrusively presents information." );

product12.setPrice( 149.99f );

product12.setImage( "assets/products/orb.jpg" );

product12.setThumbnail( "assets/products/orb_sm.jpg" );

products.add( product12 );

 

ProductVO product13 = new ProductVO();

product13.setId( 13 );

product13.setName( "USB Microscope" );

product13

.setDescription( "The USB connected Computer Microscope allows you to turn the ordinary into the extraordinary for hours of fun and learning. View specimens collected around the house, backyard, your desk, or the fridge. Look at the micro-printing on a dollar bill or examine the traces on your motherboard." );

product13.setPrice( 54.99f );

product13.setImage( "assets/products/microscope.jpg" );

product13.setThumbnail( "assets/products/microscope_sm.jpg" );

products.add( product13 );

 

ProductVO product14 = new ProductVO();

product14.setId( 14 );

product14.setName( "Flying Saucer" );

product14

.setDescription( "The flying saucer his surpisingly quiet during operation and so sneaking up on your fellow co-workers is quite easy. The multi-controller Transmitter modulates the thrust from each propeller independently allowing you to take off and land vertically, spin in place, and fly in all directions!" );

product14.setPrice( 69.99f );

product14.setImage( "assets/products/ufo.jpg" );

product14.setThumbnail( "assets/products/ufo_sm.jpg" );

products.add( product14 );

 

ProductVO product15 = new ProductVO();

product15.setId( 15 );

product15.setName( "Levitating Globe" );

product15

.setDescription( "These electromagnetic suspended globes are actually high-tech instruments. A magnetic field sensor permanently measures the height at which the globes are suspended. This sensor feeds that data into a micro computer in the base of the unit." );

product15.setPrice( 89.99f );

product15.setImage( "assets/products/globe.jpg" );

product15.setThumbnail( "assets/products/globe_sm.jpg" );

products.add( product15 );

 

ProductVO product16 = new ProductVO();

product16.setId( 16 );

product16.setName( "Personal Robot" );

product16

.setDescription( "The ER1 is the first robot with professional-level robotics software technologies and industrial-grade hardware designed for enthusiasts, like you, who are interested in technology that takes advantage of your technical skills and your imagination." );

product16.setPrice( 139.99f );

product16.setImage( "assets/products/robot.jpg" );

product16.setThumbnail( "assets/products/robot_sm.jpg" );

products.add( product16 );

 

return products;

}

 

}

 

创建业务类ProductDelegate.java

package com.adobe.cairngorm.samples.store.business;

 

import java.util.List;

 

import com.adobe.cairngorm.samples.store.dao.ProductDAO;

public class ProductDelegate

{

public List getProducts() throws Exception

{

List list = new ProductDAO().listProducts();

return list;

}

}

 

remoting-config.xml 中配置业务类。

<?xml version="1.0" encoding="UTF-8"?>

<service id="remoting-service"

    class="flex.messaging.services.RemotingService">

 

    <adapters>

        <adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>

    </adapters>

 

    <default-channels>

        <channel ref="my-amf"/>

    </default-channels>

<destination id="productServiceImpl">

<properties>

<source>com.adobe.cairngorm.samples.store.business.ProductDelegate</source>

</properties>

</destination>

</service>

 

(3)切换回Flash视图,进行客户端开发 。

定义ProductVO.as与后台pojo类对应。

package com.adobe.cairngorm.samples.store.vo

{

import com.adobe.cairngorm.samples.store.util.Comparable;

import com.adobe.cairngorm.vo.IValueObject;

 

[RemoteClass(alias="com.adobe.cairngorm.samples.store.vo.ProductVO")]

public class ProductVO implements IValueObject, Comparable

{

public function get identifier() : String

{

return String( id );

}

public function toString() : String

{

    var s : String = "ProductVO[id=";

    s += id;

    s += ", name=";

    s += name;

    s += ", description=";

    s += description;

    s += ", price=";

    s += price;

    s += ", image=";

    s += image;

    s += ",thumbnail=";

    s += thumbnail;

    s += " ]";

    return s;

}

[Bindable]

public var id : Number;

[Bindable]

public var name : String;

[Bindable]

public var description : String;

[Bindable]

public var price : Number;

[Bindable]

public var image : String;

[Bindable]

public var thumbnail : String;

}

 

}

定义事件对象GetProductsEvent.as,该事件将会在主程序初始化的时候被派发。

package com.adobe.cairngorm.samples.store.event

{

import flash.events.Event;

import com.adobe.cairngorm.control.CairngormEvent;

 

public class GetProductsEvent extends CairngormEvent

{

public static var EVENT_GET_PRODUCTS : String = "getProducts";

 

public var position : int;

/**

 * Constructor.

 */

public function GetProductsEvent()

{

super( EVENT_GET_PRODUCTS );

}

     

      /**

       * Override the inherited clone() method, but don't return any state.

       */

override public function clone() : Event

{

return new GetProductsEvent();

}

}

}

 

定义Service组件,用来与服务器端通信获取数据。

<?xml version="1.0" encoding="utf-8"?>

<cairngorm:ServiceLocator

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:cairngorm="http://www.adobe.com/2006/cairngorm">

 

    <mx:RemoteObject id="productService" destination="productServiceImpl"

endpoint="http://localhost:8080/sj51/messagebroker/amf"

      showBusyCursor="true">

    </mx:RemoteObject>

 

 

   

 

</cairngorm:ServiceLocator>

 

开发Bussiness Delegates组件 负责实现业务逻辑。

package com.adobe.cairngorm.samples.store.business

{

import com.adobe.cairngorm.business.ServiceLocator;

import mx.controls.Alert;

import mx.rpc.AbstractOperation;

import mx.rpc.IResponder;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;

 

/**

 * @version $Revision: $

 */

public class ProductDelegate

{

public function ProductDelegate( responder : IResponder )

{

this.service = ServiceLocator.getInstance().getRemoteObject( "productService" );

this.responder = responder;

}

public function getProducts() : void

{

var call : Object = service.getProducts();

call.addResponder( responder );

}

private var responder : IResponder;

private var service : Object;

}

 

}

 

开发模型组件用来保存数据并关联到组件。

package com.adobe.cairngorm.samples.store.model

{

   import mx.collections.ICollectionView;

   import mx.formatters.CurrencyFormatter;

   

   import com.adobe.cairngorm.model.ModelLocator;

  

   import com.adobe.cairngorm.samples.store.util.Comparator;

  

   import com.adobe.cairngorm.samples.store.vo.ProductVO;

 

   import mx.collections.ArrayCollection;

   

   [Bindable]

   public class ShopModelLocator implements ModelLocator

   {

      private static var modelLocator : ShopModelLocator;

      

      public static function getInstance() : ShopModelLocator

      {

       if ( modelLocator == null )

       {

       modelLocator = new ShopModelLocator();

       }

      

       return modelLocator;

      }

      

      //Constructor should be private but current AS3.0 does not allow it yet (?)...

      public function ShopModelLocator()

      {

         if ( modelLocator != null )

         {

          throw new Error( "Only one ShopModelLocator instance should be instantiated" );

         }

         

       

         productComparator = new Comparator();

         currencyFormatter = getInitialisedFormatter();

      

      }

   

      private function getInitialisedFormatter() : CurrencyFormatter

      {

         var formatter:CurrencyFormatter = new CurrencyFormatter();

         formatter.currencySymbol = "$";

         formatter.precision = 2;

          

         return formatter;

      }

      

      public var products : ICollectionView;

        

      public var selectedItem : ProductVO;

        

 

        

      public var productComparator : Comparator;

        

      public var currencyFormatter : CurrencyFormatter;

        

    

        

    

   }

 

}

 

开发Command组件负责处理GetProductsEvent事件。

package com.adobe.cairngorm.samples.store.command

{

import com.adobe.cairngorm.commands.ICommand;

import com.adobe.cairngorm.control.CairngormEvent;

import com.adobe.cairngorm.samples.store.business.ProductDelegate;

import com.adobe.cairngorm.samples.store.model.ShopModelLocator;

import com.adobe.cairngorm.samples.store.util.Comparator;

import mx.collections.ICollectionView;

import mx.collections.Sort;

import mx.collections.SortField;

import mx.controls.Alert;

import mx.rpc.IResponder;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;

import mx.utils.ArrayUtil;

/**

 * @version $Revision: $

 */

public class GetProductsCommand implements ICommand, IResponder

{

   public function GetProductsCommand()

{  

}

public function execute( event : CairngormEvent ): void

{

if( ShopModelLocator.getInstance().products == null )

{

  

var delegate : ProductDelegate = new ProductDelegate( this );

delegate.getProducts();

}

else

{

Alert.show( "Products already retrieved!" );

return;

}

}

public function result( event : Object ) : void

{

 

var products : ICollectionView = ICollectionView( event.result );

var model : ShopModelLocator = ShopModelLocator.getInstance();

// sort the data

var sort :Sort = new Sort();

   sort.fields = [ new SortField( "name", true ) ];

   products.sort = sort;

   products.refresh();

   

    // set the products on the model

model.selectedItem = products[ 0 ];

model.products = products;

}

public function fault( event : Object ) : void

{

var faultEvent : FaultEvent = FaultEvent( event );

Alert.show(faultEvent.fault.toString());

Alert.show( "Products could not be retrieved!" );

}

}

 

}

 

开发控制器组件,用来监听事件。

package com.adobe.cairngorm.samples.store.control

{

import com.adobe.cairngorm.control.FrontController;

import com.adobe.cairngorm.samples.store.command.*

import com.adobe.cairngorm.samples.store.event.UpdateShoppingCartEvent;

import com.adobe.cairngorm.samples.store.event.FilterProductsEvent;

import com.adobe.cairngorm.samples.store.event.GetProductsEvent;;

import com.adobe.cairngorm.samples.store.event.SortProductsEvent;

import com.adobe.cairngorm.samples.store.event.ValidateOrderEvent;

import com.adobe.cairngorm.samples.store.event.ValidateCreditCardEvent;

import com.adobe.cairngorm.samples.store.event.PurchaseCompleteEvent;

/**

 * @version $Revision: $

 */

public class ShopController extends FrontController

{

public function ShopController()

{

initialiseCommands();

}

public function initialiseCommands() : void

{

addCommand( GetProductsEvent.EVENT_GET_PRODUCTS, GetProductsCommand );   

}

}

}

 

开发自定义组件ProductsAndCheckoutViewStack.mxml

<?xml version="1.0" encoding="utf-8"?>

 

<mx:ViewStack

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:view="com.adobe.cairngorm.samples.store.view.*"

xmlns:productview="com.adobe.cairngorm.samples.store.view.productview.*"

xmlns:checkout="com.adobe.cairngorm.samples.store.view.checkout.*"

width="100%" height="100%"

 >

 

<mx:Script>

<![CDATA[

import mx.core.UIComponent;

import com.adobe.cairngorm.samples.store.model.ShopModelLocator;

[Bindable]

public var model : ShopModelLocator = ShopModelLocator.getInstance();

]]>

</mx:Script>

<mx:Canvas  width="100%" height="100%" >

 

 

 

 

 <mx:TileList id="tileListComp"

  width="100%"

  height="100%"

  dataProvider="{ShopModelLocator.getInstance().products}"

  itemRenderer="com.adobe.cairngorm.samples.store.view.productview.ProductThumbnail"

  columnWidth="122" rowHeight="118"

  dragEnabled="true"

    borderStyle="none" />

 

 </mx:Canvas>

 

 

</mx:ViewStack>

 

ProductsAndCheckoutViewStack中使用的渲染器组件的代码如下。

<?xml version="1.0" encoding="utf-8"?>

<mx:VBox

xmlns:mx="http://www.adobe.com/2006/mxml"

width="100%"

height="100%"

styleName="outerProductThumbnail">

<mx:Script>

<![CDATA[

import com.adobe.cairngorm.samples.store.util.Comparable;

import com.adobe.cairngorm.model.ModelLocator;

import com.adobe.cairngorm.samples.store.vo.ProductVO;

import com.adobe.cairngorm.samples.store.model.ShopModelLocator;

[Bindable]

public var model : ShopModelLocator = ShopModelLocator.getInstance();

private function addComparable( event : Event ) : void

{

ShopModelLocator.getInstance().productComparator.addComparable(

image,

Comparable( data ) );

}

]]>

</mx:Script>

  

    <mx:VBox

     id="thumbComp"

     width="100%"

     height="100%"  

clipContent="false"

styleName="innerProductThumbnail"

visible="false"

creationComplete="addComparable( event );">

<mx:Image

id="image"

source="{ data.image }"

width="75"

height="70"

complete="thumbComp.visible = true;" />

<mx:Label

text="{ data.name }"

height="20" />

<mx:Label

text="{ model.currencyFormatter.format( data.price ) }"

height="20"

styleName="priceThumb" />

</mx:VBox>

 

</mx:VBox>

创建BodyPanel.mxml组件。

<?xml version="1.0" encoding="utf-8"?>

 

<mx:Panel

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:view="com.adobe.cairngorm.samples.store.view.*"

xmlns:chooser="com.adobe.cairngorm.samples.store.view.productchooser.*" >

 

<view:ProductsAndCheckoutViewStack />

</mx:Panel>

 

创建主应用程序 sj51.mxml

<?xml version="1.0" encoding="utf-8"?>

 

<mx:Application

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:control="com.adobe.cairngorm.samples.store.control.*"

xmlns:business="com.adobe.cairngorm.samples.store.business.*"

xmlns:view="com.adobe.cairngorm.samples.store.view.*"

xmlns:details="com.adobe.cairngorm.samples.store.view.productdetails.*"

xmlns:cart="com.adobe.cairngorm.samples.store.view.shoppingcart.*"

creationComplete="onCreationComplete();"

pageTitle="CairngormStore"

width="973"

height="681"

styleName="main"

horizontalAlign="center" xmlns:s="library://ns.adobe.com/flex/spark">

<mx:Script>

<![CDATA[

import com.adobe.cairngorm.control.CairngormEvent;

import com.adobe.cairngorm.control.CairngormEventDispatcher;

import com.adobe.cairngorm.samples.store.control.ShopController;

import com.adobe.cairngorm.samples.store.event.GetProductsEvent;

import com.adobe.cairngorm.samples.store.model.ShopModelLocator;

import mx.controls.Alert;

[Bindable]

public var model : ShopModelLocator = ShopModelLocator.getInstance();

        

private function onCreationComplete() : void

{

CairngormEventDispatcher.getInstance().dispatchEvent( new CairngormEvent( GetProductsEvent.EVENT_GET_PRODUCTS ) );

}

]]>

</mx:Script>

<!-- ========================================================================== -->

<!-- the ServiceLocator where we specify the remote services -->

<business:Services id="services" />

<!-- the FrontController, containing Commands specific to this appliation -->

<control:ShopController id="controller" />

 

<!-- ========================================================================== -->

 

<mx:Style source="cairngormstore.css" />

<s:Label text="Cairngorm Store" styleName="appTitle" />

<s:HGroup width="100%" height="555"  horizontalAlign="center">

<view:BodyPanel title="Product Catalog" width="512" height="100%" />

 

</s:HGroup>

 

 

</mx:Application>

 

 

4)运行应用程序,效果如图6.2.1所示。

 

6.2.1 BodyPanel.mxml

实训任务2:实现商品详细信息功能

训练技能点

Ø 控件的综合运用

Ø RemotingObject

Ø Cairngorm框架

需求说明

在任务1的基础上继续开发,当用户单击某一商品的时候显示详细的商品信息。

实现思路

(1) 创建组件ProductDetails.mxml

<?xml version="1.0" encoding="utf-8"?>

<mx:Panel

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:details="com.adobe.cairngorm.samples.store.view.productdetails.*"

title="Product Details"

styleName="productDetails">

 

<mx:Script>

<![CDATA[

import com.adobe.cairngorm.control.CairngormEvent;

import com.adobe.cairngorm.control.CairngormEventDispatcher;

import com.adobe.cairngorm.samples.store.model.ShopModelLocator;

import com.adobe.cairngorm.samples.store.vo.ProductVO;

import flash.events.MouseEvent;

import mx.core.DragSource;

import mx.formatters.CurrencyFormatter;

import mx.managers.DragManager;

[Bindable]

public var currencyFormatter : CurrencyFormatter;

[Bindable]

public var selectedItem : ProductVO;

]]>

</mx:Script>

<!-- Visual Effects -->

    <mx:Zoom id="zoom" duration="500"  zoomHeightFrom="1.0" zoomHeightTo="1.1" zoomWidthFrom="1.0" zoomWidthTo="1.1"/>

    <mx:Zoom id="zoomOut" duration="500"  zoomHeightFrom="1.1" zoomHeightTo="1.0" zoomWidthFrom="1.1" zoomWidthTo="1.0"/>

    

 

 

 

<!-- UI Layout -->

<mx:VBox width="100%" height="100%">

<mx:HBox>

<mx:Canvas clipContent="false" width="150" height="140">

<mx:Image

id="image"

source="{ selectedItem.image }"

rollOverEffect="zoom"

rollOutEffect="zoomOut"/>

</mx:Canvas>

<mx:VBox

width="100%"

height="100%"

styleName="productDetailsTitle">

<mx:Label

id="itemName"

text="{ selectedItem.name }"

styleName="title" />

 

<mx:Label

id="price"

text="{ currencyFormatter.format( selectedItem.price ) }"

styleName="price" />

    

</mx:VBox>

</mx:HBox>

<mx:Text

id="description"

width="100%"

height="100%"

text="{ selectedItem.description }"/>

</mx:VBox>

<mx:ControlBar id="productControlBar">

<mx:Label text="Quantity"/>

<mx:NumericStepper

id="numericStepperComp"

width="40"

minimum="1"

maximum="100"

value="1" />

<mx:Button

label="Add to Cart"

 />

</mx:ControlBar>

</mx:Panel>

 

(2) 修改主程序,sj52.mxml 注意加粗部分。

<?xml version="1.0" encoding="utf-8"?>

 

<mx:Application

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:control="com.adobe.cairngorm.samples.store.control.*"

xmlns:business="com.adobe.cairngorm.samples.store.business.*"

xmlns:view="com.adobe.cairngorm.samples.store.view.*"

xmlns:detail="com.adobe.cairngorm.samples.store.productdetails.*"

 

creationComplete="onCreationComplete();"

pageTitle="CairngormStore"

width="973"

height="681"

styleName="main"

horizontalAlign="center" xmlns:s="library://ns.adobe.com/flex/spark">

<mx:Script>

<![CDATA[

import com.adobe.cairngorm.control.CairngormEvent;

import com.adobe.cairngorm.control.CairngormEventDispatcher;

import com.adobe.cairngorm.samples.store.control.ShopController;

import com.adobe.cairngorm.samples.store.event.GetProductsEvent;

import com.adobe.cairngorm.samples.store.model.ShopModelLocator;

import mx.controls.Alert;

[Bindable]

public var model : ShopModelLocator = ShopModelLocator.getInstance();

        

private function onCreationComplete() : void

{

CairngormEventDispatcher.getInstance().dispatchEvent( new CairngormEvent( GetProductsEvent.EVENT_GET_PRODUCTS ) );

}

]]>

</mx:Script>

<!-- ========================================================================== -->

<!-- the ServiceLocator where we specify the remote services -->

<business:Services id="services" />

<!-- the FrontController, containing Commands specific to this appliation -->

<control:ShopController id="controller" />

 

<!-- ========================================================================== -->

 

<mx:Style source="cairngormstore.css" />

<s:Label text="Cairngorm Store" styleName="appTitle" />

<s:HGroup width="100%" height="555"  horizontalAlign="center">

<view:BodyPanel title="Product Catalog" width="512" height="100%" />

<s:VGroup width="370" height="100%">

<detail:ProductDetails

id="productDetailsComp"

width="100%"

height="325"

selectedItem="{model.selectedItem}"

currencyFormatter="{model.currencyFormatter}" />

</s:VGroup>

</s:HGroup>

 

 

</mx:Application>

 

(3) 修改ProductsAndCheckoutViewStack组件。

<?xml version="1.0" encoding="utf-8"?>

 

<mx:ViewStack

xmlns:mx="http://www.adobe.com/2006/mxml"

xmlns:view="com.adobe.cairngorm.samples.store.view.*"

xmlns:productview="com.adobe.cairngorm.samples.store.view.productview.*"

xmlns:checkout="com.adobe.cairngorm.samples.store.view.checkout.*"

width="100%" height="100%"

 >

 

<mx:Script>

<![CDATA[

import com.adobe.cairngorm.samples.store.model.ShopModelLocator;

import mx.core.UIComponent;

]]>

</mx:Script>

<mx:Binding destination="tileListComp.selectedItem" source="ShopModelLocator.getInstance().selectedItem" />

 

<mx:Canvas  width="100%" height="100%" >

 

 

 <mx:Script>

 <![CDATA[

 import mx.controls.Alert;

 import com.adobe.cairngorm.samples.store.model.ShopModelLocator;

 import com.adobe.cairngorm.samples.store.vo.ProductVO;

 

 import mx.collections.ICollectionView;

 

 

 

 public function updateSelectedProduct( event : Object ) : void

 {

 ShopModelLocator.getInstance().selectedItem= event.target.selectedItem;

 

 }

 

 

 ]]>

 </mx:Script>

 

 <mx:TileList id="tileListComp"

  width="100%"

  height="100%"

  dataProvider="{ShopModelLocator.getInstance().products}"

  itemRenderer="com.adobe.cairngorm.samples.store.view.productview.ProductThumbnail"

  columnWidth="122" rowHeight="118"

  dragEnabled="true"

  

  change="updateSelectedProduct( event );"

  borderStyle="none"

  />

 

 </mx:Canvas>

 

 

</mx:ViewStack>

运行应用,效果如图6.2.2所示。

 

6.2.2 商品详细信息


巩固练习

简答题

1)简述Cairngorrn框架的工作流程?

操作题

参考官方的CairngormStore实例代码,独立完成其主要功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

teayear

读后有收获可以支付宝请作者喝咖

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值