2011-01-15 3 views
9

Я использую GWT 2.1's CellBrowser с обычным TreeViewModel. TreeViewModel в свою очередь использует AsyncDataProvider для получения данных динамически. Все это прекрасно работает - когда пользователь нажимает на узел, мой AsyncDataProvider извлекает результаты через RPC, и CellBrowser покорно отображает их.GWT: Как программно перезагрузить 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); 

ответ

10

Похоже, что у многих это есть same issue. Вот как я обработал обновление данных от AsyncDataProvider.

Сначала создайте интерфейс, который добавит возможность обновления поставщика данных путем переноса защищенного метода onRangeChanged AsyncDataProvider. Например ...

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 необходимости обновляться, то можете позвонить в него через операцию или однако ваш логический контроллер настроен.

/** 
* 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 
+0

опечатка на «HashRefresh», но в остальном +1! :) – HaveAGuess

+0

Почему все голосуют за этот ответ? Тот, который ниже, намного лучше - однострочное изменение, которое делает все это. –

+0

updateRowData (start, response.getEntities()) обновляет все дисплеи для провайдера, вместо этого вы можете использовать updateRowData (display, start, response.getEntities()). Но display.setVisibleRangeAndClearData (display.getVisibleRange(), true) все еще лучше :) – Quiz

7

Обнаруженные теперь следующий код в основном то же самое, но с HasData интерфейса вместо использования AsyncDataProvider.

HasData<T> display; 
... 
display.setVisibleRangeAndClearData(display.getVisibleRange(), true); 
+0

Работает для меня! Благодаря! –

2

Я не понимаю, почему ответ affablebloke отмечен как «правильный» и выдержанный так много !?

Caffeine Coma спросил об обновлении Cell Browser и не ячейки таблицы, что это совершенно разные вещи!

Для меня следующий трюк сработал: определяю DataProvider сек за пределами TreeViewModel и передать их в качестве аргумента конструктора. В моем случае они предоставляют пустые структуры данных в начале.

Теперь у вас есть ссылка на DataProvider с «снаружи», чтобы обновить браузер ячеек.

Пример:

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(...); 
+0

Благодарим вас за предоставленный ответ. Он работает отлично. Мне было интересно, как обновить CellBrowser довольно долго. –

0

У меня была та же проблема, и это работает для меня:

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 контролировать таблицу разбиения на страницы.

Надеюсь, это поможет!

Смежные вопросы