验证错误阻止撤消
Validation errors block undo
我的基于 EMF 的 Eclipse 应用程序存在以下问题:
撤消工作正常。验证工作正常。但是,当 GUI 字段中的数据存在验证错误时,这会阻止使用 撤消 操作。例如,无法撤消以返回该字段的有效状态。
在这张图片中无法使用撤销:
应用程序中使用的工具:
- Eclipse 数据绑定
UpdateValueStrategy
关于验证绑定
- 撤消是使用调用
CommandStack.undo
的标准 UndoAction
实现的
- A
MessageManagerSupport
class 将验证框架连接到基于 Eclipse Forms 的 GUI。
数据绑定如下所示:
dataBindingContext.bindValue(WidgetProperties.text(...),
EMFEditProperties.value(...), validatingUpdateStrategy, null);
问题是这样的:
- 撤消系统处理更改模型的命令。
- 验证系统会在出现验证错误时阻止更新到达模型。
要在出现验证错误时使撤消起作用,我想我可以做以下不同的事情之一:
- 让撤销系统在GUI层工作。 (这将是一个巨大的变化,可能根本不可能为此使用 EMF。)
- 使 GUI 中的无效数据触发更改模型数据的命令,其方式与有效数据相同。 (只要数据不能保存到磁盘就可以了。但是我找不到办法做到这一点。)
- 直接在模型上进行验证,可能由
Resource
上的内容侦听器触发。 (验证策略的一个大变化,这个阶段似乎无法跟踪源GUI控件。)
这些解决方案要么看起来不可能,要么有严重的缺点。
即使出现验证错误也能使撤消工作的最佳方法是什么?
注意:我接受 Mad Matts 的回答,因为他们的建议引导我找到我的解决方案。但我对此并不满意,我希望有更好的。
如果有人在某个时候找到更好的解决方案,我很乐意考虑接受它而不是当前的解决方案!
Validator 保护您的 Target 值免受无效值的影响是有道理的。
因此,在无效值的情况下,目标命令堆栈保持不变。
为什么要强制设置无效值? GUI 中的 ctrl + z
是否足以重置上一个有效状态?
如果您仍想将这些值设置为您的实际 Target 模型,您可以使用 UpdateValueStrategy
。
The update phases are:
Validate after get - validateAfterGet(Object)
Conversion - convert(Object)
Validate after conversion - validateAfterConvert(Object)
Validate before set - validateBeforeSet(Object)
Value set - doSet(IObservableValue, Object)
我不确定验证错误 (Status.ERROR
) 的确切位置,但您可以检查位置然后手动强制执行 SetCommand
。
您可以为 UpdateValueStrategy
的每个步骤设置自定义 IValidator
来做到这一点。
注意:这是我最终在我的应用程序中使用的解决方案。我不是很满意。我认为这有点像 hack。
我接受 Mad Matts 的回答,因为他们的建议让我找到了这个解决方案。
如果有人在某个时候找到更好的解决方案,我很乐意考虑接受它而不是当前的解决方案!
我最终创建了一个 UpdateValueStratety
sub-class,它运行一个验证器 在 模型对象上设置了一个值。这似乎工作正常。
我为 post 我最终使用的代码创建了这个答案。这是:
/**
* An {@link UpdateValueStrategy} that can perform validation AFTER a value is set
* in the model. This is used because undo dosen't work if no model changed in made.
*/
public class LateValidationUpdateValueStrategy extends UpdateValueStrategy {
private IValidator afterSetValidator;
public void setAfterSetValidator(IValidator afterSetValidator) {
this.afterSetValidator = afterSetValidator;
}
@Override
protected IStatus doSet(IObservableValue observableValue, Object value) {
IStatus setStatus = super.doSet(observableValue, value);
if (setStatus.getSeverity() >= IStatus.ERROR || afterSetValidator == null) {
return setStatus;
}
// I used a validator here that calls the EMF generated model validator.
// In that way I can specify validation of the model.
IStatus validStatus = afterSetValidator.validate(value);
// Merge the two statuses
if (setStatus.isOK() && validStatus.isOK()) {
return validStatus;
} else if (!setStatus.isOK() && validStatus.isOK()) {
return setStatus;
} else if (setStatus.isOK() && !validStatus.isOK()) {
return validStatus;
} else {
return new MultiStatus(Activator.PLUGIN_ID, -1,
new IStatus[] { setStatus, validStatus },
setStatus.getMessage() + "; " + validStatus.getMessage(), null);
}
}
}
我的基于 EMF 的 Eclipse 应用程序存在以下问题:
撤消工作正常。验证工作正常。但是,当 GUI 字段中的数据存在验证错误时,这会阻止使用 撤消 操作。例如,无法撤消以返回该字段的有效状态。
在这张图片中无法使用撤销:
应用程序中使用的工具:
- Eclipse 数据绑定
UpdateValueStrategy
关于验证绑定- 撤消是使用调用
CommandStack.undo
的标准 - A
MessageManagerSupport
class 将验证框架连接到基于 Eclipse Forms 的 GUI。
UndoAction
实现的
数据绑定如下所示:
dataBindingContext.bindValue(WidgetProperties.text(...),
EMFEditProperties.value(...), validatingUpdateStrategy, null);
问题是这样的:
- 撤消系统处理更改模型的命令。
- 验证系统会在出现验证错误时阻止更新到达模型。
要在出现验证错误时使撤消起作用,我想我可以做以下不同的事情之一:
- 让撤销系统在GUI层工作。 (这将是一个巨大的变化,可能根本不可能为此使用 EMF。)
- 使 GUI 中的无效数据触发更改模型数据的命令,其方式与有效数据相同。 (只要数据不能保存到磁盘就可以了。但是我找不到办法做到这一点。)
- 直接在模型上进行验证,可能由
Resource
上的内容侦听器触发。 (验证策略的一个大变化,这个阶段似乎无法跟踪源GUI控件。)
这些解决方案要么看起来不可能,要么有严重的缺点。
即使出现验证错误也能使撤消工作的最佳方法是什么?
注意:我接受 Mad Matts 的回答,因为他们的建议引导我找到我的解决方案。但我对此并不满意,我希望有更好的。
如果有人在某个时候找到更好的解决方案,我很乐意考虑接受它而不是当前的解决方案!
Validator 保护您的 Target 值免受无效值的影响是有道理的。
因此,在无效值的情况下,目标命令堆栈保持不变。
为什么要强制设置无效值? GUI 中的 ctrl + z
是否足以重置上一个有效状态?
如果您仍想将这些值设置为您的实际 Target 模型,您可以使用 UpdateValueStrategy
。
The update phases are:
Validate after get - validateAfterGet(Object)
Conversion - convert(Object)
Validate after conversion - validateAfterConvert(Object)
Validate before set - validateBeforeSet(Object)
Value set - doSet(IObservableValue, Object)
我不确定验证错误 (Status.ERROR
) 的确切位置,但您可以检查位置然后手动强制执行 SetCommand
。
您可以为 UpdateValueStrategy
的每个步骤设置自定义 IValidator
来做到这一点。
注意:这是我最终在我的应用程序中使用的解决方案。我不是很满意。我认为这有点像 hack。
我接受 Mad Matts 的回答,因为他们的建议让我找到了这个解决方案。
如果有人在某个时候找到更好的解决方案,我很乐意考虑接受它而不是当前的解决方案!
我最终创建了一个 UpdateValueStratety
sub-class,它运行一个验证器 在 模型对象上设置了一个值。这似乎工作正常。
我为 post 我最终使用的代码创建了这个答案。这是:
/**
* An {@link UpdateValueStrategy} that can perform validation AFTER a value is set
* in the model. This is used because undo dosen't work if no model changed in made.
*/
public class LateValidationUpdateValueStrategy extends UpdateValueStrategy {
private IValidator afterSetValidator;
public void setAfterSetValidator(IValidator afterSetValidator) {
this.afterSetValidator = afterSetValidator;
}
@Override
protected IStatus doSet(IObservableValue observableValue, Object value) {
IStatus setStatus = super.doSet(observableValue, value);
if (setStatus.getSeverity() >= IStatus.ERROR || afterSetValidator == null) {
return setStatus;
}
// I used a validator here that calls the EMF generated model validator.
// In that way I can specify validation of the model.
IStatus validStatus = afterSetValidator.validate(value);
// Merge the two statuses
if (setStatus.isOK() && validStatus.isOK()) {
return validStatus;
} else if (!setStatus.isOK() && validStatus.isOK()) {
return setStatus;
} else if (setStatus.isOK() && !validStatus.isOK()) {
return validStatus;
} else {
return new MultiStatus(Activator.PLUGIN_ID, -1,
new IStatus[] { setStatus, validStatus },
setStatus.getMessage() + "; " + validStatus.getMessage(), null);
}
}
}