GWT: Как программно перезагрузить CellBrowser?
Я использую GWT 2.1 CellBrowser с пользовательским TreeViewModel
, TreeViewModel в свою очередь использует AsyncDataProvider
получать данные динамически. Все это прекрасно работает - когда пользователь нажимает на узел, мой AsyncDataProvider извлекает результаты через RPC, и CellBrowser покорно отображает их.
Я чувствую себя глупо из-за того, что не могу понять это, но как я могу программно сказать CellBrowser перезагрузить (и отобразить) данные? Я предполагаю, что мне нужно каким-то образом получить дескриптор AsyncDataProvider для моего корневого узла, а затем вызвать updateRowData() & updateRowCount() для него, но я не вижу очевидного способа сделать запрос к браузеру (или его модели) для корневого DataProvider.
Я полагаю, я мог бы добавить код в свой конструктор AsyncDataProvider, который ищет нулевой аргумент, и таким образом распознает "эй, я корень" и где-то храню ссылку, но это кажется хакерским. Конечно, есть лучший способ сделать это.
Извиняюсь за сброс большого количества кода здесь, но я не знаю, как свести это к чему-то более простому и все же предоставить достаточно контекста.
Мой AsyncDataProvider:
private static class CategoryDataProvider extends AsyncDataProvider<Category>
{
private Category selectedCategory;
private CategoryDataProvider(Category selectedCategory)
{
this.selectedCategory = selectedCategory;
}
@Override
protected void onRangeChanged(HasData<Category> display)
{
new AsyncCall<List<Category>>()
{
@Override
protected void callService(AsyncCallback<List<Category>> cb)
{
// default to root
String categoryId = "-1";
if (selectedCategory != null)
{
categoryId = selectedCategory.getCategoryId();
}
// when a category is clicked, fetch its child categories
service.getCategoriesForParent(categoryId, cb);
}
@Override
public void onSuccess(List<Category> result)
{
// update the display
updateRowCount(result.size(), true);
updateRowData(0, result);
}
}.go();
}
}
Моя модель:
private static class CategoryTreeModel implements TreeViewModel
{
private SingleSelectionModel<Category> selectionModel;
public CategoryTreeModel(SingleSelectionModel<Category> selectionModel)
{
this.selectionModel = selectionModel;
}
/**
* @return the NodeInfo that provides the children of the specified category
*/
public <T> NodeInfo<?> getNodeInfo(T value)
{
CategoryDataProvider dataProvider = new CategoryDataProvider((Category) value);
// Return a node info that pairs the data with a cell.
return new TreeViewModel.DefaultNodeInfo<Category>(dataProvider, new CategoryCell(), selectionModel, null);
}
/**
* @return true if the specified category represents a leaf node
*/
public boolean isLeaf(Object value)
{
return value != null && ((Category) value).isLeafCategory();
}
}
И, наконец, вот как я их использую:
CategoryTreeModel model = new CategoryTreeModel(selectionModel);
CellBrowser cellBrowser = new CellBrowser(model, null);
4 ответа
Похоже, что многие люди имеют эту же проблему. Вот как я справился с обновлением данных из AsyncDataProvider.
Сначала создайте интерфейс, который добавляет возможность обновления поставщика данных, обернув защищенный метод AsRyncDataProvider onRangeChanged. Например...
HasRefresh.java
public interface HasRefresh<HasData<T>>{
/**
* Called when a display wants to refresh
*
* @param display the display to refresh
*/
void refresh(HasData<T> display);
}
Затем CellTable, нуждающийся в обновлении, может затем обратиться к нему через Activity или, если настроена логика вашего контроллера.
/**
* A custom {@link AsyncDataProvider}.
*/
public class MyAsyncDataProvider extends
AsyncDataProvider<Entity> implements HasRefresh<Entity> {
public void refresh(Entity display){
onRangeChanged(display);
}
/**
* {@link #onRangeChanged(HasData)} is called when the table requests a
* new range of data. You can push data back to the displays using
* {@link #updateRowData(int, List)}.
*/
@Override
protected void onRangeChanged(
HasData<Entity> display) {
currentRange = display.getVisibleRange();
final int start = currentRange.getStart();
dataServiceQuery = context.getEntities();
dataServiceQuery
.execute(new DataServiceQueryHandler<Entity>() {
@Override
public void onQueryResponse(
DataServiceQueryResponse<Entity> response) {
updateRowCount(response.getCount(), true);
updateRowData(start, response.getEntities());
}
});
}// end onRangeChanged()
}// end MyAsyncDataProvider class
Теперь выяснилось, что следующий код в основном такой же, но из интерфейса HasData вместо использования AsyncDataProvider.
HasData<T> display;
...
display.setVisibleRangeAndClearData(display.getVisibleRange(), true);
Я не понимаю, почему ответ на affablebloke помечен как "правильный" и так много проголосовал!?
Кофеин Кома спросил об обновлении Cell Browser, а не Cell Cell, это совершенно разные вещи!
Для меня сработал следующий трюк: я определяю DataProvider
за пределами TreeViewModel
и передать их в качестве аргумента в конструктор. В моем случае они предоставляют пустые структуры данных в начале.
Теперь у вас есть ссылка на DataProvider
s извне, чтобы обновить браузер сотовой связи.
Пример:
private class MyTreeViewModel implements TreeViewModel {
AbstractDataProvider<MyDataStructure> myDataProvider;
public MyTreeViewModel(AbstractDataProvider<MyDataStructure> myDataProvider)
{
this.myDataProvider = myDataProvider;
}
@Override
public <T> NodeInfo<?> getNodeInfo(T value) {
if(value == null)
{
// Level 0
return new DefaultNodeInfo<MyDataStructure>(myDataProvider, new MyCellImpl());
}
}
}
AbstractDataProvider<MyDataStructure> myDataProvider = new ListDataProvider<MyDataStructure>(new ArrayList<MyDataStructure>()); // or AsyncDataProvider
MyTreeViewModel myModel = new MyTreeViewModel(myDataProvider);
CellBrowser<MyDataStructure> cellBrowser = new CellBrowser.Builder<MyDataStructure>(myModel, null).build();
/*
here you can do some stuff, for example, bind the CellBrowser to a template with UiBinder
*/
/*
if you use a ListDataProvider, do
*/
myDataProvider.setList(myDataStructureFromSomewhere);
myDataProvider.refresh();
/*
if you use an AsyncDataProvider, do
*/
myDataProvider.updateRowData(..., myDataStructureFromSomewhere);
myDataProvider.updateRowCount(...);
У меня была такая же проблема, и это сработало для меня:
List<TreeGridRecord> dataToTable = ....
int firstPosition = this.pager.getDisplay().getVisibleRange().getStart();
this.dataProvider.updateRowData(firstPosition, dataToTable);
int rowCount = this.pager.getPageStart() + dataToTable.size();
this.dataProvider.updateRowCount(rowCount, exactCount);
Где "пейджер" - это SimplePager для управления нумерацией таблиц.
Надеюсь это поможет!