想象一下,我有一个类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
是一个非常复杂的小部件,与CellTable
或DataGrid
相比,它们使用的概念完全不同。
这也是为什么它不像其他CellWidgets一样妨碍HasData
接口的原因。
此外,开箱即用的方式对CellTree
更新和刷新其节点的支持确实不够好。有两种解决方法(请参见here和here)。CellTree
的扩展也尝试解决其中的某些问题(Project,Code,Demo)。
我建议先使用CellTree
实现您的用例,然后再担心它是否适合MVP
样式。我已经告诉你,在处理View
时在Presenter
和CellTree
之间划出清晰的界限并不容易。
您的用例
如果我正确理解了您的用例,则会有一个Container
对象的列表(您使用的是CellList
吗?),并且当您选择一个特定的容器时,您想要在CellTree
中显示项目列表并允许用户来编辑和添加/删除项目。
我将尝试强调重要步骤:
1.)您的数据结构与CellTree
不能很好地配合。您应该引用每个项目的父项和子项列表:
public class Item
{
public int getItemId();
public Item getParent();
public List<Item> getChilds();
}
CellTree
与DataGrid
或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()
和TreeViewModel
函数以添加和删除项目。请查看链接的问题以获取一些解决方法和代码,我建议使用扩展的
CellTree
。如果可能,请使用其他小部件。关于java - 如何在GWT中为CellTree正确实现MVP?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24936431/