Xpage extlib Dialog keepComponents是true和JSF组件

时间:2013-04-05 07:22:22

标签: xpages xpages-extlib

我对Extention库中的Dialog控件有问题:

我创建了一个java自定义控件,它搜索一些视图,收集一些数据并显示它。如果我把它放在XPage上,这很好用。

但是我想在Dialog中显示数据,所以我使用了扩展库中的Dialog控件。在没有任何配置的情况下使用Dialog控件也可以正常工作,但是每次打开对话框时我的控件都需要一些时间来搜索视图并显示数据。为了减少用户的等待时间,我想使用选项{{对话框控件中的1}}。

现在,如果我第一次打开Dialog,一切都是完美的,但是如果我打开它一段时间它会显示第一个开头的内容,除了我的controlRenderer的错误,它告诉我它无法获取viewName从控制。每次打开和关闭对话框时,此错误都会叠加。

我在OpenNtf上发现了一个帖子,当他使用这个选项时,他的对话框中有多个内容存在同样的问题,但他没有得到任何答案。 这是组件的错误吗?我应该忘记这个选项并将我的数据缓存在bean中吗?为什么渲染器不能从组件中获取Viewname?

1 个答案:

答案 0 :(得分:0)

下面的答案假定您的问题中的短语“java custom control”指的是您开发的JSF组件;在XPages中,术语“自定义控件”通常是指自定义控件设计元素的一个实例,它是IBM对“复合组件”的JSF概念的实现。

您已声明该组件最初的行为符合预期,但在后续请求中失败。这通常表示组件的restoreStatesaveState方法尚未正确实施。

当为应用程序启用默认序列化选项时,所有组件状态将在每个请求结束时写入磁盘,并在下一个开始时读回内存。这两个操作分别由每个组件的saveStaterestoreState方法处理。

例如,假设您定义了一个用于将HTML画布标签添加到XPage的组件,并决定支持与该元素关联的手势和触摸事件。因此,您的组件类将包含用于存储绑定到这些事件的任何代码的字段:

private String ongesturechange;
private String ongestureend;
private String ongesturestart;
private String ontouchcancel;
private String ontouchend;
private String ontouchmove;
private String ontouchstart;

这些字段中的每一个通常都会有一个关联的“getter”和“setter”方法:

public String getOngesturechange() {
    return getStringProperty("ongesturechange", this.ongesturechange);
}

public void setOngesturechange(String ongesturechange) {
    this.ongesturechange = ongesturechange;
}

初始化该组件的实例时,将为该组件实例定义的每个属性关联的“setter”方法将传递为该属性定义的值。然后,对于初始页面请求的剩余部分,每个已定义属性的私有字段将存储已设置的值。在请求结束时,saveState方法将这些字段的值写入磁盘。典型的saveState方法类似于以下内容:

@Override
public Object saveState(FacesContext context) {
    Object[] properties = new Object[8];
    int idx = 0;
    properties[idx++] = super.saveState(context);
    properties[idx++] = this.ongesturechange;
    properties[idx++] = this.ongestureend;
    properties[idx++] = this.ongesturestart;
    properties[idx++] = this.ontouchcancel;
    properties[idx++] = this.ontouchend;
    properties[idx++] = this.ontouchmove;
    properties[idx++] = this.ontouchstart;
    return properties;
}

super.saveState()的调用执行相同的方法,但使用父类中定义的方法版本。因此,每个组件的磁盘表示基本上是一个嵌套数组:层次结构中的每个层都存储它从数组的第一个元素中的父类继承的所有属性,然后存储它在其他数组元素中定义的所有属性

在后续请求中恢复组件树时,每个组件都使用其restoreState方法重新构建其所有字段的值。典型的restoreState方法类似于以下内容:

@Override
public void restoreState(FacesContext context, Object state) {
    Object[] properties = (Object[]) state;
    int idx = 0;
    super.restoreState(context, properties[idx++]);
    this.ongesturechange = ((String) properties[idx++]);
    this.ongestureend = ((String) properties[idx++]);
    this.ongesturestart = ((String) properties[idx++]);
    this.ontouchcancel = ((String) properties[idx++]);
    this.ontouchend = ((String) properties[idx++]);
    this.ontouchmove = ((String) properties[idx++]);
    this.ontouchstart = ((String) properties[idx++]);
}

这将分层读取磁盘数据:每个类将一组属性传递给父类,然后将剩余的数组元素分配给它们在保存组件状态时与之关联的字段。

此过程提供了一种跨请求维护组件状态的简单方法 - 每个继承层只需要关注层定义的新属性 - 但这些状态维护方法很容易忘记实现。如果组件实现中省略了任一方法,那么页面将“忘记”后续请求中的属性值,因为它们从未写入磁盘,或者未加载回内存,或两者都没有。

假设这是您的问题的根本原因,当组件位于具有false的默认(keepComponents)值的对话框内时不会发生问题的原因是因为默认对话框行为是在关闭对话框时完全从组件树中删除其子项。此行为是出于性能原因:理论上,从存储仅存在于用户当前未与之交互的对话框内的组件的服务器端表示中获得的好处是没有好处。再次打开该对话框时,将使用原始属性值创建每个子组件的 new 实例。在这种情况下,组件没有保存其状态并不重要,因为每次使用它时,都会创建一个新实例。但是,如果告诉对话框将其子节点保留在组件树中,则现在组件必须正确维护其自己的状态...否则在每个请求结束时将丢弃其属性值,并且后续请求不会知道先前的值。 / p>

总而言之,是的,如果数据在每次单个事件期间再次获取数据的请求之间的数据不太可能发生变化,那么您显示的数据应该缓存在bean(或数据源)中。但是您所描述的特定行为的原因很可能是因为您的组件实现没有正确维护自己的状态。