我在页面上有许多Wicket组件,它们使用PropertyModel
来反映某些bean的属性。使用AjaxFormComponentUpdatingBehavior
时,这些组件会在用户更改时通过Ajax自动更新。
当属性发生变化时,我想用我的组件编辑的bean会激活PropertyChangeEvent
,这些bean应触发重新呈现侦听这些事件的某些组件(实现PropertyChangeListener
):
示例:
TextField
和PropertyModel
AjaxFormComponentUpdatingBehavior
AjaxFormComponentUpdatingBehavior
onEvent
更新PropertyModel
(不幸的是,此方法为final
)PropertyModel
调用支持bean的属性设置器PropertyChangeEvent
onUpdate
,但现在它已经晚了,属性更改事件已经处理完毕。由于我的bean不可序列化,因此无法将组件永久注册为事件侦听器。我要么注册代理对象,以某种方式检索要通知的组件,要么注册我的组件临时以获取AJAX请求的范围。
我想要做的是在加载目标页面之后挂钩Wickets请求周期但之前 Ajax行为更新模型,这将导致PropertyChangeEvent
。在这里,我可以将每个组件注册为其后台bean(addPropertyChangeListener
)上的事件侦听器,以便在需要更新时通知他们。
然后,在onEvent
中,如果之前收到AjaxRequestTarget
,则每个组件都可以使用PropertyChangeEvent
来自行更新。
最后,在onDetach
中,组件可以从其bean(removePropertyChangeListener
)取消注册。
不幸的是,我发现没有内置的方法可以获得关于Ajax请求的通知#34;在我的Ajax行为的onUpdate
方法中,模型已经更新,注册更改侦听器为时已晚。我可以实现自己的行为,但是使用不同的组件选项(文本字段,选择列表等),这是非常有用的。
我错过了什么吗?
答案 0 :(得分:1)
我并不完全明白“注册为事件监听器的组件”的含义。你在谈论注册IRequestCycleListener
s?
无论哪种方式,也许Wicket的inter-component events可以帮助你。每个组件都实现以下接口:
public interface IEventSink
{
/**
* Called when an event is sent to this sink
*
* @param event
*/
void onEvent(IEvent<?> event);
}
您可以将AjaxFormComponentUpdatingBehavior
子类化为在模型更新后触发事件,如下所示:
public class AjaxUpdateEvent {
private final AjaxRequestTarget target;
public AjaxUpdateEvent(AjaxRequestTarget target) {
this.target = target;
}
public AjaxRequestTarget getAjaxRequestTarget() {
return target;
}
}
public class BeanModifiedEvent extends AjaxUpdateEvent {
private final Bean bean;
public BeanModifiedEvent(AjaxRequestTarget target, Bean theBean) {
super(target);
}
public Bean getBean() {
return bean;
}
}
public class CustomUpdatingBehavior extends AjaxFormComponentUpdatingBehavior {
protected abstract void onUpdate(AjaxRequestTarget target) {
Bean bean = getFormComponent().getModelObject();
getComponent().send(getComponent().getPage(), Broadcast.BREADTH, new BeanModifiedEvent(target, bean));
}
}
然后,您可以捕获所需组件中的事件并将其添加到ajax请求中:
public class UserDetailsPanel extends Panel {
.....
@Override
public void onEvent(IEvent event) {
if(event.getPayload() instanceof BeanModifiedEvent) {
// if(whatever) to control whether to add or not
AjaxRequestTarget target = ((BeanModifiedEvent) event.getPayload()).getAjaxRequestTarget();
target.add(...);
}
}
活动文件:
答案 1 :(得分:1)
您可以覆盖#getUpdateModel()以返回false,然后在#onUpdate()中执行任何操作,然后再调用getFormComponent()。updateModel()。
答案 2 :(得分:0)
您可以覆盖正在使用的每个组件的onModelChanging并在那里触发PropertyChangeEvent。根据之前调用的onModelChanging文档 模型改变了。
@Override
protected void onModelChanging() {
super.onModelChanging();
oldModelObject = yourComponent.getModelObject();
//fire PropertyChangeEvent
}
答案 3 :(得分:0)
这是我最终提出来的。
我将IContextProvider<AjaxRequestTarget, Page>
子类化为AjaxRequestTarget
个对象创建自定义提供程序。当请求AjaxRequestTarget
时,我使用Wicket的事件机制将其广播到组件树。
public class BroadcastingAjaxRequestTargetProvider implements IContextProvider<AjaxRequestTarget, Page> {
private final IContextProvider<AjaxRequestTarget, Page> parent;
public BroadcastingAjaxRequestTargetProvider(IContextProvider<AjaxRequestTarget, Page> parent) {
this.parent = parent;
}
@Override
public AjaxRequestTarget get(Page page) {
AjaxRequestTarget target = parent.get(page);
page.send(page, Broadcast.BREADTH, new AjaxRequestBegin(target));
return target;
}
}
类AjaxRequestBegin
只是封装AjaxRequestTarget
的小型有效负载对象。
我在我的Wicket应用程序init()
方法中注册了此提供程序:
setAjaxRequestTargetProvider(new BroadcastingAjaxRequestTargetProvider(getAjaxRequestTargetProvider()));
现在,在Wicket将其分派给组件或行为之前,在处理AJAX请求时会通知每个组件。组件可以覆盖onEvent
以为请求注册PropertyChangeListener
:
public void onEvent(IEvent<?> event) {
final Object payload = event.getPayload();
if (payload instanceof AjaxRequestBegin) {
final AjaxRequestTarget target = ((AjaxRequestBegin) payload).getTarget()
AjaxPropertyChangeListener listener = new AjaxPropertyChangeListener(target);
target.addListener(listener);
getBean().addPropertyChangeListener(listener);
}
}
private class AjaxPropertyChangeListener implements PropertyChangeListener, AjaxRequestTarget.IListener {
private final AjaxRequestTarget target;
public AjaxPropertyChangeListener(AjaxRequestTarget target) {
this.target = target;
}
@Override
public void propertyChange(PropertyChangeEvent event) {
target.add(MyComponent.this);
}
@Override
public void onBeforeRespond(Map<String, Component> map, AjaxRequestTarget target) {
}
@Override
public void onAfterRespond(Map<String, Component> map, IJavaScriptResponse response) {
getBean().removePropertyChangeListener(this);
}
}
请注意,AjaxPropertyChangeListener
还会在AJAX请求完成后实现AjaxRequestTarget.IListener
注销自己。