如何正确发布活动?

时间:2016-10-10 13:45:29

标签: delphi events components design-time

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

There was an error while performing this operation

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

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;

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

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

enter image description here

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

更多信息:

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

1 个答案:

答案 0 :(得分:8)

更新(稍微有点虚假)回答

你接受了我的原始答案,但我写的不正确。 Rob Kennedy指出了前Embarcadero开发人员Allen Bauer关于Assigned主题的article

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

所有这些意味着在设计时致电False时会返回Assigned。只要在调用它们之前检查已发布的方法指针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;

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

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

原创(非常虚假)回答

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

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

Loaded方法应该如此防御:

procedure TMyFrame.Loaded();
begin
  inherited;
  if not (csDesigning in ComponentState) and Assigned(FOnLoaded) then 
    FOnLoaded();
end;