派生的 TClient 数据集;定义一个 always-运行 OnAfterPost

Derived TClientdataset; defining an always-run OnAfterPost

我从 TClientdataset 派生并试图定义一个 'always run' AfterPost 事件。我已经尝试在构造函数中分配我的 AfterPost 事件,但派生组件似乎没有接收它

TMyClientDataset = class(TClientDataset)
private
  FInserting: Boolean;    //set to True at the MyOnNewRecord event
  property FuserAfterPost: TDataSetNotifyEvent;
...
public
  constructor Create(AOwner: TComponent);
...

implementation
constructor TMyClientDataset.Create(AOwner: TComponent)
begin
  ...
  if Assigned(AfterPost) then
    FuserAfterPost := AfterPost;
  Afterpost := MyAfterPost;
...
end;

procedure TMyClientDataset.MyAfterPost(Dataset: TDataset);
begin
  If Assigned(FuserAfterPost) then
    FuserAfterPost(Dataset);
  FInserting := False;
end;

我想做的是:在新记录上,设置 Finserting := True;在 post、运行 之后,用户提供了 OnAfterPost 并设置了 FInserting := False;但是 MyAfterpost 事件甚至不会 运行。我假设构造函数不是做 AfterPost := MyAfterPost; 的正确位置?它应该去哪里?

想做的事没有合适的地方。因为组件的用户可以在程序 运行ning 时随时将处理程序或 nil 附加到事件处理程序,而不仅仅是在设计时。也可以分离现有的处理程序。那么你的代码就不会运行.

出于这个原因,VCL 采用了对事件处理程序的两步调用。首先是一个虚拟过程,它通常只是调用一个可能的事件处理程序。在您的情况下,这是 DoAfterPost。

TMyClientDataset = class(TClientDataset)
  ..
protected
  procedure DoAfterPost; override;

...

procedure TMyClientDataset.DoAfterPost;
begin
  inherited;
  FInserting := False;
end;


对于不存在这样的机会的情况,除了正确记录并希望组件的用户阅读并遵守它之外没有机会。覆盖 Loaded 将是备份现有设计时附加处理程序的正确位置。

是解决此类问题的绝佳指南。是的,它确实回答了你提出的问题,但它遗漏了一些东西。

在我看来,您遇到了 XY 问题,未能提出正确的问题。您无需尝试手动跟踪 FInserting。 Delphi 已经这样做了。看看TDataSet.State and TDataSetState.

基本上你的 FInserting 等同于 State = dsInsert.
虽然,正如您所指出的,您的 FInserting 标志在 OnAfterPost 中是 True(这使它具有误导性,并且在此基础上在技术上是一个错误)。