Гибкая сетка данных с помощью ComboBox ItemRenderer
-
05-07-2019 - |
Вопрос
Я собираюсь воздержаться от попыток выяснить "правильный" способ встраивания ComboBox в сетку данных Flex (3.4).По Правам (например,согласно этой странице http://blog.flexmonkeypatches.com/2008/02/18/simple-datagrid-combobox-as-item-editor-example/) это должно быть легко, но я ни за что на свете не смогу заставить это работать.
Разница, которую я имею в примере, приведенном выше, заключается в том, что мое отображаемое значение (то, что видит пользователь) отличается от значения id, которое я хочу выбрать и сохранить в моем поставщике данных.
Итак, что у меня есть, это:
<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
содержит как поля "данные", так и "метка" (в соответствии с ComboBox
- с какой стати он не предоставляет одновременно LabelField и idField, я никогда не узнаю).
В любом случае, приведенный выше код MXML не работает двумя способами:
- Поле со списком не отображается ни с одним выбранным элементом.
- После выбора элемента он не сохраняет обратно этот выбранный элемент в хранилище данных.
Итак, работает ли у кого-нибудь похожая ситуация?
Решение
Хотя ответ Джеффа является частичным ответом для одного подхода к этому (см. http://flex.gunua.com/?p=119 для полного примера того, как это используется с хорошим эффектом), это не так обобщенно, как я хотел.
К счастью, я наконец-то нашел отличную помощь по Обмен экспертами (the answers by hobbit72) описывает, как создать пользовательский компонент, который работает в сетке в качестве ItemRenderer.Я расширил этот код, чтобы он также поддерживал использование поля со списком в качестве редактора элементов.Полный компонент выглядит следующим образом:
<?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>
Использование этого компонента очень просто.Как поставщик товаров:
<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>
Использование этого компонента очень просто.И как редактор статей:
<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), в противном случае вы видите ключ в таблице только тогда, когда поле не редактируется (не проблема, если ваши ключи / значения совпадают).
Обратите внимание, что в моем случае я хотел, чтобы событие item focus out распространилось, чтобы предоставить немедленную обратную связь пользователю (моя DataGrid имеет itemFocusOut="handleChange()"
), следовательно, change
событие, создающее событие ITEM_FOCUS_OUT.
Обратите внимание, что, вероятно, есть более простые способы использовать поле со списком в качестве редактора элементов, если вы не возражаете, чтобы поле со списком отображалось только тогда, когда пользователь нажимает на ячейку для редактирования.Подход, который я хотел, был общим способом отображения поля со списком в DataGrid для всех строк, доступным для редактирования и с достойным распространением событий.
Другие советы
Самый простой способ добавить itemRenderers в DataGrids - это создать пользовательский компонент MXML.В вашем случае создайте canvas, HBox или VBox в качестве пользовательского компонента и добавьте combobox в качестве дочернего элемента.Установите 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
В моем случае я использовал spark datagrid, где в одном из столбцов есть ItemRenderer, который использует выпадающий список.Моя проблема заключалась в том, что при изменении моего списка элементов выпадающие списки не обновляются с помощью нового 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"/>