视图事件
本节介绍可以在控制器中处理的视图生命周期事件。如需了解事件的顺序,请参阅本节末尾的 图表。
如需在 Jmix Studio 中生成视图事件处理方法的桩代码,在 Jmix UI 结构面板中选择根 或者也可以通过视图类代码顶部操作面板的 Generate Handler 或 Code → Generate 菜单(Alt+Insert / Cmd+N)。 |
InitEvent
InitEvent
是视图打开过程中产生的第一个事件。此时,视图及其所有声明式定义的组件已经创建,并完成依赖项注入。某些可视化组件未完全初始化,例如,按钮还未与操作关联。在此事件监听器中,可以创建并初始化可视化组件和数据组件。
@ViewComponent
private JmixComboBox<String> timeZoneField;
@Subscribe
public void onInit(final InitEvent event) {
timeZoneField.setItems(List.of(TimeZone.getAvailableIDs()));
}
该事件仅在创建视图后触发一次。也就是说,如果首次导航到视图,则会触发该事件。但是,如果多次导航至当前的视图(例如,多次点击同一菜单),则不会触发该事件,因为视图实例已创建。 |
BeforeShowEvent
BeforeShowEvent
是视图打开过程中的第二个事件(在 View.InitEvent
之后)。此时所有组件均已完成其内部初始化过程。数据加载器 已通过自动配置的 DataLoadCoordinator facet 触发。UI 组件中已经使用了安全策略。在此事件监听器中,可以加载数据、检查权限和修改 UI 组件。例如:
@ViewComponent
private CollectionLoader<User> usersDl;
@Subscribe
public void onBeforeShow(final BeforeShowEvent event) {
usersDl.load();
}
视图打开后,如果再次导航到已打开的视图将再次触发同一视图实例的 例如,用户首次导航到视图,会创建视图实例并触发
|
ReadyEvent
ReadyEvent
是视图打开过程中的最后一个事件(在 View.BeforeShowEvent
之后)。在该事件的监听器中,可以根据加载的数据对视图进行最终配置,并显示通知或对话框。
@Autowired
private Notifications notifications;
@Subscribe
public void onReady(final ReadyEvent event) {
notifications.show("Just opened");
}
视图打开后,如果再次导航到已打开的视图将再次触发同一视图实例的 例如,用户首次导航到视图,会创建视图实例并触发
|
AttachEvent
AttachEvent
当视图添加至 UI 时发送。
@Subscribe
public void onAttachEvent(final AttachEvent event) {
log.debug("View is attached");
}
该事件由 Vaadin 触发,因为视图也是一个 UI 组件。 |
BeforeCloseEvent
BeforeCloseEvent
是视图关闭过程中的第一个事件。此时视图仍显示并完全正常运行。在该事件监听器中,可以使用事件的 preventClose()
方法在特定条件下阻止关闭视图。
@Subscribe
public void onBeforeClose(BeforeCloseEvent event) {
if (!isLicenseAgreementAccepted()) {
CloseAction action = event.getCloseAction();
if (action instanceof NavigateCloseAction navigateCloseAction) {
BeforeLeaveEvent beforeLeaveEvent = navigateCloseAction.getBeforeLeaveEvent();
beforeLeaveEvent.postpone();
}
event.preventClose();
}
}
如果在导航时需要阻止关闭视图,那也需要延迟导航。可以检查操作的类型,如果是 NavigateCloseAction ,那么需要获取 Vaadin 的 BeforeLeaveEvent 并调用其 postpone() 方法。
|
AfterCloseEvent
AfterCloseEvent
是视图关闭过程中的第二个事件(在 View.BeforeCloseEvent
之后)。在该事件监听器中,可以在视图关闭之后显示通知或对话框,示例:
@Autowired
private Notifications notifications;
@Subscribe
public void onAfterClose(final AfterCloseEvent event) {
notifications.show("View is closed");
}
DetachEvent
DetachEvent
当视图中 UI 中移除时发送。在该事件监听器中可以释放视图占用的资源。
@Subscribe
public void onDetachEvent(final DetachEvent event) {
log.debug("View is detached");
}
该事件由 Vaadin 触发,因为视图也是一个 UI 组件。 |
QueryParametersChangeEvent
QueryParametersChangeEvent
事件可以获取视图打开时的 URL 查询参数。如果视图是通过导航打开的,那么该事件在 InitEvent
之后发送。
@ViewComponent
private Span messageLabel;
public void setMessage(String message) {
messageLabel.setText(message);
}
@Subscribe
public void onQueryParametersChange(final QueryParametersChangeEvent event) {
event.getQueryParameters()
.getSingleParameter("message")
.ifPresent(this::setMessage);
}
InitEntityEvent
InitEntityEvent
在视图继承了 StandardDetailView,新实体还未设置到被编辑实体的数据容器时发送。
可以在该事件监听器中初始化新实体实例的默认值,示例:
@Subscribe
public void onInitEntity(final InitEntityEvent<User> event) {
User user = event.getEntity();
user.setOnboardingStatus(OnboardingStatus.NOT_STARTED);
}
ValidationEvent
ValidationEvent
在视图继承了 StandardDetailView
,保存 DataContext 且完成验证时发送。使用该事件的监听器可以添加额外的视图验证。
@Subscribe
public void onValidation(final ValidationEvent event) {
if (entityStates.isNew(getEditedEntity())
&& !Objects.equals(passwordField.getValue(), confirmPasswordField.getValue())) {
event.getErrors().add("Passwords do not match");
}
}
BeforeSaveEvent
BeforeSaveEvent
在视图继承了 StandardDetailView
保存 DataContext
之前发送。使用该事件的监听器可以阻止保存、在保存前修改实体的属性值或与用户交互。
@ViewComponent
private JmixPasswordField passwordField;
@ViewComponent
private JmixPasswordField confirmPasswordField;
@Autowired
private EntityStates entityStates;
@Autowired
private PasswordEncoder passwordEncoder;
@Subscribe
public void onBeforeSave(final BeforeSaveEvent event) {
if (entityStates.isNew(getEditedEntity())) {
if (!Objects.equals(passwordField.getValue(), confirmPasswordField.getValue())) {
notifications.create("Passwords do not match")
.withType(Notifications.Type.WARNING)
.show();
event.preventSave(); (1)
}
getEditedEntity().setPassword(passwordEncoder.encode(passwordField.getValue())); (2)
}
}
1 | 如果密码不匹配则中断保存流程。 |
2 | 为实体设置加密的密码。 |
AfterSaveEvent
AfterSaveEvent
在视图继承了 StandardDetailView
保存 DataContext
之后发送。使用该事件的监听器可以在保存成功后通知用户。示例:
@Autowired
private Notifications notifications;
@Subscribe
public void onAfterSave(final AfterSaveEvent event) {
notifications.create("Entity saved successfully")
.withType(Notifications.Type.SUCCESS)
.withPosition(Notification.Position.TOP_END)
.show();
}