Flex DataGrid с ComboBox itemRenderer - PullRequest
       44

Flex DataGrid с ComboBox itemRenderer

9 голосов
/ 11 сентября 2009

Я жалею, пытаясь выяснить «правильный» способ встроить ComboBox в DataGrid Flex (3.4). По праву (например, согласно этой странице http://blog.flexmonkeypatches.com/2008/02/18/simple-datagrid-combobox-as-item-editor-example/) это должно быть легко, но я не могу на всю жизнь сделать эту работу.

Отличие, которое я имею к приведенному выше примеру, состоит в том, что мое отображаемое значение (то, что видит пользователь) отличается от значения идентификатора, которое я хочу выбрать и сохранить в моем поставщике данных.

Итак, что у меня есть:

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

Где transactionTypesData имеет оба поля 'data' и 'label' (в соответствии с тем, что ComboBox - почему он не предоставляет и labelField, и idField, я никогда не узнаю).

В любом случае, вышеприведенный код MXML не работает двумя способами:

  1. Поле со списком не отображается ни с одним выбранным элементом.
  2. После выбора элемента он не сохраняет этот выбранный элемент в хранилище данных.

Итак, у кого-нибудь работает похожая ситуация?

Ответы [ 3 ]

5 голосов
/ 17 сентября 2009

Хотя ответ Джеффа является частичным ответом для одного подхода к этому (см. http://flex.gunua.com/?p=119 для полного примера того, как это используется для хорошего эффекта), он не такой общий, как я хотел.

К счастью, я наконец-то нашел отличную помощь по Эксперты Exchange (ответы от hobbit72) описывает, как создать пользовательский компонент, который работает в сетке как ItemRenderer. Я расширил этот код, чтобы также поддерживать использование поля со списком в качестве ItemEditor. Полный компонент выглядит следующим образом:

<?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> 

Использование этого компонента просто. Как 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>

Использование этого компонента просто. И как 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>

Обратите внимание, что при использовании его в качестве ItemEditor, необходимо использовать пользовательскую функцию labelFunction (которая ищет имя из PersonID в моем случае), в противном случае ключ в сетке вы видите только тогда, когда поле не редактируется ( не проблема, если ваши ключи / значения одинаковы).

Обратите внимание, что в моем случае я хотел, чтобы событие фокуса элемента распространялось вверх, чтобы обеспечить немедленную обратную связь с пользователем (моя DataGrid имеет itemFocusOut="handleChange()"), поэтому событие change создает событие ITEM_FOCUS_OUT.

Обратите внимание, что, вероятно, существуют более простые способы использовать ComboBox в качестве ItemEditor, если вы не возражаете против ComboBox, который отображается только тогда, когда пользователь нажимает на ячейку для редактирования. Подход, который я хотел, представлял собой общий способ отображения поля со списком в DataGrid для всех строк, и он был редактируемым и с достойным распространением событий.

2 голосов
/ 14 сентября 2009

Самый простой способ добавить itemRenderers в DataGrids - создать пользовательский компонент MXML. В вашем случае создайте Canvas, HBox или VBox в качестве пользовательского компонента и добавьте комбинированный список как дочерний. Установите dataProvider в самой dataGrid и назначьте itemRenderer столбцу, а затем переопределите функцию set data itemRenderer для доступа все данные от данного поставщика данных для этого экземпляра, как показано ниже:

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

Этот метод будет вызываться для каждого экземпляра itemRenderer

1 голос
/ 02 февраля 2014

В моем случае я использовал сетку данных искры, где в одном из столбцов есть ItemRenderer, который использует DropDownListBox. Моя проблема заключалась в том, что при изменении списка элементов DropDownLists не обновляются с новым dataProvider. Чтобы решить эту проблему, мне пришлось передать dataProvider для DropDownListBox как часть данных (ItemRenderer), а затем переопределить установщик данных, чтобы просто назначить dataProvider DropDownlListBox. Возможно, немного накладных расходов, но если у кого-то есть лучшее решение, пожалуйста, дайте мне знать:

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

...