ZK:如何创建组件和注册数据绑定

问题描述 投票:2回答:2

嗨,

我正在使用ZK framework开发Web应用程序。我在组件上使用数据绑定来设置和获取值。我可以在源ZUL文件中以及在页面控制器的doAfterCompose方法中注册数据绑定。在页面撰写期间调用此方法。但是现在我必须添加一个新组件,并将其数据绑定到现有的组成页面中。我知道如何创建组件,这很简单,但是我在注册数据绑定时遇到了问题。框架引发异常,我正在使用未知数据Bean。

有一个简单的代码应该可以,但是不能。该ZUL文件描述了简单的页面布局和控制器捕获事件等。使用了注释ZkModel和ZkEvents。这些注释不是框架的一部分,它们是我们的增强功能。 ZkModel将变量发布到ZUL文件,因此可以使用数据绑定从ZUL文件进行访问。 ZkEvent在组件上注册事件,并在事件上调用这些方法。这些增强功能正在起作用,因此没有问题。

ZUL文件(test.zul):

<?xml version="1.0" encoding="UTF-8"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<?init class="cz.datalite.zk.databinder.DLDataBinderInit" root="winTest" validator="${validator}"?>
<!-- template -->
<?init class="org.zkoss.zk.ui.util.Composition" arg0="/includes/template.zul"?>
<?page title="Test page"?>

<zk xmlns="http://www.zkoss.org/2005/zul">
    <window id="winTest"  self="@{define(content)}" height="100%" apply="${testController}">
        <button label="OK" id="btn"/>
        <label id="lab" value="text"/>
        <textbox id="txt1" value="@{ctl.bindingValue}"/>
    </window>
</zk>

TestController.java:

package cz.datalite.bpej.evidence;

import cz.datalite.stereotype.Controller;
import cz.datalite.zk.annotation.ZkEvent;
import cz.datalite.zk.annotation.ZkModel;
import cz.datalite.zk.components.textbox.DLTextbox;
import cz.datalite.zk.composer.DLComposer;
import java.util.HashMap;
import java.util.Map;
import org.zkoss.zk.ui.Component;
import org.zkoss.zkplus.databind.Binding;
import org.zkoss.zkplus.databind.DataBinder;
import org.zkoss.zul.impl.XulElement;

@Controller // this class serves as a controller
public class TestController extends DLComposer {

    @ZkModel // this property is published and accessible from ZUL file
    String bindingValue = "there is binding text";

    @ZkEvent( id = "btn" ) // this methods is invoked on "onClick" event on component "btn"
    public void onOk() throws Exception {
        DLTextbox textbox = new DLTextbox();
        textbox.setParent( self );
        setValueAnnotation( textbox, "value", "ctl.bindingValue" );    
    }

    /**
     * Sets the component's annotation to specific value
     * (call eg. setValueAnnotation(comp, "model", "aaa") is corresponding to model="@{aaa}")
     * @param comp defined component
     * @param propName name of property
     * @param annot annotation
     */
    private void setValueAnnotation( XulElement comp, String propName, String annot ) {
        DataBinder binder = ( DataBinder ) comp.getVariable( "binder", false );

        // adds new binding
        Map attrs = new HashMap();
        attrs.put( "value", annot );
        binder.addBinding( comp, propName, annot );

        // if the first bean is fellow then register it ( if it hasn't been used yet then it is not registered. )
        String bean = annot;
        if ( bean.contains( "." ) ) {
            bean = bean.split( "\\." )[0];
        }
        Component fellowBean = comp.getFellowIfAny( bean );
        if ( fellowBean != null ) {
            binder.bindBean( bean, fellowBean );
        }

        // load components value
        Binding bind = (( DataBinder ) comp.getVariable( "binder", false )).getBinding( comp, propName );
        if ( bind != null ) {
            bind.loadAttribute( comp );
        }

    }
}

如果我运行这两个文件,则应用程序运行正常。在onClick事件上,on按钮上的事件将创建新的文本框,其值绑定到right属性。但是现在,如果我在ZUL文件中评论文本框组件

        <!--textbox id="txt1" value="@{ctl.bindingValue}"/-->

然后它停止工作。现在有抛出异常

找不到指定的数据绑定Bean表达式:ctl.bindingValue

org.zkoss.zkplus.databind.DataBinder(DataBinder.java#myGetBeanWithExpression:1004)
org.zkoss.zkplus.databind.DataBinder(DataBinder.java#getBeanAndRegisterBeanSameNodes:988)
org.zkoss.zkplus.databind.Binding(Binding.java#loadAttribute:413)
cz.datalite.bpej.evidence.TestController(TestController.java#setValueAnnotation:58)
cz.datalite.bpej.evidence.TestController(TestController.java#onOk:25)

这就是问题所在。我需要能够在不使用ZUL文件中的bean的情况下创建一个新组件并添加其数据绑定。我需要能够从控制器进行注册。你能帮我吗?我会很感激。

java data-binding zk
2个回答
1
投票

不幸的是,当前的DataBinder尚不支持动态绑定(必须等待Data Binding 2.0,希望在ZK 5.5中可用)。

当前的DataBinder实现将在首次调用getXxx()或setXxx()之后忽略以后添加的所有绑定。在这些方法中,init()方法是按需调用的,如果曾经调用过,则不会再次调用。在init()方法中,基本上,DataBinder会扫描所有Bindings并构造一个内部数据结构,然后再使用这些内部数据结构。(这就是DataBinder无法看到后来添加的绑定的原因)

希望这可以澄清您的问题。


1
投票

在zk 8中,这可以通过模板机制以及viewmodel概念的@load@bind功能来实现:http://books.zkoss.org/zk-mvvm-book/8.0/data_binding/children_binding.html

© www.soinside.com 2019 - 2024. All rights reserved.