datagrid flex3 itemrenderer

Flex DataGrid con ComboBox itemRenderer



flex3 (3)

Me ahorraré tratando de descubrir la forma "correcta" de insertar un ComboBox dentro de un DataGrid Flex (3.4). Por derechos (por ejemplo, de acuerdo con esta página http://blog.flexmonkeypatches.com/2008/02/18/simple-datagrid-combobox-as-item-editor-example/ ) debería ser fácil, pero no puedo la vida de mí hace que esto funcione

La diferencia que tengo con el ejemplo vinculado anteriormente es que mi valor de visualización (lo que el usuario ve) es diferente al valor de identificación que deseo seleccionar y almacenar en mi proveedor de datos.

Entonces lo que tengo es:

<mx:DataGridColumn headerText="Type" width="200" dataField="TransactionTypeID" editorDataField="value" textAlign="center" editable="true" rendererIsEditor="true"> <mx:itemRenderer> <mx:Component> <mx:ComboBox dataProvider="{parentDocument.transactionTypesData}"/> </mx:Component> </mx:itemRenderer> </mx:DataGridColumn>

Donde transactionTypesData tiene los campos ''datos'' y ''etiqueta'' (según lo que ComboBox - ¿por qué en la tierra no proporciona una etiqueta Campo e IdField? Nunca lo sabré).

De todos modos, el código MXML anterior no funciona de dos maneras:

  1. El cuadro combinado no aparece con ningún elemento seleccionado.
  2. Después de seleccionar un artículo, no almacena ese elemento seleccionado en el almacén de datos.

Entonces, ¿alguien tiene una situación similar funcionando?


La forma más sencilla de agregar itemRenderers a DataGrids es crear un componente MXML personalizado. En su caso, cree un lienzo, HBox o VBox como el componente personalizado y agregue el cuadro combinado como un niño. Establezca el proveedor de datos en el dataGrid mismo y asigne el itemRenderer a la columna, y luego anule la función de datos configurados del itemRenderer para acceder todos los datos del proveedor de datos dado para esa instancia como se ve a continuación:

<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script> <![CDATA[ override public function set data(value:Object):void{ trace(value.data); trace(value.name); } ]]> </mx:Script> <mx:ComboBox width="100%" height="100%" id="myComboBox"/> </mx:HBox>

Se llamará a este método para cada instancia del itemRenderer


Mientras que la respuesta de Jeff es una respuesta parcial para un enfoque para esto (ver http://flex.gunua.com/?p=119 para un ejemplo completo de que esto se usa con buenos resultados), no es tan general como yo quería .

Afortunadamente, finalmente encontré una gran ayuda en Experts Exchange (las respuestas de hobbit72) describe cómo crear un componente personalizado que funcione en una grilla como ItemRenderer. He extendido ese código para que también sea compatible con el uso del cuadro combinado como ItemEditor también. El componente completo es el siguiente:

<?xml version="1.0" encoding="utf-8"?> <mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml" dataChange="setSelected()" change="onSelectionChange(event)" focusEnabled="true"> <mx:Script> <![CDATA[ import mx.events.DataGridEvent; import mx.events.ListEvent; import mx.controls.dataGridClasses.DataGridListData; private var _ownerData:Object; private var _lookupField:String = "value"; // When using this component as an itemEditor rather than an itemRenderer // then set '' editorDataField="selectedItemKey"'' on the column to // ensure that changes to the ComboBox are propogated. [Bindable] public var selectedItemKey:Object; public function set lookupField (value:String) : void { if(value) { _lookupField = value; setSelected(); } } override public function set data (value:Object) : void { if(value) { _ownerData = value; setSelected(); } } override public function get data() : Object { return _ownerData; } private function setSelected() : void { if (dataProvider && _ownerData) { var col:DataGridListData = DataGridListData(listData); for each (var dp:Object in dataProvider) { if (dp[_lookupField] == _ownerData[col.dataField]) { selectedItem = dp; selectedItemKey = _ownerData[col.dataField]; return; } } } selectedItem = null; } private function onSelectionChange (e:ListEvent) : void { if (selectedItem && _ownerData) { var col:DataGridListData = DataGridListData(listData); _ownerData[col.dataField] = selectedItem[_lookupField]; selectedItemKey = selectedItem[_lookupField]; } } ]]> </mx:Script> </mx:ComboBox>

Usar este componente es sencillo. Como un ItemRenderer:

<mx:DataGridColumn headerText="Child" dataField="PersonID" editable="false" textAlign="center"> <mx:itemRenderer> <mx:Component> <fx:GridComboBox dataProvider="{parentDocument.childrenData}" labelField="Name" lookupField="PersonID" change="dispatchEvent(new mx.events.DataGridEvent(mx.events.DataGridEvent.ITEM_FOCUS_OUT, true, true))"/> </mx:Component> </mx:itemRenderer> </mx:DataGridColumn>

Usar este componente es sencillo. Y como un ItemEditor:

<mx:DataGridColumn labelFunction="lookupChildName" headerText="Child" dataField="PersonID" editable="true" editorDataField="selectedItemKey"> <mx:itemEditor> <mx:Component> <fx:GridComboBox dataProvider="{parentDocument.childrenData}" labelField="Name" lookupField="PersonID" change="dispatchEvent(new mx.events.DataGridEvent(mx.events.DataGridEvent.ITEM_FOCUS_OUT, true, true))"/> </mx:Component> </mx:itemEditor> </mx:DataGridColumn>

Tenga en cuenta que cuando lo use como ItemEditor, se debe usar una función de etiqueta personalizada (que busque el nombre del PersonID en mi caso), de lo contrario solo verá la clave en la cuadrícula cuando el campo no se esté editando (no es un problema) si tus claves / valores son los mismos).

Tenga en cuenta que en mi caso, quería que el evento de enfoque del artículo se propagara para proporcionar comentarios inmediatos al usuario (mi DataGrid tiene itemFocusOut="handleChange()" ), de ahí el evento de change que crea un evento ITEM_FOCUS_OUT.

Tenga en cuenta que probablemente haya formas más simples de tener un ComboBox como ItemEditor cuando no le molesta que el ComboBox solo se muestre cuando el usuario hace clic en la celda para editar. El enfoque que quería era una forma genérica de mostrar un cuadro combinado en un DataGrid para todas las filas, y ser editable y con una propogación de eventos decente.


En mi caso, utilicé una chispa de cuadrícula de datos donde una de las columnas tiene un ItemRenderer que utiliza un DropDownListBox. Mi problema fue que cuando mi lista de elementos cambia, DropDownLists no se actualiza con el nuevo dataProvider. Para resolver esto, tuve que pasar el dataProvider para DropDownListBox como parte de los datos (del ItemRenderer), y luego anulando el setter de los datos para simplemente asignar el dataProvider de DropDownlListBox. Probablemente un poco de sobrecarga, pero si alguien tiene una mejor solución, por favor avíseme:

<s:GridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx"> <fx:Script> <![CDATA[ override public function set data(v : Object) : void { super.data = v; if (v == null) return; dropDown.dataProvider = data.dataProvider; } ]]> </fx:Script> <s:DropDownList id="dropDown" width="100%" height="100%" dataProvider="{data.dataProvider}" labelField="name"/>