理解 Flex itemEditor-第 2 部分:编辑事件和复杂编辑器

理解 Flex itemEditor-第 2 部分:编辑事件和复杂编辑器

转载 http://www.adobe.com/cn/devnet/flex/articles/itemrenderers_pt1.html

 

在本系列的第 1 部分中,您已经看到如何创建一些简单的内联 itemEditor。如果您阅读过 itemRenderer 系列,您可能会发现两者十分相似。

使 itemEditor 能正常运行有两个要点。首先,使用 itemEditor 属性命名类。其次,使用 editorDataField 属性命名 itemEditor 的 value 属性。

在本文中,我将说明如何使用事件创建更复杂的 itemEditor,它们可以执行一些简单的数据验证操作并且可以防止他人编辑某些单元格。

这里请注意一点:这里的“复杂”并不不是指包含许多控制和布局的编辑器。我指的是比内联 itemEditor 复杂一些。我认为要求用户在 DataGrid 的列表或单元格中进行复杂编辑时不公平的。编辑器应当只关注一件事:单元格的内容。例如,如果您使用列表控制并展示一个购物车,那么允许用户直接编辑单元格中的值来更改购物车中的商品数量无可厚非。但允许他们更改商品本身、颜色、特殊说明等内容是不合理的。换言之,允许他们直接从购物车购买商品并不合理,因为整个站点都可以购买商品。购物车只是方便他们结帐而已。当然,他们应该可以再加一罐冰激凌或拿掉一包薯片,但不可以把薯片换成两盒全麦意大利面。

 

itemEditEnd 事件

假设您的应用程序有一个 DataGrid 用于协助管理库存。用户可以使用它更改部件号,但您不希望允许他们将部件号留空。如果使用默认 itemEditor,即 TextInput 控制,用户可以单击“Part #”列中的单元格,按 delete 键并擦除部件号。以下代码通过实施一种技术来防止这种情况。

         <mx:DataGrid x="10" y="64" editable="true" dataProvider="{inventoryDB}" 
                 itemEditEnd="verifyInput(event)">
                 <mx:columns>
                          <mx:DataGridColumn headerText="Product" dataField="product"/>
                          <mx:DataGridColumn headerText="Part #" dataField="part"/>
                          <mx:DataGridColumn headerText="Type" dataField="type"
                                   itemEditor="editors.ProductTypeEditor" editorDataField="type"/>
                          <mx:DataGridColumn headerText="Quantity" dataField="quantity"/>
                 </mx:columns>
         </mx:DataGrid>

每当编辑即将完成时,列表控制调度一个 itemEditEnd 事件。在数据提交回 dataProvider 之前,事件发生。通过处理该事件,您可以更改数据,或验证数据并根据情况停止提交。在此例中,verifyInput() 函数确保产品部件号不空。

                 private function verifyInput( event:DataGridEvent ) : void
                 {
                          // it is OK if the user cancels the edit
                          if( event.reason == DataGridEventReason.CANCELLED ) return;
                          
                          // grab the instance of the itemEditor. For this DataGrid, only the
                          // TextInput control is used as the editor, so it is safe to get the
                          // editor no matter what column has been edited.
                          var editor:TextInput = (event.currentTarget as DataGrid).itemEditorInstance as TextInput;
                          
                          // if  the edit is on the part number column, make sure it is not blank
                          if( event.dataField == "part" )
                          {
                                   if( editor.text.length == 0 ) {
                                            // call event.preventDefault() so the edit will not continue and store the
                                            // blank value
                                            event.preventDefault();
                                            // give the editor an error to display to the user
                                            editor.errorString = "You must enter a part number";
                                            return;
                                   }
                          }
                          
                          // handle other columns here
                 }

该事件是 DataGridEvent 类的一个实例,它包含一些很实用的属性。reason 属性说明调度该事件的原因。如果用户按下 ESCAPE 键或单击 DataGrid 以外区域,原因是 DataGridEventReason.CANCELLED。您可能希望像我那样忽略该事件,告诉 DataGrid 只需执行默认操作,即取消编辑并恢复先前值。

如果决定处理该事件,您需要 itemEditor 才能访问其属性。事件的 currentTarget 属性包含控制,我已经将它转换为 DataGrid。DataGrid 包含一个 itemEditorInstance 属性,我将它转换为 TextInput,对于本例,它属性 itemEditor 类型。

因为将为任何单元格调用该事件处理程序,所以您必须决定您是否想验证编辑。我检查事件的 dataField 属性,确保单元格在“part”列中。如果是,我测试编辑器的 text 属性,查看它是否包含任何字符。如果没有字符,会发生两件事。

首先,会调用 event.preventDefault()。我通过这种方式防止编辑操作,并防止 DataGrid 将新值恢复回 dataProvider 中。对于用户而言,他们在按下 TAB 或 ENTER 键后,似乎未发生任何事。preventDefault() 函数将 itemEditor 保留在原位。

其次,我将一个 errorString 放到 TextInput 控制上。这是可选的,但它却是会告诉用户出错了。毕竟,当他们按下 TAB 或 ENTER 键时,未发生任何事,此时应当提供一个理由。

itemEditBeginning 事件

有时您可能希望防止单元格被编辑。您可以将 DataGridColumn 的可编辑属性设置为 false,但这会防止每个单元格被编辑。假设您只希望将列中的某些单元格变为无法编辑?您可以使用 itemEditBeginning 事件指定某个单元格是否可编辑。

    <mx:DataGrid x="10" y="64" editable="true" dataProvider="{inventoryDB}" 
        itemEditEnd="verifyInput(event)" 
        itemEditBeginning="allowForEdit(event)">
        <mx:columns>
            <mx:DataGridColumn headerText="Product" dataField="product"/>
            <mx:DataGridColumn headerText="Part #" dataField="part"/>
            <mx:DataGridColumn headerText="Type" dataField="type"
                itemEditor="editors.ProductTypeEditor" editorDataField="type"/>
            <mx:DataGridColumn headerText="Quantity" dataField="quantity"/>
        </mx:columns>
    </mx:DataGrid>

通过处理 itemEditBeginning 事件,您可以动态决定单元格的可编辑性。在本例中,数据的每个记录中包含一个名为 permanent 的字段。我们的想法是 permanent=true 表示产品名是一个无法更改的值,因而无法编辑该行的产品单元格。它由 allowForEdit() 函数处理:

        private function allowForEdit(event:DataGridEvent) : void
        {
            // if the field to be edited is a product, prevent the user from making
            // changes if the permanent flag is true<. You can use more complex logic, 
            // of course.
            if( event.dataField == "product" ) {
                
                var item:Object = ((event.currentTarget as DataGrid).dataProvider as ArrayCollection)[event.rowIndex];
                if( item.permanent ) {
                    event.preventDefault();
                }
            }
            
            // handle other columns here
        }

再次说明,该事件是 DataGridEvent 类的一个实例,我在此处已检查事件的 dataField 属性,确保它是我正在处理的“product”字段。随后,我可以使用事件的 currentTarget 属性从 DataGrid 的 dataProvider 获得记录,并将它转换为 DataGrid。随后,我将 DataGrid 的 dataProvider 转换为 ArrayCollection 并获得 event.rowIndex 值。我也可以在这个函数中直接访问 inventoryDB ArrayCollection,因为它们在同一文件中,但这个方法更普通。

获得记录后,我就可以查询其参数属性以及它是否为 true,调用 event.preventDefault() 函数来禁用该单元格的编辑操作。在此例中,itemEditBeginning 的默认行为是显示 itemEditor;阻止默认行为将使该单元格无法编辑。

编辑限制

必须注意,处理编辑事件时要考虑到一些限制。当您使用编辑事件决定是否应继续事件时,您可能希望调用后端或服务器进程。例如,您可能有一个可验证部件号的 Web 服务。此时,您可以在 itemEditEnd 事件中尝试执行 Web 服务调用并验证用户刚才输入的内容。看上去符合逻辑,对吗?

似乎符合逻辑,但实际不可行,因为服务调用是异步的。您当然可以执行调用,但稍后才能返回结果-这要等到事件处理程序退出之后了。事实上,在您的函数退出之前不会执行调用。您的调用将排队,并在 Flex 框架退出函数时执行请求,随后由 Web 服务的结果处理程序返回结果。

所以在编辑单元格时,无法执行这类服务器端验证。如果要执行这类验证,那么当您的应用程序启动时,您应当向服务器查询要验证的数据,并在编辑单元格时使用它。

后续工作

动态允许编辑和验证更改的能力可以大幅改善应用程序的用户体验。您可以帮助用户减少错误并在编辑过程中提出反馈。您可以防止他们编辑特定数据并简化应用程序开发,因为您不必验证用户无法更改的内容。

 

你可能感兴趣的:(应用服务器,Web,Flex,单元测试,Adobe)