Delphi TField.OnValidate 可以在不引发异常的情况下恢复原始值吗?

Can Delphi TField.OnValidate restore the original value without raising exception?

我通常将验证逻辑实现为:

procedure TMyDM.IBQueryAMOUNTValidate(
  Sender: TField);
begin
  inherited;
  if Sender.AsFloat>100
    then raise Exception.Create('Amount is too large!');
end;

问题是 - 是否有机会不在 OnValidate 中引发 Exception (停止进一步处理),而是在 OnValidate 中静默恢复原始值并继续OnChangeCheckBrowseMode 以及 CheckBrowseMode/Post?

调用的所有 GUI 更新

当然,我知道我总是可以用处理 OldValueNewValueOnChange 逻辑替换 OnValidate 逻辑,但在我看来,代码应该是我坚持使用 OnValidate.

在我看来,OnValidate 事件的唯一目的是引发异常。来自 Delphi 帮助 (http://docwiki.embarcadero.com/Libraries/Berlin/en/Data.DB.TField.OnValidate):

To reject the current value of the field from the OnValidate event handler, raise an exception ...
If writing the data does not raise an exception, the OnChange event handler is called to allow a response to the change.

对于验证任务,我使用 OnSetText 事件,这使我可以在不接受新值时静默恢复原始值。

除了引发异常以拒绝 Sender的价值。

要了解原因,请设置一个简单的测试应用程序,该应用程序包含一个 TClientDataSet,其中包含字段 ID(整数)和名称(字符串(20))、TDataSource、 名称字段的 TDBNavigator、TDBGrid 和 TDBEdit。添加以下代码:

procedure TForm1.ClientDataSet1NameValidate(Sender: TField);
begin
  if Sender.AsString = 'x' then
    Sender.DataSet.Cancel;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ClientDataSet1.CreateDataSet;
  ClientDataSet1.InsertRecord([1, 'a']);
  ClientDataSet1.InsertRecord([2, 'b']);
  ClientDataSet1.InsertRecord([3, 'c']);
end;

编译,运行,然后在 DBEdit 中输入 'x'(不带引号)。然后在 DBNavigator 上单击保存。

请注意,编辑已取消,但 'x' 仍保留在 DBEdit 中。这是 在 Delphi 10.2.3 中,顺便说一句。回到 D7 时代,情况更糟 - 错误的行 数据库网格将显示 'x'!

另一件事是 OnValidate 实际上从未在 TDataSet 的方法中被调用, 只有后代,例如TClient 数据集。所以一般情况下不能保证 OnValidate 将在所有时间或在正确的时间被调用 - 这取决于数据集类型的作者是否正确。

所以我认为你的问题的答案是 "No",保留 OnValidate 以引发异常,但不会更多。