Просмотр полной версии : Проблема с ComboBox в DataGrid
Skabeika
03.08.2009, 19:36
Как можно реализовать редактирование поля в DataGrid с помощью ComboBox? Причем данные для этого поля должны браться из другой таблицы.
Вот код msxml:
<mx:DataGrid id = "booksAdmin"
width = "100%"
height = "100%"
editable = "{editableBookCh.selected}"
dataProvider = "{bookAdminArray}"
creationComplete = "booksAdmin.addEventListener(DataGridEvent.ITEM_EDIT_END, editBooksAdminCellEnd)">
...
<mx:DataGridColumn id = "izdatBooksAdminCol"
labelFunction="izdat_labelFunc"
dataField = "izdat"
editorDataField="id"
headerText = "Издательство">
<mx:itemEditor>
<mx:Component>
<mx:ComboBox editable="false"
dataProvider="{outerDocument.bookAdminIzdatArray}"
labelField="name"
/>
</mx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
...
В приведенном выше примере в массиве bookAdminIzdatArray хранятся данные из родительской таблицы, этот массив заполняется динамически с помощью HttpService. Во время редактирования в ComboBox появляются записи родительской таблицы, но я никак не могу сделать так, чтобы в DataGrid отображался не первичный ключ родительской таблицы, а элементы массива bookAdminIzdatArray. Кроме того, после редактирования пропадает даже этот первичный ключ и не отображается ничего.
Ну так покажите, что вы в editBooksAdminCellEnd делаете - это ж как бы самое главное :)
Skabeika
03.08.2009, 19:49
editBooksAdminCellEnd работает с текстовыми полями нормально (я его не сам придумал а списал с какого-то примера, не помню уже какого)
private function editBooksAdminCellEnd(e:DataGridEvent):void {
var rowIndex:int = e.rowIndex;
var columnIndex:Number = e.columnIndex;
var vo:* = bookAdminArray[rowIndex];
var col:DataGridColumn = booksAdmin.columns[columnIndex];
var newvalue:String = booksAdmin.itemEditorInstance[col.editorDataField];
if (newvalue == "") {
booksAdmin.itemEditorInstance[col.editorDataField] = vo.name;
return;
}
if (newvalue == vo.name) {
return;
}
CursorManager.setBusyCursor();
var parameters:* = { "method": "Update", "id": vo.id, "new": newvalue }
gateway = new HTTPService();
gateway.url = BOOK_URL;
gateway.method = "POST";
gateway.useProxy = false;
gateway.request = parameters;
gateway.addEventListener(ResultEvent.RESULT, resultUpdateBooksHandler);
gateway.addEventListener(FaultEvent.FAULT, faultUpdateBooksHandler);
gateway.send();
}
Кстати сейчас только я подумал что в параметрах сервису нужно передавать еще и колонку, но это поправимо. А вот как быть с ComboBox, понятия не имею
Почти все похожие примеры в google используют собственные компоненты, не существует ли метода попроще? И можно ли такое сделать с помощью компонентов?
Пример почти гарантировано отсюда ;) 3-й или второй...
http://livedocs.adobe.com/flex/3/html/help.html?content=celleditor_8.html
Только разница в том, что у вас редактирование происходит асинхронно - показывайте, что в resultUpdateBooksHandler() находится.
var parameters:* = { "method": "Update", "id": vo.id, "new": newvalue };
parameters - должны быть типа Object, а не *.
vo технически может быть типа *, но лучше не допускать такию ситуацию.
Skabeika
03.08.2009, 19:58
Пример почти гарантировано отсюда ;) 3-й или второй...
http://livedocs.adobe.com/flex/3/html/help.html?content=celleditor_8.html
Только разница в том, что у вас редактирование происходит асинхронно - показывайте, что в resultUpdateBooksHandler() находится.
Собственно вот это:)
private function resultUpdateBooksHandler(e:ResultEvent):void {
CursorManager.removeBusyCursor();
}
Ну так а вам в ней как раз и нужно обновить данные... а вы в ней просто ничего не делаете... :)
Skabeika
03.08.2009, 20:07
А все остальное правильно? Просто я ни разу с Flex не работал еще. Что-то мне подсказывает что нужно обработать событие change в ComboBox и как-то установить свойство selected (и то и другое у ComboBox). Но я с ними сколько не игрался так и не добился успеха
Добавлено через 10 минут
Не подскажите как можно обновить данные?
Мммм... itemEditor сам уже подписан на "change", так что вы неявно на него подписались. Просто вы никогда itemEditorInstance не кастуете к ComboBox, поэтому вам это может быть не заметно.
т.е. если ваша функция editBooksAdminCellEnd вообще вызывается, то вы подписались на "change" и эта часть сработала нормально. Другое дело, что создавать каждый раз по экземпляру HTTPService - это как-то многовато, лучше было бы создать один экземпляр и использовать его с любым итем-эдитором.
Ну, и как бы вы самое главное не сделали - когда приходит результат от сервиса - вам надо эти изменения отразить в дата-провайдере, а вы этого никогда не делаете.
<?xml version="1.0" encoding="utf-8"?>
<!-- view.ValueTable -->
<mx:Panel
xmlns:mx="http://www.adobe.com/2006/mxml"
title="Skill XML"
horizontalAlign="center"
width="400" height="300"
>
<mx:Metadata>
[Event(name="valueUpdate", type="flash.events.Event")]
</mx:Metadata>
<mx:Script>
<![CDATA[
import flash.events.Event;
import mx.controls.listClasses.IDropInListItemRenderer;
import mx.controls.TextInput;
import mx.events.DataGridEvent;
import mx.events.DataGridEventReason;
import mx.managers.PopUpManager;
private function counter(input:Object, input2:Object):String
{
var i:int;
var ri:int;
super.data.(contains(input) ? (ri = i) : i++);
return (ri + 1).toString();
}
private function editValueBegin(event:DataGridEvent):void
{
event.preventDefault();
dg.createItemEditor(event.columnIndex, event.rowIndex);
(dg.itemEditorInstance as IDropInListItemRenderer).listData =
(dg.editedItemRenderer as IDropInListItemRenderer).listData;
dg.itemEditorInstance.data = dg.editedItemRenderer.data;
(dg.itemEditorInstance as TextInput).setFocus();
}
private function editValueEnd(event:DataGridEvent):void
{
if (event.reason == DataGridEventReason.CANCELLED) return;
var newData:String =
(dg.itemEditorInstance as TextInput).text;
dg.editedItemRenderer.data = dg.itemEditorInstance.data;
if (newData == "")
{
event.preventDefault();
(dg.itemEditorInstance as TextInput).errorString =
"This field is mandatory!";
return;
}
else
{
(dg.itemEditorInstance as TextInput).text = newData;
dispatchEvent(new Event("valueUpdate"));
}
}
]]>
</mx:Script>
<mx:DataGrid
id="dg"
dataProvider="{data}"
width="100%"
height="100%"
editable="true"
itemEditBegin="editValueBegin(event)"
itemEditEnd="editValueEnd(event)"
>
<mx:columns>
<mx:DataGridColumn
headerText="Level"
labelFunction="{counter}"
editable="false"
width="40"
resizable="false"
/>
<mx:DataGridColumn
headerText="Value"
editable="true"
dataField="@val"
>
<mx:itemEditor>
<mx:Component>
<mx:TextInput restrict="0-9"/>
</mx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
<mx:Button label="Close" click="PopUpManager.removePopUp(this)"/>
</mx:Panel>
Вот пример где-то был. Только тут нет асинхронного изменения данных, оно у меня происходит в этой строчке:
dg.editedItemRenderer.data = dg.itemEditorInstance.data;
А вам прийдется записать, какая позиция редактировалась, когда отправился запрос, и когда ответ на запрос будет получен, заменить эту позицию новыми данными.
Skabeika
03.08.2009, 20:31
Если создать один экземпляр, то скорее всего придется обнулять handler-ы каждый раз (кода ненамного меньше). У меня вылезало какое-то переполнение буфера из-за этого.
Дело в том, что у меня даже не отображается то что надо, без редактирования. Вроде бы задал свойства dataField, editorDataField. Тогда почему не отображается соответствующая запись из списка, а значение первичного ключа. Почем не работает двунаправленное связывание???
Двунаправленое связывание - фича новая, и не везде работает, как раз например в аргументах сервиса - не работает.
Нет, как раз не прийдется обнулять хендлеры. Их вполне можно использовать многократно.
вы видите первичное значение потому, что вы никогда не применяете изменения, вы получаете ответ от сервиса - но в коде никак на это не реагируете, т.е. просто ничего не меняете - вам нужно в resultUpdateBooksHandler записать новое значение туда, где вы его до запроса хотели поменять.
Skabeika
03.08.2009, 20:49
За пример спасибо, сейчас буду изучать его.
Дело в том что я вижу первичные ключи до редактирования. То есть мне надо еще что-то дописывать в resultBooksAdminHandler?
private function resultBooksAdminHandler(e:ResultEvent):void {
booksAdmin.enabled = true;
bookAdminArray.removeAll();
var xmlData:XML = e.result as XML;
for each (var row:XML in xmlData.row) {
var temp:* =
{
"id": row.id,
"name": row.name,
"tom": row.tom,
"author": row.author,
"coauthor": row.coauthor,
"year": row.year,
"izdat": row.izdat,
"mesto": row.mesto,
"cat": row.cat
};
bookAdminArray.addItem(temp);
}
}
То есть автоматически подставлятся не будет текстовое значение из вспомогательного списочного массива вместо значения первичного ключа, который находится в основном массиве?
в приведенном выше методе происходит заполнение источника данных для DataGrid
Нет, автоматически не будет подставлятся, вам это нужно описать в labelFunction например. А еще лучше - непосредственно модифицировать датапровайдер грида, т.как грид повторно использует итем-рендереры, и если у вас появится скроллинг в гриде - комбобоксы начнут показывать неизвесно что, т.как они не будут создаваться по-новой, а просто последний удаленный будет использоваться для отображения нового.
Работает на vBulletin ® версия 3.7.3. Copyright ©2000-2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Copyright © 1999-2008 Flasher.ru. All rights reserved.