Pregunta

Me voy a escatimar tratando de averiguar el " correcto " forma de incrustar un ComboBox dentro de un DataGrid Flex (3.4). Por derechos (por ejemplo, según 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 por mi vida hacer que esto funcione.

La diferencia que tengo con el ejemplo vinculado anteriormente es que mi valor de visualización (lo que ve el usuario) 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 un campo de etiqueta e idField I 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 elemento, no almacena ese elemento seleccionado en el almacén de datos.

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

¿Fue útil?

Solución

Si bien la respuesta de Jeff es una respuesta parcial para un enfoque para esto (consulte http: // flex. gunua.com/?p=119 para un ejemplo completo de cómo se usa con buenos resultados), no es tan general como quería.

Afortunadamente, finalmente encontré una gran ayuda en Intercambio de expertos (las respuestas de hobbit72) describe cómo crear un componente personalizado que funciona en una cuadrícula como ItemRenderer. He extendido ese código para que también admita el uso del cuadro combinado como un editor de elementos. 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> 

El uso de 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>

El uso de este componente es sencillo. Y como 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 al usarlo como ItemEditor, se debe usar un LabelFunction personalizado (que busca 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 sus claves / valores son los mismos).

Tenga en cuenta que, en mi caso, quería que el evento de enfoque del elemento se propagara para proporcionar una respuesta inmediata al usuario (mi Cuadrícula de datos tiene itemFocusOut = " handleChange () " ), por lo tanto change evento creando un evento ITEM_FOCUS_OUT.

Tenga en cuenta que probablemente haya formas más simples de tener un ComboBox como ItemEditor cuando no le importa que ComboBox solo se muestre cuando el usuario haga 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 propagación de eventos decente.

Otros consejos

La forma más fácil de agregar itemRenderers a DataGrids es hacer 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 DataProvider en el DataGrid y asigne el itemRenderer a la columna, y luego anule la función set data 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

En mi caso, usé una red de datos de chispa donde una de las columnas tiene un ItemRenderer que utiliza un DropDownListBox. Mi problema fue que cuando mi lista de elementos cambia, las DropDownLists no se actualizan con el nuevo dataProvider. Para resolver esto, tuve que pasar el DataProvider para el DropDownListBox como parte de los datos (del ItemRenderer), y luego al reemplazar el setter de los datos para simplemente asignar el DataProvider del DropDownlListBox. Probablemente un poco de sobrecarga, pero si alguien tiene una mejor solución, hágamelo saber:

<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"/>

    

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top