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

我想写一个演讲者,与


CellTreeWidget实例和
用于获取数据的远程服务。


CellTreeWidget中显示的数据是项目列表。每个项目都有一个父项目,并且属于一个容器。

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

public class Item
{
    public int getItemId();
    public int getParentItemId();
}


演示者涉及以下过程:


用户选择一个容器(请参见下面的Presenter.startEdit)。
用户保存对容器所做的更改(请参见下面的Presenter.save)。


用户选择容器时,必须更新CellTreeWidget以显示新选择的容器的项目。

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


向远程服务发送保存请求,并
如果请求已正确处理,请确保树中的项目已更新。


步骤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实现的明显方法。

因此,我的问题是:如果你


具有树状结构
显示在CellTree中,
可以在客户端(用户添加新项目)和
在服务器上(新项目保存在数据库中并获得新的ID)


并想实现一种干净的机制来更新数据和视图,如何以正确的GWT方式完成它?

最佳答案

免责声明

不幸的是,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();
}


CellTreeDataGridCellTable不同,它使用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()TreeViewModel函数以添加和删除项目。

请查看链接的问题以获取一些解决方法和代码,我建议使用扩展的CellTree。如果可能,请使用其他小部件。

关于java - 如何在GWT中为CellTree正确实现MVP?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24936431/

10-10 18:25