如何正确发布活动?

Fab*_*zio 3 delphi events components design-time

在仅运行时的包中,我定义了一个发布OnLoaded事件的TFrame后代:

type
  TMyMethod = procedure() of object;

  TMyFrame = class(TFrame)
  protected
    FOnLoaded : TMyMethod;
    procedure Loaded(); override;
  published
    property OnLoaded : TMyMethod read FOnLoaded write FOnLoaded;
  end;

implementation

{$R *.dfm}

procedure TMyFrame.Loaded();
begin
  inherited;
  if(Assigned(FOnLoaded))
  then FOnLoaded();
end;
Run Code Online (Sandbox Code Playgroud)

在仅限设计时的包中,我注册了TMyFrame组件,如下所示:

unit uMyRegistrations;

interface

uses
  Classes, uMyFrame;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('MyTestComponents', [
    TMyFrame
  ]);
end;
Run Code Online (Sandbox Code Playgroud)

我已经安装了designtime包,我可以在工具选项板中找到TMyFrame,并在对象检查器中显示其OnLoaded事件.

我已将TMyFrame拖入表单中,然后通过双击对象检查器分配了OnLoaded事件.在分配事件之后,我注意到每次我尝试在Delphi中打开表单的文件时都会出现访问冲突错误消息(它让我打开".pas"文件,但我无法切换到可视化设计器视图).

在此输入图像描述

我是否正确发布了OnLoaded事件?如果是这样,还有什么不对?

更多信息:

  1. 我正在使用Delphi 2007(不知道它是否重要).
  2. 通过对不同的父类执行相同的操作(不仅对于TFrame后代),也会出现错误.

Dav*_*nan 8

更新(稍微少于虚假)的答案

你接受了我的原始答案,但我写的不正确.Rob Kennedy指出了前Embarcadero开发商Allen Bauer关于该主题的一篇文章Assigned.

Allen解释说该Assigned函数只测试方法指针中两个指针的一个指针.IDE在设计时通过将sentinel值分配给任何已发布的方法属性(即事件)来利用此功能.这些sentinel值具有nil方法指针(Assigned检查的指针)中的两个指针之一,以及标识另一个指针中的属性值的索引.

所有这些意味着FalseAssigned在设计时致电时返回.只要Assigned在调用之前检查已发布的方法指针,就不会在设计时调用它们.

所以我最初写的不是真的.

所以我挖得更深了一点.我使用了以下非常简单的代码,使用XE7进行测试:

type
  TMyControl = class(TGraphicControl)
  protected
    FSize: Integer;
    procedure Loaded; override;
  end;

....

procedure TMyControl.Loaded;
begin
  inherited;
  FSize := InstanceSize;
end;

....

procedure Register;
begin
  RegisterComponents('MyTestComponents', [TMyControl]);
end;
Run Code Online (Sandbox Code Playgroud)

这足以在Loaded执行方法时在设计时在IDE中导致AV .

我的结论是,IDE在流式传输时会做一些相当不好的事情,并且在Loaded调用方法时,您的对象不适合使用.但我真的没有比这更好的理解.


原始(非常虚假)答案

您不能在设计时执行事件处理程序,而您的代码就是这样做的.原因是在设计时事件处理程序的代码不可用.

控件的代码可用,IDE已加载它 - 但实现事件处理程序的代码不是.该代码不是设计时包的一部分,它是当前在IDE中打开的项目的一部分.毕竟,它甚至可能还没有编译!

Loaded方法应该像这样防范:

procedure TMyFrame.Loaded();
begin
  inherited;
  if not (csDesigning in ComponentState) and Assigned(FOnLoaded) then 
    FOnLoaded();
end;
Run Code Online (Sandbox Code Playgroud)

  • `Assigned`函数应该已经防范了.[在设计时,IDE将事件处理程序设置为一个特殊值,以便它知道在DFM资源中写入什么,但是"Assigned"将认为是未分配的.](http://community.embarcadero.com/blogs/entry/assigned-or-not-assigned-that-the-question-28836)除非从'Loaded`中触发事件处理程序有什么特别之处,我认为这个问题还有更多. (2认同)