在仅运行时的包中,我定义了一个发布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切换到视觉设计师视图)。
我是否正确发布了OnLoaded事件?如果是这样,还有什么问题?
更多信息:
答案 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;