在我的代码库中,我们非常依赖事件重新排队,我怀疑这是由于 ICEfaces 或 MyFaces 中的实现细节而不是标准指定的行为。我们过去经常做的一件事是这样的事情:
<ice:inputText value="#{bb.frequency}" valueChangeListener="#{bb.valueChanged}"/>
目标是安排在频率变化时retune
被调用。setFrequency
然后我们在支持 bean 中有一些相当恶心的代码,这些代码会重新排队事件。它通常看起来像这样:
class BB {
// this happens first, thanks to UPDATE_MODEL_VALUES
public void setFrequency(Frequency f) {
this.model.f = f;
}
public void valueChanged(ValueChangeEvent event) {
if (event.getOldValue().equals(event.getNewValue())
return; // nothing changed, so leave
if (FacesContext.getCurrentInstance().getPhaseId() != INVOKE_APPLICATION) {
OurMagicEventUtils.requeueEvent(event, INVOKE_APPLICATION);
}
else {
// do the post-setter work here (the setter happened recently during
// UPDATE_MODEL_VALUES so we're up-to-date by here
this.model.retune();
}
}
}
这不是一个好的生活方式。我还没有找到一种可靠的方法来为后期阶段重新排队事件,这显然不是人们做的那种事情。我看到两个解决方案:
将重调智能移至
BB#setFrequency
方法。在很多情况下,我无法摆脱这一点,因为我直接处理了一个较低级别的模型类,并且我不想干扰它对其他客户的行为。
创建一个自定义组件并将逻辑移到那里的
setFoo
方法中。我不喜欢这一点,因为 Mojarra 和自定义组件在嵌入其他容器时存在很多问题。对于我需要做的事情来说,这似乎也有点矫枉过正——我实际上只需要
retune
在设置一些属性后调用。为所有内容创建支持 bean。将大多数方法直接委托给内部事物,但
setFoo
在那里捕获并执行重调。这与我们过去所做的非常相似,它意味着大量的样板、包装器和胶水代码,所以我不喜欢它。
在我的脑海中,我想象这样的事情:
<ice:inputText value="#{bb.frequency}" afterChange=#{bb.retune}"/>
但这显然是行不通的,也不会附加一个,<f:actionListener>
因为它需要一个类名,但与你当前正在做的任何事情都没有关联,此外它只能设置在UICommand
s 上,而UIInput
s 不是。
解决这个困境的优雅/正确方法是什么?