我们想用MVVM模式创建一个树。
这棵树应该有两个参数传递的目录。 我们的目标是创建一个目录浏览器,我们希望在打开一个孩子时有一个“按需加载”以获得更好的性能。
暂时,我们在文档中找到了例子,但它不完整:
public class TreeSelectionVM {
private TreeModel<TreeNode<String>> itemTree;
private String pickedItem;
//omit getter and setter for brevity
}
<window apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('org.zkoss.reference.developer.mvvm.collection.TreeSelectionVM')">
<tree id="tree" model="@bind(vm.itemTree) " width="600px"
selectedItem="@bind(vm.pickedItem)">
<treecols>
<treecol label="name" />
<treecol label="index" />
</treecols>
<template name="model" var="node" status="s">
<treeitem open="@bind(node.open)">
<treerow>
<treecell label="@bind(node.data)" />
<treecell label="@bind(s.index)" />
</treerow>
</treeitem>
</template>
</tree>
</window>
我们应该管理onOpen事件吗?或者我们应该实现TreeModel和TreeNode方法(getChild&amp; co)?
谢谢。
答案 0 :(得分:3)
这是一个更完整的zk mvvm树示例,它与目录资源管理器一致,按需加载:
https://github.com/simbo1905/zktreemvvm
只需使用“git clone”查看它,然后运行:
mvn -Djetty.port=8080 package jetty:run
代码将在给定端口上启动自己的jetty服务器。
它使用Apache Commons VFS作为文件系统的抽象,而不是使用更难以模拟和单元测试的原始java.io.File。默认情况下,代码显示ZK屏幕以浏览commons-vfs2-2.0.jar的内部,就好像它是常规文件和文件夹一样。只需将ViewModel类中的FILE_SYSTEM_URI uri更改为文件位置,如“file:/// some / path /”,即可查看常规文件系统。
zul页面包含一棵树,并将其模型绑定到vm.treeModel,并将selectedItem事件绑定到vm.pickedItem方法:
<?xml version="1.0" encoding="UTF-8"?>
<zk>
<window apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('org.github.simbo1905.zktreemvvm.CommonsVfs220ViewModel')">
<tree model="@load(vm.treeModel)" selectedItem="@bind(vm.pickedItem)">
<treecols>
<treecol label="name" />
<treecol label="index" />
</treecols>
<template name="model" var="node" status="s">
<treeitem>
<treerow>
<treecell label="@bind(node) @converter('org.github.simbo1905.zktreemvvm.NodeConverter')" />
<treecell label="@bind(s.index)" />
</treerow>
</treeitem>
</template>
</tree>
</window>
</zk>
@Converter对树模型中保存的FileObject数据进行友好呈现。
实际的ViewModel做的不多,但是保存selectedItem事件处理程序(除了日志之外什么都不做)并提供对TreeModel的访问:
public TreeModel<FileObject> getTreeModel() {
if (treeModel == null) {
try {
FileSystemManager fsManager = VFS.getManager();
FileObject fo = fsManager.resolveFile( FILE_SYSTEM_URI );
treeModel = new CachingVfsTreeModel(fo);
} catch (FileSystemException e) {
throw new IllegalArgumentException(String.format("Could not open VFS uri: %s",FILE_SYSTEM_URI),e);
}
}
return treeModel;
}
主要工作在VfsTreeModel类中,它扩展了AbstractTreeModel并定义了必需的方法
public class VfsTreeModel extends AbstractTreeModel<FileObject> {
// __ snip __
@Override
public FileObject getChild(FileObject parent, int index) {
log.info(String.format("%s getChild on %s with index %s", level(parent), innerName(parent), index));
FileObject child = null;
try {
FileObject[] children = parent.getChildren();
child = children[index];
} catch (FileSystemException e) {
throw new IllegalArgumentException(e);
}
return child;
}
@Override
public int getChildCount(FileObject node) {
int childCount = 0;
try {
FileType type = node.getType();
if( type == FileType.FOLDER ){
childCount = node.getChildren().length;
}
} catch (FileSystemException e) {
throw new IllegalArgumentException(e);
}
log.info(String.format("%s getChildCount on %s returning %s",level(node),innerName(node), childCount));
return childCount;
}
@Override
public boolean isLeaf(FileObject node) {
boolean isLeaf = false;
try {
FileType type = node.getType();
isLeaf = (type == FileType.FILE );
} catch (FileSystemException e) {
throw new IllegalArgumentException(e);
}
log.info(String.format("%s isLeaf on %s returning %s", level(node),innerName(node), isLeaf));
return isLeaf;
}
此错误跟踪器中有一个建议覆盖getPath,以防止框架进行大量其他调用以找出该信息:
http://tracker.zkoss.org/browse/ZK-1278
该方法是作为步行到根目录实现的:
@Override
public int[] getPath(FileObject node) {
List<Integer> paths = new ArrayList<Integer>();
try {
FileObject parent = node.getParent();
while (parent != null && parent.getType().equals(FileType.FOLDER)) {
FileObject[] children = parent.getChildren();
for( int index = 0; index < children.length; index++){
FileObject c = children[index];
if( node.equals(c)){
paths.add(index);
break;
}
}
node = parent;
parent = node.getParent();
}
} catch (FileSystemException e) {
throw new IllegalArgumentException(e);
}
int[] p = new int[paths.size()];
for( int index = 0; index < paths.size(); index++){
p[index] = paths.get(p.length - 1 - index); // reverse
}
log.info(String.format("%s getPath on %s",level(node),innerName(node)));
return p;
}
在以下树模型文档和“大数据”文档中,它建议使用缓存:
http://books.zkoss.org/wiki/ZK_Developer%27s_Reference/MVC/Model/Tree_Model
因此,在示例代码中,ViewModel创建了VfsViewModel的缓存子类。刷新页面会创建新对象并让缓存被垃圾收集,这对于这个例子来说可能已经足够了。
答案 1 :(得分:1)
文档告诉您实现自己的TreeModel
,我也是如此;)
有关详细信息,请阅读this。
以下是TreeModel
的一般示例
请记住,这只是一个普遍的例子,你必须提出。缓存
并且部分加载你的自我。
ZK的MeshElement
s的数据模型独立于MVVM或MVC,
结果model="xxx"
只需拨打setModel()
的{{1}}即可
并且ZK不关心Component
表达式,只要它是eval的
到ZK可以在java中找到的东西。并且模板替换了渲染器
示例:
.zul文件
xxx
ListboxMVVM
<window title="new page title" border="normal" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('web.zk.controller.ListboxMVVM')">
<listbox model="@load(vm.list)">
<listhead>
<listheader />
</listhead>
<template name="model">
<listitem>
<listcell label="@load(each.name)" />
</listitem>
</template>
</listbox>
</window>
</zk>
UsersListModel是一个impl。 public class ListboxMVVM {
public UsersListModel getList() {
return new UsersListModel(10, 0);
}
}
正如我之前提到的,this部分ZK文档讨论了如何实现。树的模型。
简而言之,
AbstractListModel
调用来获取预期的内容,其中逻辑的责任,
加载或卸载以及如何缓冲所需内容的方式,是你的
它返回的对象可以是你喜欢的任何东西,正如你所期望的那样,
在阅读public Object getElementAt(int index);
作为返回类型时
要从数据中生成树节点,请执行。一个renderer更像是MVC的方式
但也适用于MVVM,或者如上所述编写模板,其中Object
是你从each
的召唤得到的对象。
答案 2 :(得分:1)
我尝试实现RODTreeModel和RODTreeNode来分离模型/节点端和数据端,这样如果数据bean实现了RODTreeNodeData接口(whilch包含两个方法getChildren和getChildCount),任何数据bean都可以按需加载
基本概念/规则是让数据bean完成工作,用node.getChildCount()替换node.getChildren()。size(),并根据需要调用dataBean.getChildCount。
推迟getChildren()相关文件: