ZK/操作指南/数据绑定
外观
macrobind.zul: 宏组件的“视图”定义,一个姓氏和名字填充表单。注意文本框的 onChange 事件是如何使用 ZK3 的“转发”功能传播到空间所有者的。
<?xml version="1.0" encoding="UTF-8"?>
<grid>
<rows>
<row>First Name:
<textbox id="firstName" forward="onChange=onFirstNameChange"/>
</row>
<row>Last Name:
<textbox id="lastName" forward="onChange=onLastNameChange"/>
</row>
<row>Full Name: <label id="fullName"/></row>
</rows>
</grid>
macrobind.zs: 宏组件 Username 的类定义。它将 API 调用委派给真正的 UI 组件。
import org.zkoss.zk.ui.*;
import org.zkoss.zul.*;
public class Username extends HtmlMacroComponent {
public void setFirstName(String str) {
getFellow("firstName").setValue(str);
refreshFullName();
}
public String getFirstName() {
return getFellow("firstName").getValue();
}
public void setLastName(String str) {
getFellow("lastName").setValue(str);
refreshFullName();
}
public String getLastName() {
return getFellow("lastName").getValue();
}
private void refreshFullName() {
getFellow("fullName").setValue(getFirstName() + " " + getLastName());
}
}
usemacrobind.zul: 使用 Username 宏组件并应用注释数据绑定的示例应用程序。注意 @{...} 绑定中的 save-when 定义。它告诉 DataBinder 在事件触发时将 Username 的值保存到 Person 对象。access:both 告诉 DataBinder Username 对象既用于加载也用于保存。底部的按钮用于检查 Person 对象的属性是否真的发生了变化。
<?xml version="1.0" encoding="UTF-8"?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<?init zscript="macrobind.zs" ?>
<?component name="username" macro-uri="macrobind.zul" class="Username"?>
<window xmlns:a="http://www.zkoss.org/2005/zk/annotation">
<zscript>
//define a Person data object for data-binding test
public class Person {
private String _firstName;
private String _lastName;
public Person(String first, String last) {
_firstName = first;
_lastName = last;
}
public void setFirstName(String str) {
_firstName = str;
}
public String getFirstName() {
return _firstName;
}
public String setLastName(String str) {
_lastName = str;
}
public String getLastName() {
return _lastName;
}
}
Person person = new Person("Hello", "World");
</zscript>
<!--
see http://www.zkoss.org/javadoc/3.0.0/zkplus/org/zkoss/zkplus/databind/AnnotateDataBinder.html
-->
<username
firstName="@{person.firstName,save-when='self.onFirstNameChange',access=both}"
lastName="@{person.lastName,save-when='self.onLastNameChange',access=both}"/>
<button label="check Person" onClick='alert(person.firstName+" "+person.lastName)'/>
</window>
请注意,在 ZK2.4 中,无需使用“转发”功能,通过使用此版本的 macrobind.zul 可以在宏组件上显式触发事件来实现相同的功能。
<?xml version="1.0" encoding="UTF-8"?>
<grid>
<rows>
<row>First Name:
<textbox id="firstName">
<attribute name="onChange"><!-- delegate event to the Macro Component -->
Events.sendEvent(spaceOwner, new Event("onFirstNameChange", spaceOwner));
</attribute>
</textbox>
</row>
<row>Last Name:
<textbox id="lastName">
<attribute name="onChange"><!-- delegate event to the Macro Component -->
Events.sendEvent(spaceOwner, new Event("onLastNameChange", spaceOwner));
</attribute>
</textbox>
</row>
<row>Full Name: <label id="fullName"/></row>
</rows>
</grid>
people.zs: 我们需要一些 POJO 来绑定数据。这是一个快速创建 POJO 类文件,我们将把 xul 网格绑定到这个类。
/*
create a person class.
chould be compiled Java on your classpath we do it in beanshell
as it is quick and easy
*/
public class Person{
private String firstName;
private String lastName;
public String getFirstName(){
return firstName;
}
public void setFirstName(String firstName){
this.firstName = firstName;
}
public String getLastName(){
return lastName;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
public Person(String firstName, String lastName){
this.setFirstName(firstName);
this.setLastName(lastName);
}
}
example-people.zs: 我们需要一些示例数据 POJO。这是一个创建它们的示例文件。
// as sample list of persons. would be loaded from a database see
// the sample app
personA = new Person("john","wayne");
personB = new Person("jane","doe");
persons = new java.util.ArrayList();
persons.add(personA);
persons.add(personB);
index.zul: 将所有内容整合到一个数据绑定示例中。
<?init zscript="people.zs" ?>
<window>
<zscript src="example-people.zs"/>
<zscript>
// down to business. define how to assign components to each
// row for each object in the list that we are going to render
// as rows. note the setParent(row) that hooks the new component
// into the Desktop
public class MyRowRenderer implements RowRenderer {
public void render(Row row, Object data) {
new Label("First Name:").setParent(row);
new Textbox(((Person)data).getFirstName()).setParent(row);
new Label("Last Name:").setParent(row);
new Textbox(((Person)data).getLastName()).setParent(row);
}
}
// create a simple data mode wapping our list of persons
ListModel model = new SimpleListModel(persons.toArray());
// instantiate our custom row renderer
RowRenderer rowRenderer = new MyRowRenderer();
</zscript>
<!-- create a grid and assign the model and the renderer -->
<grid model="${model}" rowRenderer="${rowRenderer}"/>
</window>