`
schy_hqh
  • 浏览: 558093 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

(十)自定义事件并利用事件对象传递数据以及集合元素变化能派发的事件

 
阅读更多
创建和分派事件
1.使用事件可以降低程序的耦合度
2.子类自定义事件,事件可以冒泡,父类声明事件,捕获并处理事件
------------------------------------------------------
要让一个组件广播事件,需要使用dispatchEvent()方法
该方法在flash.events.EventDispatcher类中定义
Flex中的UIComponent类就直接继承自EventDispatcher类
dispatchEvent()接受一个参数,即需要分派的事件对象
在分派事件后,任何监听该事件的对象都会收到通知,相应的事件监听器/处理程序就会执行

如果事件目标(分派事件的对象)不是可见对象,Flash Player会简单将事件对象分派给指定的目标
如:Flash Player会直接将result事件分派给HTTPService组件

如果事件目标是可见的,Flash Player在分派事件时会从最外层容器(Application容器)开始,逐层分派,直至目标组件
如果事件可以冒泡,则还会再次返回Application容器

创建自定义事件
1.创建事件
      为自定义事件添加属性或者方法,必须重写clone()
      该方法负责在原始事件的基础上创建一个新的事件
2.声明事件
3.派发事件
4.监听自定义事件

为集合添加事件监听器,当集合中的元素发生变化时,发生一个事件,触发某种操作
如:shoppingCart中商品数量的变化需要重新计算商品总价
------------------------------------------------------------------
package cart {
	import mx.collections.ArrayCollection;
	import mx.collections.IViewCursor;
	import mx.collections.Sort;
	import mx.collections.SortField;
	import mx.events.CollectionEvent;

	public class ShoppingCart {
		[Bindable]
		public var items:ArrayCollection = new ArrayCollection();//所有商品都将放入此购物车

		[Bindable]
		public var total:Number = 0;//购物车中所有物品的总金额
		/**
		 * 创建购物车的时候就指定排序规则 
		 * 排序字段按product进行排序
		 */		
		public function ShoppingCart() {
			var prodSort:Sort = new Sort();
			var sortField:SortField = new SortField( "product" );
			prodSort.fields = [ sortField ];
			items.sort = prodSort;
			items.refresh();
			
			//为ArrayCollection添加事件监听函数
			//这样做的好处:不用分别在添加或删除购物车中的商品时计算总价
			//而是更全面的考虑到:只要items集合中的数据由变化,就重新计算购物车中的商品总价
			//通过ArrayCollection具备的change事件来实现更好!!
			items.addEventListener(CollectionEvent.COLLECTION_CHANGE,handleItemsChange);
		}
		/**
		 * 添加商品到购物车
		 * 如果已经存在,则更新数量
		 * 否则,直接加入到购物车,默认一次添加1个 
		 * @param item
		 * 
		 */		
		public function addItem( item:ShoppingCartItem ):void {
			if ( isItemInCart( item ) ) {
				updateItem( item );
			} else {
				items.addItem( item );
			}

			//calculateTotal();
		}
		/**
		 * 从购物车中删除某类商品
		 * 使用游标进行删除 
		 * @param item
		 * 
		 */		
		public function removeItem( item:ShoppingCartItem ):void {
			var cursor:IViewCursor = items.createCursor();

			if ( cursor.findFirst( item ) ) {
				cursor.remove();
			}

			//calculateTotal();
		}
		
		/**
		 * 购物车中已经存在该类商品
		 * 通过cursor寻找到该商品并返回 
		 * @param item
		 * @return 如果存在,返回存在的哪个product,否则返回null
		 * 
		 */		
		private function getItemInCart( item:ShoppingCartItem ):ShoppingCartItem {
			var existingItem:ShoppingCartItem;
			var cursor:IViewCursor = items.createCursor();

			var found:Boolean = cursor.findFirst( item );

			if ( found ){
				existingItem = cursor.current as ShoppingCartItem;
			}

			return existingItem; 
		}
		
		/**
		 * 判断购物车中是否已经添加该类商品
		 * @param item
		 * @return 
		 * 
		 */		
		private function isItemInCart( item:ShoppingCartItem ):Boolean {
			var sci:ShoppingCartItem = getItemInCart( item );

			return ( sci != null );
		}
		
		/**
		 * 当购物车中已经添加过此商品,则该方法会通过逻辑判断进而被调用
		 * 更新该商品的数量 
		 * @param item
		 * 
		 */		
		private function updateItem( item:ShoppingCartItem ):void {
			var existingItem:ShoppingCartItem = getItemInCart( item );
			existingItem.quantity += item.quantity;
		}
		
		/**
		 * 统计购物车中所有商品的总价
		 */		
		private function calculateTotal():void{
			var newTotal:Number = 0;
			var existingItem:ShoppingCartItem;

			for ( var i:uint=0; i<items.length; i++ ) {
				existingItem = items[ i ] as ShoppingCartItem;
				newTotal += existingItem.subtotal;
			}
			
			this.total = newTotal;
		}
		
		/**
		 * CollectionEvent是ArrayCollection等集合广播的一个特殊类型的事件
		 * 表示集合中某项发生了变化
		 * 只要ShoppingCart中的商品有变化,都会重新计算商品的总价
		 * 这样就能准确的跟踪购物车中的总金额
		 * @param event
		 * 
		 */		
		private function handleItemsChange(event:CollectionEvent):void {
			calculateTotal();
		}
	}
}



package cart {
	import valueObjects.Product;

	[Bindable]
	public class ShoppingCartItem {
		public var product:Product;//代表某类商品
		private var _quantity:uint;//添加的商品数量
		public var subtotal:Number;//小计该类商品的金额

		public function ShoppingCartItem( product:Product, quantity:uint=1 ){
			this.product = product;
			this._quantity = quantity;
			calculateSubtotal();//这里不能注释掉,第一次添加的时候需要在这里计算金额
		}
		
		public function get quantity():uint
		{
			return _quantity;
		}

		public function set quantity(value:uint):void
		{
			_quantity = value;
			calculateSubtotal();//每次添加商品都会引发数量的改变,set 方法都会被调用,在这里重新计算总价
		}

		private function calculateSubtotal():void{
			this.subtotal = product.listPrice * quantity;
		}
		
		/**
		 * cartGroup中的List中,dataProvider="{shoppingCart.items}"
		 * 将会以toString返回的字符串作为列表呈现
		 * @return 
		 * 
		 */		
		public function toString():String {
			return "[ShoppingCartItem] " + product.prodName + ":" + quantity;
		}
	}
}


ProductItem.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:DataRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
		 xmlns:s="library://ns.adobe.com/flex/spark" 
		 xmlns:mx="library://ns.adobe.com/flex/mx" 
		 width="100%">

	<s:states>
		<s:State name="State1"/>
		<s:State name="expanded"/>
	</s:states>
	
	<!-- 声明自定义事件 -->
	<fx:Metadata>
		[Event(name="addProduct", type="events.ProductEvent")]
		[Event(name="removeProduct", type="events.ProductEvent")]
	</fx:Metadata>
	
	
	<fx:Script>
		<![CDATA[
			import cart.ShoppingCart;
			import cart.ShoppingCartItem;
			
			import events.ProductEvent;
			
			import valueObjects.Product;
			[Bindable]
			public var product:Product;//由flex在为data赋值的时候,将value赋值给product
			
			//public var shoppingCart:ShoppingCart;//购物车从哪里传入呢?通过事件派发添加/删除事件,在ShoppingView中完成,而不是在ProductItem中完成!
			
			//添加某类商品到购物车,添加商品会派发一个addProduct事件
			private function addToCart(product:Product):void {
				var event:Event = new ProductEvent("addProduct",product);//将product放到事件对象event中
				this.dispatchEvent(event);//派发事件
			}
			
			//从购物车中删除该类商品,派发一个removeProduct事件
			private function removeFromCart( product:Product ):void {
				var event:Event = new ProductEvent("removeProduct",product);//将product放到事件对象event中
				this.dispatchEvent(event);//派发事件
			}
			
			//当指定了dataProvider之后,flex会针对数据集中每个数据项创建一个呈现器实例
			//然后将取得的数据放到data中保存
			//这里覆盖data的set方法,利用上述原理,在赋值时直接将数据赋值到product对象中,而不是赋值给data
			public override function set data(value:Object) :void {
				this.product = value as Product; //注意进行类型转换
			}
		]]>
	</fx:Script>
	
	<fx:Declarations>
		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
	</fx:Declarations>
	
	<!-- 商品 -->
	<s:VGroup  id="products">
		<s:Label text="{product.prodName}" id="prodName"/>
		<mx:Image source="assets/{product.imageName}" scaleContent="true" 
				  mouseOver="this.currentState='expanded'"
				  mouseOut="this.currentState='State1'"/>
		<s:Label text="${product.listPrice}" id="price"/>
		<s:Button label="AddToCart" id="add"
				  click="addToCart(product )"/>
		<s:Button label="Remove From Cart" id="remove"
				  click="removeFromCart(product )"/>			
	</s:VGroup>
	
	<!-- 商品详细信息 -->
	<s:VGroup includeIn="expanded" x="200" width="100%">
		<s:RichText text="{product.description}"
					width="50%"/>
		<s:Label text="Certified Organic"
				 visible="{product.isOrganic}"/>
		<s:Label text="Low Fat"
				 visible="{product.isLowFat}"/>
	</s:VGroup>
</s:DataRenderer>


ProductEvent.as
package events
{
	import flash.events.Event;
	
	import valueObjects.Product;
	
	public class ProductEvent extends Event
	{
		public var product:Product;
		
		public function ProductEvent(type:String, product:Product)
		{
			super(type, true);//指定事件可以冒泡
			this.product = product;//将数据作为事件对象的一个属性绑定到对象上进行传递
		}
		
		public override function clone():Event {
			return new ProductEvent(type,product);
		}
		
	}
}


ShoppingView.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" 
		 xmlns:s="library://ns.adobe.com/flex/spark" 
		 xmlns:mx="library://ns.adobe.com/flex/mx" width="0" height="0" xmlns:components="components.*">
	<s:layout>
		<s:HorizontalLayout/>
	</s:layout>
	<s:states>
		<s:State name="State1"/>
		<s:State name="cartView"/>
	</s:states>
	

	<fx:Script>
		<![CDATA[
			import cart.ShoppingCart;
			import cart.ShoppingCartItem;
			
			import components.ProductItem;
			
			import events.ProductEvent;
			
			import mx.collections.ArrayCollection;
			
			import valueObjects.Product;
			[Bindable]
			public var shoppingCart:ShoppingCart = new ShoppingCart();//创建一个购物车,每种商品都使用同一个购物车!
			[Bindable]
			public var groceryInventory:ArrayCollection;//用于存放HTTPService返回的各种商品信息
			
			//查看当前购物车中的商品
			private function handleViewCartClick( event:MouseEvent ):void {
				this.currentState="cartView";
			}
			
			//该方法返回一个字符串,用来作为数据集的呈现方式,由labelFunction函数指定
			//当List中使用labelFunction时,会自动以正确的方式从dataProvider中获取数据并传递到该方法中
			//返回的字符串将作为被呈现的内容
			private function renderProductName(item:ShoppingCartItem):String {
				var product:Product = item.product;
				return "("+item.quantity+")" + product.prodName + " $" + item.subtotal;
			}
			
			
			//对ProductItem派发的addProduct事件进行监听并处理
			public function addProductHandler(event:ProductEvent):void {
				var sci:ShoppingCartItem = new ShoppingCartItem(event.product);//从自定义事件中获取属性
				shoppingCart.addItem(sci);
			}
			
			//对ProductItem派发的removeProduct事件进行监听并处理
			public function removeProductHandler(event:ProductEvent):void {
				var sci:ShoppingCartItem = new ShoppingCartItem(event.product);//从自定义事件中获取属性
				shoppingCart.removeItem(sci);
			}
		]]>
	</fx:Script>
	
	<fx:Declarations>
		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
	</fx:Declarations>
	
	<!-- 该DataGroup被下面的ProductList取代  
	            通过事件冒泡实现商品的添加与删除
	            因为原来在ProductItem中直接对购物车添加或删除商品的操作无法进行
	  	  原因是无法对每个ProductItem都传入同一个购物车
		 [虽然this.parent.parent.shoppingCart可以访问到购物车,但是依赖性太强,不推荐]
		<s:DataGroup width="100%" height="100%" 
					 width.cartView="0" height.cartView="0" visible.cartView="false"
					 dataProvider="{groceryInventory}"
					 itemRenderer="components.ProductItem">
			<s:layout>
				<s:VerticalLayout/>
			</s:layout>
		</s:DataGroup>
	-->
	
	<!-- 使用具有事件监听出派发功能的组件替代原来的DataGroup-->
	<!-- 实现添加/删除商品的步骤:
	     ProductList作为一个组件,通过dataProvider获取到数据
		  在ProductList中又指名了itemRenderer为ProductItem
		  这样,ProductItem中的product属性就可以被赋予值
		  当添加商品的时候,会触发addProduct事件,而且事件可以冒泡
		  在ProductList中对该事件进行了声明,则可以对该事件继续向上冒泡
		  这样,在ShoppingView中就可以对这个事件进行捕获并处理!!!
	           然后,在ProductList组件中就可以指定事件发生后的处理函数了!!!
	-->
	<components:ProductList width="100%" height="100%"
							width.cartView="0" height.cartView="0" visible.cartView="false"
							dataProvider="{groceryInventory}"
							addProduct="addProductHandler(event)"
							removeProduct="removeProductHandler(event)"/>
	
	<!-- 购物车组件 -->
	<s:VGroup id="cartGroup" height="100%"  width.cartView="100%">
		<s:List id="cartList"
				dataProvider="{shoppingCart.items}" includeIn="State1"
				labelFunction="renderProductName"/>			
		<s:Label text="Your Cart Total: ${shoppingCart.total}"/>
		<s:Button label="View Cart" click="handleViewCartClick( event )" includeIn="State1"/>
		<mx:DataGrid includeIn="cartView" id="dgCart" width="100%">
			<mx:columns>
				<mx:DataGridColumn headerText="Column 1" dataField="col1"/>
				<mx:DataGridColumn headerText="Column 2" dataField="col2"/>
				<mx:DataGridColumn headerText="Column 3" dataField="col3"/>
			</mx:columns>
		</mx:DataGrid>
		<s:Button includeIn="cartView" label="Continue Shopping" click="this.currentState=''"/>
	</s:VGroup>
</s:Group>


ProductList.mxml
<?xml version="1.0" encoding="utf-8"?>
<!-- 由于ProductItem已经自定义并声明了事件,所以父类也必须声明那些事件,这样才能对其进行派发与监听 -->
<s:DataGroup xmlns:fx="http://ns.adobe.com/mxml/2009" 
			 xmlns:s="library://ns.adobe.com/flex/spark" 
			 xmlns:mx="library://ns.adobe.com/flex/mx"
			 itemRenderer="components.ProductItem"> <!-- 将itemRenderer指定为ProductItem -->
	<s:layout>
		<s:VerticalLayout/>
	</s:layout>
	
	<!-- 声明ProductItem中的自定义事件 -->
	<fx:Metadata>
		[Event(name="addProduct", type="events.ProductEvent")]
		[Event(name="removeProduct", type="events.ProductEvent")]
	</fx:Metadata>
	
	<fx:Declarations>
		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
	</fx:Declarations>
	
</s:DataGroup>
分享到:
评论

相关推荐

    自定义事件在xcontrol控件调用过程中传递数据

    本文将深入探讨如何在XControl调用过程中利用自定义事件来传递数据,以及在实际应用中的具体实现。 首先,我们需要了解自定义事件的概念。在LabVIEW中,事件是一种通信机制,它允许VIs和控件之间异步交换信息。...

    flex4自定义事件用法

    下面将详细介绍Flex4自定义事件的用法,以及如何在一个完整的项目中导入和运行。 1. **创建自定义事件类** - 首先,我们需要创建一个继承自`Event`类的新类。通常,我们会选择`flash.events.Event`或`mx.events....

    ActionScript的自定义组件及自定义事件例子

    3. **派发事件**:在需要触发事件的地方,使用`dispatchEvent()`方法发送自定义事件。 4. **监听事件**:在接收方组件中,使用`addEventListener()`方法添加事件监听器,处理自定义事件。 在提供的“WinCCALLMine”...

    Flex TitleWindow父子页面的事件派发

    本文将深入探讨如何在Flex的TitleWindow父子页面之间进行有效的事件派发,以及背后的事件机制,这对于理解和优化Flex应用中的交互逻辑至关重要。 ### 1. Flex TitleWindow与事件派发基础 TitleWindow作为Flex中的...

    flex自定义组件事件DEMO

    - 派发事件:在组件中使用dispatchEvent方法触发自定义事件。 3. 事件处理:处理自定义事件通常需要在组件内部注册事件监听器,并在监听器函数中处理事件。监听器可以添加到组件本身或其父组件上,使用...

    Flex4视频教程_02-03用AS自定义事件.rar

    2. **派发自定义事件**:在事件源对象(通常是UIComponent或其他自定义组件)上,使用dispatchEvent方法来派发自定义事件。派发时需要实例化自定义事件,并传入相关参数: ```actionscript var customEvent:...

    EventDispatcher,js事件派发器,javascript事件派发器

    在JavaScript编程中,事件派发器(EventDispatcher)是一个核心概念,它允许对象之间通过事件进行通信,从而实现解耦和模块化的代码设计。EventDispatcher是JavaScript中的一个设计模式,通常用于实现事件驱动的编程...

    flex 自定义控件、事件

    自定义控件可以派发自定义事件,或者监听并响应其他组件的事件。在MXML中,你可以使用`&lt;mx:Metadata&gt;`标签声明自定义事件,然后在代码中使用`dispatchEvent()`方法触发这些事件。 5. **MXML使用**:MXML是一种声明...

    android事件派发验证demo

    下面我们将详细探讨Android事件派发的工作原理、涉及的概念以及如何通过Checkbox动态改变事件的消费和拦截。 首先,Android事件派发主要基于ViewGroup的分发机制和View的事件处理。当用户在屏幕上点击或触摸时,...

    Flex自定义组件和事件

    自定义事件允许开发者创建具有特定含义和数据的事件,以更好地匹配应用的业务逻辑。 #### 2. 创建自定义事件类 自定义事件通常继承自Event类或其子类,如MouseEvent或KeyboardEvent。例如,创建一个名为`...

    主动派发事件总结

    主动派发事件总结主动派发事件总结 - snandy -

    android envent 事件派发机制 源代码

    在Android系统中,事件派发机制是用户界面交互的核心部分,它使得应用程序能够响应用户的触摸操作和其他输入事件。本文将深入解析Android事件派发机制的源代码,帮助开发者理解这一重要概念。 首先,事件的生命周期...

    安卓自定义控件相关-Android自定义view十字按钮本十字按钮可用于智能家电app通过设置listener就可以监听四个方向的点击事件同时其button的反应模式如系统给的button一致。在代码中也给出了另外五个普通按钮进行与十字按钮进行效果对比亦可以学习自定义组件的消息派发机制.rar

    Android自定义view:十字按钮本十字按钮可用于智能家电app,通过设置listener就可以监听四个方向的点击事件,同时其button的反应模式如系统给的button一致。在代码中也给出了另外五个普通按钮进行与十字按钮进行效果...

    Android点击事件派发机制源码分析

    当用户在屏幕上触碰或滑动时,系统会生成一系列的MotionEvent对象,这些事件沿着视图层次结构从上到下进行传递。事件的派发首先由Activity的`dispatchTouchEvent`方法启动。在这个方法中,Activity会检查事件类型,...

    Flex基础培训

    - 在事件对象中设置数据:在派发事件时,将需要传递的数据赋值给自定义事件类的属性。 - 接收并使用数据:在事件处理器中访问这些属性,从而实现数据的有效传递。 #### 四、示例代码解析 以下是一段关于如何创建...

    FLEX 事件机制-自定义事件介绍

    在事件处理函数`myEventHandler`中,你可以访问事件对象的`data`属性,获取传递的数据,并根据需要进行处理: ```actionscript public function myEventHandler(eve:Event):void { input.text = (eve as MyEvent)....

    Flex事件机制详细说明

    ### Flex事件机制详解 #### 一、事件简介 在Flex框架中,事件是应用程序与用户交互的核心机制之一。...此外,了解如何手动触发事件以及如何扩展事件对象的功能,可以帮助开发者更好地应对复杂的应用场景。

    第八节 事件传递参数.docx

    在ActionScript编程中,事件传递参数是一个非常实用的功能,它允许你在不同的类之间发送自定义消息并附带数据。在本示例中,我们将详细探讨如何在ActionScript 3.0中实现事件参数的传递。 首先,我们创建了一个名为...

    精通flex3.0 精通 Flex3.0 LCDS ActionScript 事件

    - **实时数据更新**:利用LCDS的实时推送功能,实现数据的即时更新,并处理相应的`dataChange`事件。 5. **ActionScript与LCDS的交互** - **创建数据服务代理**:通过ActionScript的Proxy类访问LCDS服务,配置...

    flex控件事件

    对于列表和数据网格等控件,滚动事件(ScrollEvent.SCROLL)允许我们对用户滚动行为作出反应,而数据改变事件(DataEvent.COLLECTION_CHANGE)则在数据源发生变化时触发,可用于实时更新UI。 通过深入了解和应用...

Global site tag (gtag.js) - Google Analytics