3

我从 TClientdataset 派生并尝试定义一个“始终运行”的 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;吗?它应该去哪里?

4

2 回答 2

3

你想做的事没有好地方。因为组件的用户可以在程序运行时随时将处理程序或 nil 附加到事件处理程序,而不仅仅是在设计时。也可以分离现有的处理程序。然后您的代码将无法运行。

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

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

...

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


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

于 2016-10-17T11:13:37.490 回答
0

Sertac 的回答是对这类问题的极好指导。是的,它确实回答了您提出的问题,但它缺少一些东西。

在我看来,你有一个 XY 问题,并且没有提出正确的问题。您无需尝试手动跟踪FInserting。德尔福已经这样做了。看看TDataSet.StateTDataSetState

基本上你FInserting相当于State = dsInsert.
尽管,正如您所指出的,您的FInserting标志TrueOnAfterPost其中(这使其具有误导性,并且在此基础上从技术上讲是一个错误)。

于 2016-10-17T13:02:45.057 回答