如何解决Apache Wicket - 更新共享特定模型的所有组件的最佳方式
使用 Apache Wicket 9 - 刷新所有 组件 共享的 模型 的最佳方法是什么后台进程?
以下代码有效,但恐怕有我不知道的更好(内置)解决方案。特别是没有为每个具有修改内容的 Model 调用 visitChildren() :
<wicket:panel>
<span wicket:id="child"></span><br>
<a wicket:id="update">update</a><br>
</wicket:panel>
public class Test extends Panel {
public Test(String id) {
super(id);
AtomicInteger i = new AtomicInteger(); // arbitrary content within the model
IModel<String> model = () -> i.toString();
add(new Label("child",model).setoutputMarkupId(true));
add(new AjaxLink<>("update") {
@Override
public void onClick(AjaxRequestTarget target) {
i.incrementAndGet(); // change content within the model
updateComponents(target,model,getPage());
}
});
}
// for all components in page use root = getPage()
public static void updateComponents(AjaxRequestTarget target,IModel<?> model,MarkupContainer root) {
root.visitChildren(Component.class,(c,ivisit) -> {
if (c.getDefaultModel() == model) target.add(c);
});
}
}
解决方法
Wicket 没有提供任何开箱即用的相关内容(在当前的最新版本中 - Wicket 9.2.0)。
你的实现在我看来相当不错!我也会这样做。
您可以考虑的一项改进是使用您可以全局注册的 AjaxRequestTarget.IListener,即如果您需要在多个地方使用相同的逻辑,则对于整个应用程序。
在 MyApplication#init() 方法中:
getAjaxRequestTargetListeners().add(new AjaxRequestTarget.IListener() {
@Override public void onBeforeRespond(final Map<String,Component> map,final AjaxRequestTarget target) {
// map's values are the Components what you have already added to AjaxRequestTarget
// I see your second approach:
// You can use RequestCycle's MetaData to store flags which types
// of components/behaviors/models need to be added to the target
// as well. I.e. in #onClick() do
// `RequestCycle.get().setMetaData(BEHAVIOR_TYPE,State2Listener.class)`
// and here use `Class<?> behaviorClass = `RequestCycle.get().getMetaData(BEHAVIOR_TYPE)`
}
});
,
虽然我最初的方法有效,但我发现它受到组件模型必须设计为适合比较这一事实的限制。为了克服这个限制,我想展示另一个基于简单自定义行为的解决方案。这样,我们就可以相应地刷新所有必需的组件,而无需对组件模型进行任何假设,如以下示例所示:
<wicket:panel>
<span wicket:id="child1"/> + <span wicket:id="child2"/> = <span wicket:id="sum"/><br>
<a wicket:id="update1">update1</a><br>
<a wicket:id="update2">update2</a><br>
</wicket:panel>
public class Test2 extends Panel {
// example data class
static class Pojo implements Serializable {
int i1,i2; // some mutable data
}
// data instance
Pojo data = new Pojo();
// listeners
public class State1Listener extends Behavior {}
public class State2Listener extends Behavior {}
public Test2(String id) {
super(id);
add(new Label("child1")
.add(new State1Listener()) // mark as depending on i1
.setDefaultModel(() -> Integer.toString(data.i1))
.setOutputMarkupId(true));
add(new Label("child2")
.add(new State2Listener()) // mark as depending on i2
.setDefaultModel(() -> Integer.toString(data.i2))
.setOutputMarkupId(true));
add(new Label("sum")
.add(new State1Listener()) // mark as depending on i1
.add(new State2Listener()) // and i2
.setDefaultModel(() -> Integer.toString(data.i1 + data.i2))
.setOutputMarkupId(true));
add(new AjaxLink<>("update1") {
@Override
public void onClick(AjaxRequestTarget target) {
data.i1++; // do some update on i1
// we know that i1 was (potentially) modified,// so refresh all components depending on i1
updateComponentsByBehavior(target,State1Listener.class,getPage());
}
});
add(new AjaxLink<>("update2") {
@Override
public void onClick(AjaxRequestTarget target) {
data.i2++; // do some update on i2
// we know that i2 was (potentially) modified,// so refresh all components depending on i2
updateComponentsByBehavior(target,State2Listener.class,getPage());
}
});
}
// static helper method
public static void updateComponentsByBehavior(AjaxRequestTarget target,Class<? extends Behavior> behaviorClazz,MarkupContainer root) {
root.visitChildren((c,ivisit) -> {
if (!c.getBehaviors(behaviorClazz).isEmpty()) target.add(c);
});
}
}
,
根据 martin-g 的回答,这里是对基于后一种 行为 方法的另一种改进。这次使用 RequestCycle.get/setMetaData() 而不是重复调用 visitChildren()。要使用此设置运行 Test2 示例,updateComponentsByBehavior(...) 的调用必须替换为 registerComponentsByBehavior(...) :
public class MyApplication extends WebApplication {
private static final MetaDataKey<List<Class<? extends Behavior>>> BEHAVIOR_TYPE
= new MetaDataKey<>() {};
public static void registerComponentsByBehavior(Class<? extends Behavior> behaviorClazz) {
// register behavior class in current cycle
RequestCycle.get().getMetaData(WicketApplication.BEHAVIOR_TYPE).add(behaviorClazz);
}
@Override
public void init() {
...
getRequestCycleListeners().add(new IRequestCycleListener() {
@Override
public void onBeginRequest(RequestCycle cycle) {
// clear list of registered behavior classes for current cycle
RequestCycle.get().setMetaData(BEHAVIOR_TYPE,new ArrayList<>());
}
});
getAjaxRequestTargetListeners().add(new AjaxRequestTarget.IListener() {
@Override
public void onBeforeRespond(final Map<String,final AjaxRequestTarget target) {
List<Class<? extends Behavior>> list =
RequestCycle.get().getMetaData(BEHAVIOR_TYPE);
target.getPage().visitChildren((c,ivisit) -> {
for (Behavior b : c.getBehaviors()) {
// add components if behavior has been previously
// registered in current cycle
if (list.contains(b.getClass())) target.add(c);
}
});
}
});
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。