如何在GWT中为CellTree正确实现MVP?

时间:2014-07-24 14:25:59

标签: java gwt

想象一下,我有一个班级CellTreeWidget,其中包含CellTree

我想写一个与

交互的演示者
  1. CellTreeWidget实例和
  2. 获取数据的远程服务。
  3. CellTreeWidget中显示的数据是项目列表。每个项目都有一个父项目,属于一个容器。

    public class Container
    {
        public List<Item> getItemList();
        public void setItemList(List<Item> aItemList);
    }
    
    public class Item
    {
        public int getItemId();
        public int getParentItemId();
    }
    

    以下过程涉及演示者:

    1. 用户选择一个容器(请参阅下面的Presenter.startEdit)。
    2. 用户保存对容器所做的更改(请参阅下面的Presenter.save)。
    3. 当用户选择容器时,必须更新CellTreeWidget以显示新选择的容器的项目。

      当用户保存对容器所做的更改时,演示者必须

      1. 向远程服务发送保存请求
      2. 如果请求已正确处理,请确保树中的项目已更新。
      3. 步骤2是必要的,因为用户可以在客户端上创建新项目。当它们保存在服务器上时,它们的数据(主键)会发生变化。

        为了实现这一点,我被告知使用以下方法:

        public class Presenter
        {
            private RemoteService service;
            private View view;
            private ListDataProvider<Item> dataProvider;
            private Container data;
        
            public Presenter()
            {
                dataProvider = new ListDataProvider<Item>(new ItemProvidesKey());
            }
            public void setService(final RemoteService aService) 
            {
                service = aService;
            }
            public void setView(final View aView) 
            {
                view = aView;
        
                final HasData<Item> dataToDisplay = view.getDisplay();
        
                if (dataToDisplay != null)
                {
                  dataProvider.addDataDisplay(dataToDisplay);
                }
            }
            public void save() {
                List<Item> allPages = new ArrayList<Item>();
                allPages.addAll(dataProvider.getList());
                data.setItemList(allPages);
        
                service.save(data, new AsyncCallback<ContainerSaveResult>() {
                    @Override
                    public void onSuccess(ContainerSaveResult result) {
                        afterSave(result);
                    }
        
                    @Override
                    public void onFailure(Throwable caught) {
                        Window.alert("Save error: " + caught.getMessage());
                    }
                });
            }
        
            protected void afterSave(ContainerSaveResult result) 
            {
                for (final Page curItem : dataProvider.getList()) 
                {
                    final Integer oldId = curPage.getItemId();
                    final Integer newId = result.getNewItemIdsByOldItemIds().get(oldId);
        
                    if (newId != null) 
                    {
                        curPage.setItemId(newId);
                    }
                }
        
                dataProvider.flush();
            }
            public void startEdit(Container aContainer) 
            {
                data = aContainer;
                if (data != null) 
                {
                    view.getDisplay().setRowCount(data.getItemList().size(), true);
                    dataProvider.setList(data.getItemList());
                }
            }
        }
        

        CellTreeWidget实现了接口View,其定义如下:

        public interface View extends IsWidget, HasSelectionChangedHandlers {
          HasData<Item> getDisplay();
        }
        

        这种方法的问题在于,我认为没有明显的方法可以在HasData<Item> getDisplay()类中提供方法CellTreeWidget的实现。

        因此我的问题是:如果你

        1. 有一个树状结构,
        2. 显示在CellTree
        3. 可以在客户端(用户添加新项目)和
        4. 上进行修改
        5. 在服务器上(新项目保存在数据库中并获取新ID)
        6. 并希望实现一个更新数据和视图的干净机制,如何以正确的GWT风格方式完成?

1 个答案:

答案 0 :(得分:2)

声明

令人遗憾CellTree是一个非常复杂的小部件,与CellTableDataGrid相比,使用的概念完全不同。
这也是它不像其他CellWidgets那样阻止HasData接口的原因。

此外,CellTree更新和刷新其节点并不是很好的支持。有几种解决方法(请参阅herehere)。 试图解决其中一些问题的CellTree也有扩展(ProjectCodeDemo)。

我建议首先使用CellTree实现您的用例,然后担心它是否符合MVP样式。我已经可以告诉你,在处理View时,在PresenterCellTree之间绘制清晰的边界并不容易。

您的用例

如果我正确理解了您的用例,那么您有Container个对象列表(您使用的是CellList吗?),当您选择特定容器时,您想要显示项目列表在CellTree中,允许用户编辑和添加/删除项目。

我将尝试强调重要的步骤:

1。)您的数据结构与CellTree不能很好地协同工作。您应该引用父项和每个项目中的子项列表:

public class Item
{
    public int getItemId();
    public Item getParent();
    public List<Item> getChilds();
}
CellTreeDataGrid不同的

CellTable使用TreeViewModel

2.。)定义自定义TreeViewModel

public class MyCustomTreeModel implements TreeViewModel {

    private final SelectionModel<Item> selectionModel;
    private final ValueUpdater<Item> valueUpdater;

    public MyCustomTreeModel(final SelectionModel<Item> selectionModel, ValueUpdater<Item> valueUpdater) {
        this.selectionModel = selectionModel;
        this.valueUpdater = valueUpdater;
    }

    @Override
    public <T> NodeInfo<?> getNodeInfo(final T value) {
        // The root node is the container
        ListDataProvider<Item> = new ListDataProvider<Item>();
        if (value instanceof Container) {
            provider.setList(((Container)value).getItemList();
            return new DefaultNodeInfo<Item>(provider, containerCell, selectionModel,null);
        }
        provider.setList(((Item)value).getChilds());
        return new DefaultNodeInfo<Item>(provider, itemCell, selectionModel, valueUpdater);
    }

    @Override
    public boolean isLeaf(Object value) {
        Item item = (Item) value;
        return value != null && item.getChild().size() == 0;
    }
}

3.。)在MyCustomTreeModel中实例化自定义View并使用所选的CellTree实例创建Container(您可以在Presenter时创建public void onStartEdit(Container container, SelectionModel<Item> selectionModel, ValueUpdater<Item> valueUpdater) { CellTree tee = new CellTree(new MyCustomTreeModel(selectionModel,valueUpdater)); } 你选择一个容器:

add()

摘要

同样,您可能会遇到令人耳目一新的问题,您必须在remove()添加TreeViewModelCellTree功能才能添加和删除项目。

查看一些变通方法和代码的链接问题,我建议使用扩展的{{1}}。如果可能,请使用其他Widget。