0

我的基于 EMF 的 Eclipse 应用程序存在以下问题:

撤消工作正常。验证工作正常。但是当 GUI 字段中的数据出现验证错误时,这会阻止使用undo操作。例如,无法撤消以恢复该字段的有效状态。

在这张图片中,无法使用 undo

不是很有信息量的图像,希望能让这个问题看起来更有趣。


应用程序中使用的工具:

  • Eclipse 数据绑定
  • UpdateValueStrategys 在绑定上进行验证
  • 撤消是使用UndoAction调用的标准实现的CommandStack.undo
  • 一个MessageManagerSupport将验证框架连接到基于 Eclipse Forms 的 GUI 的类。

数据绑定如下所示:

dataBindingContext.bindValue(WidgetProperties.text(...), 
    EMFEditProperties.value(...), validatingUpdateStrategy, null);

问题是这样的:

  • 撤消系统对更改模型的命令起作用。
  • 当存在验证错误时,验证系统会阻止更新到达模型。

为了在出现验证错误时使撤消工作,我想我可以做以下不同的事情之一:

  1. 使撤消系统在 GUI 层上工作。(这将是一个巨大的变化,可能根本不可能使用 EMF。)
  2. 以与有效数据相同的方式,使 GUI 中的无效数据触发更改模型数据的命令。(只要数据不能保存到磁盘就可以了。但我找不到这样做的方法。)
  3. 直接在模型上进行验证,可能由Resource. (这是验证策略的一个很大的变化。在这个阶段似乎无法跟踪源 GUI 控件。)

这些解决方案要么看起来不可能,要么有严重的缺点。

即使存在验证错误,使撤消工作的最佳方法是什么?


注意:我接受 Mad Matts 的回答,因为他们的建议引导我找到解决方案。但我对此并不满意,我希望有一个更好的。

如果有人在某个时候找到了更好的解决方案,我很乐意考虑接受它而不是当前的解决方案!

4

2 回答 2

1

Validator 保护您的 Target 值免受无效值的影响是有道理的。因此,在无效值的情况下,目标命令堆栈保持不变。为什么要强制设置无效值?在 GUI 中是否ctrl + z不足以重置最后一个有效状态?

如果您仍想将这些值设置为您的实际目标模型,您可以使用UpdateValueStrategy.

更新阶段是:

  1. 获取后验证 - validateAfterGet(Object)

  2. 转换 - 转换(对象)

  3. 转换后验证 - validateAfterConvert(Object)

  4. 设置前验证 - validateBeforeSet(Object)

  5. 值集 - doSet(IObservableValue, Object)

我不确定验证错误 ( Status.ERROR) 到底发生在哪里,但您可以检查在哪里,然后SetCommand手动强制执行。您可以IValidator为每个步骤设置自定义UpdateValueStrategy来执行此操作。

于 2016-10-22T14:21:27.913 回答
1

注意:这是我最终在我的应用程序中使用的解决方案。我对此并不满意。我认为这有点像黑客。

我接受 Mad Matts 的回答,因为他们的建议使我找到了这个解决方案。

如果有人在某个时候找到了更好的解决方案,我很乐意考虑接受它而不是当前的解决方案!


我最终创建了一个在模型对象上设置值UpdateValueStratety运行验证器的子类。这似乎工作正常。

我创建了这个答案来发布我最终使用的代码。这里是:

/**
 * 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);
        }
    }
}
于 2016-10-26T11:50:19.433 回答