7.7.用一个复选框渲染器选择DataGrid 列

7.7.1. 问题
我们需要创一个拥有一列CheckBox 的DataGrid,并且这个DataGrid 的表头也有一个CheckBox,当用户点击表头的CheckBox 时,这一列CheckBox 自动被选中或取消选中,我们这里所说的表头就是column 的headerRenderer。
7.7.2. 解决办法
创建一个类做为headerRenderer,并且在这个类里创建一个可以向它所在的DataGrid派发事件的方法,并且可以设置DataGrid 里所有itemRenderer 的属性。
7.7.3. 讨论
Flex 的header renderers 的创建与生命周期要比item renderers 复杂一些。在DataGrid 的生命周期里,任何与header 相关的动作都会引起headerRenderer 的重建。因此你需要在外部保存DataGrid 的状态。因此我们需要用ClassFactory。

在原文中,作者讲解了关于ClassFactory 的使用,这些我们己经在本章的第二节做过说明,所以这里就略过。
前边说了很多理论,下面我们说一下如何实现:
我们需要在mxml 里定义一些变量:
+展开
-ActionScript
// var to hold header renderer's state
public var selectAllFlag:Boolean;
[Bindable]
public var hr:ClassFactory;

selectAllFlag 变量,顾名思义,它用于表示是不是所有行都被选中了。hr 变量,是DataGridColumn 的hearerRenderer,并且被标记为[Bindable]。接下来要做的就是在mxml的creationComplete 方法里为hr 初始化:
+展开
-ActionScript
hr = new ClassFactory(CenteredCheckBoxHeaderRenderer);
hr.properties = {stateHost: this , stateProperty: "selectAllFlag" };

第一行创建了一个ClassFactory的实例,并且把我们自定义的renderer类赋值给factory的generator属性。在第二行赋值了两组key-value给hr的properties属性,renderer被创建后会用这两组key-value初始化。其中stateHost的value是“this”,它代表当前的mxml文件,stateProperty的value是我们在前边定义好的变量“selectAllFlag”的变量名。

下边我们看一下,如何为DataGridColumn指定刚刚创建的ClassFactory实例。
+展开
-XML
<mx:DataGridColumn width="30sortable="falsedataField="addToCartheaderRenderer="{hr}"
itemRenderer="CenteredCheckBoxItemRenderer" />

请注意这里的sortable="false",sortable 的默认值是true 当用户点击一个表的表头时,当前列的数据会自动排序,当用户点击CheckBox 时不应该自动排序,所以这里设置sortable="false"。

下面我们看一下header renderer 的代码:
+展开
-ActionScript
package {
import flash.display.DisplayObject;
import flash.events.MouseEvent;
import flash.text.TextField;
import mx.controls.CheckBox;
import mx.controls.DataGrid;
public class CenteredCheckBoxHeaderRenderer extends CenteredCheckBox {
public var stateHost:Object;
public var stateProperty:String;
override public function set data(value:Object):void { selected = stateHost[stateProperty]; }
// this function is defined by mx.controls.CheckBox
// it is the default handler for its click event
override protected function clickHandler(event:MouseEvent):void {
super.clickHandler(event);
// this is the important line as it updates the external variable
// we've designated to hold our state
stateHost[stateProperty] = selected;
}
}
}

当headerRenderer 被创建或重建时,setter 方法会被调用,我们没有处理传入的值,而是把外部的stateProperty 的值赋给了selected 因为headerRenderer 继承自CheckBox,这里的用意是:因为headerRenderer 会被重建,而之前是否被选中了,我们己经保存在了外部变量stateProperty 里,所以每次重建时,要把selected 用外部变量初始化。而在clickHandler 里,我们做了相反的操作,目地在于将用户操作后的CheckBox 的状态保存起来。

通过上边浅显易懂的例子,向大家讲解了ClassFactory 的使用方法,经实践验证,这是一个最好也是最有效的方式去创建一个可重用的复杂renderer。

现在我们剩下的工作就是:当用户点击了表头的CheckBox 时,要让DataGrid 里的所有CheckBox 跟着选中或取消选中。我们只需要对mxml 文件增加MouseEvent.CLICK 事件的监听,因为所有的事件都会冒泡到这里,headerRenderer 的点击事件也不例外。(我觉得原文在这里提及冒泡有些多余,可能有些读者对flex 事件的冒泡机制还不太了解,在这里我做一下简单的介绍,mxml 里的组件就像一棵树一样,applicaton 就是这棵树的根(当然,如果mxml 是一个module 或component 它的根就是canvas 或其它容器),可能它下边会有一个canvas ,canvas 里可能还包含了N 个canvas,这些canvas 就是这棵树的枝干,它们可能还包含了其它原素,如button 等,如果某个button 发生click 事件,事件会从button所在的结点开始,逐层向自己的父结点dispatch 这个事件,直到根结点为止。在本例中,不必在headerRenderer 上监听,而是在根结点上监听事件,就是原于这个冒泡的事件机制。当然这个冒泡的机制是可以组织或中断的。)

当我们捕捉到MouseEvent.CLICK 事件之后,要判断一下发出这个事件的组件是不是我们自定义的headerRenderer, 如果是,就说明header 的CheckBox 被点击了,这时我们要根据它的选中状态更新DataGrid 的dataProvider。因为dataProvider 里有一个字段addToCart 己经绑定在了DataGrid itemRenderer 中的CheckBox 的selected 属性了。我们把dataProvider 里所有addToCart 属性全部更新为header CheckBox 的选中状态(即obj.addToCart = CenteredCheckBoxHeaderRenderer(event.target).selected),这样itemRenderer 中的CheckBox 就自动选中或取消选中了。接下来使用了dataProvider 的itemUpdated 方法,此方法用于通知DataGrid,它的dataProvider 中的某个item(obj)的某个字段(addToCart)己经更新了,请重新刷新它。(我觉得在这里引入itemUpdated 似乎没有什么必要,和上边的冒泡一样,它们大大的加重了本节的难度。如果你过看flex2 的一些代码,会使用notifyItemUpdate 方法,现在被替换成itemUpdated 方法。)
+展开
-ActionScript
// click events will still bubble
private function onCheckBoxHeaderClick(event:MouseEvent):void {
// make sure click came from header
if (event.target is CenteredCheckBoxHeaderRenderer) {
// loop over data
for each (var obj:Object in dg.dataProvider) {
// update value based on CheckBox state
obj.addToCart = CenteredCheckBoxHeaderRenderer(event.target).selected;
// notify collection item was changed
ListCollectionView(dg.dataProvider).itemUpdated(obj,"addToCart");
}
}
}

加支付宝好友偷能量挖...


评论(0)网络
阅读(137)喜欢(0)flash/flex/fcs/AIR