2

你好,

我正在使用ZK 框架来开发 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>

测试控制器.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 事件上创建新的文本框,其值绑定到正确的属性。但是现在,如果我在 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 的情况下创建一个新组件并添加其数据绑定。我需要能够从控制器注册它。你能帮我吗?我会很感激的。

4

2 回答 2

2

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

于 2019-10-30T07:04:18.270 回答
1

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

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

希望这能澄清你的问题。

于 2010-07-28T10:41:33.663 回答