Delphi中自定义DataModule中断继承

Delphi中自定义DataModule中断继承,delphi,inheritance,custom-component,Delphi,Inheritance,Custom Component,我有一个自定义的DatModule(比如TMyDataModule),我希望向其中添加一个已发布的属性(枚举类型),以便在对象检查器中可以访问该属性(至少对于子体) 我将该单元添加到现有的设计时包中,并添加了注册代码,如“RegisterCustomModule(TMyDataModule,TCustomModule);”;卸载、重建、重新安装该软件包 当我打开通过从TMyDataModule继承创建的现有数据模块时,该属性将显示在OI中。到目前为止还不错 但是,通过从TMydataModule

我有一个自定义的DatModule(比如TMyDataModule),我希望向其中添加一个已发布的属性(枚举类型),以便在对象检查器中可以访问该属性(至少对于子体)

我将该单元添加到现有的设计时包中,并添加了注册代码,如“RegisterCustomModule(TMyDataModule,TCustomModule);”;卸载、重建、重新安装该软件包

当我打开通过从TMyDataModule继承创建的现有数据模块时,该属性将显示在OI中。到目前为止还不错

但是,通过从TMydataModule继承创建的任何现有(或新创建的)DMs,一旦创建,就不再从TMydataModule继承。如果我为这些子体中的任何一个编辑DFM,并尝试将开始的“对象”更改回“继承的”,那么当我退出DFM时,Delphi只会将其更改回

TMyDataModule上定义的组件在设计时不再出现在“表单”上,并且在设置属性等时无法引用它们(它们可以在代码中访问,但是……)

根据要求,举一个例子

这是父类(=TMyDataModule”):


现在,在注册定制模块之前,可以在设计时指定sdsData的SQLconnection属性,比如说在父级上定义的conMeta(它将在连接的下拉列表中显示为“conMeta”)(我们不需要这样做)注册自定义模块后,子代的OI中不会出现conMeta。但是,dmSQLBase.conMeta会出现。但是选择此选项可能会在运行时产生AV,除非单独实例化父代-这与目的相反,而且无论如何都是错误的

问题并不严重,因为对于一些现有的子代,它们的DFM将包含像上面示例中的“conMeta”这样的引用 这些引用是“无效的”(因此它们在运行时成为零指针)

实际上,我的观点是,注册模块的行为是“更干净的”。(像conMeta这样的组件也不会出现在孩子的“表单”上,这是一个加号)。
但是,如果我保留注册,我需要查找并更正任何此类引用,我只想了解到底发生了什么。

在我看来,您缺少的是注册一名库专家。。在您的设计时间包中,您应该注册库专家,如下所示:

RegisterLibraryExpert(TNewMyDataModuleExpert.Create); // <-- Your library expert
RegisterCustomModule(TMyDataModule, TCustomModule);
TNewMyDataModuleExpert = class(TIExpert)
  procedure Execute; override;
  function GetAuthor: string; override;
  function GetComment: string; override;
  function GetGlyph: HICON; override;
  function GetIDString: string; override;
  function GetName: string; override;
  function GetMenuText: string; override;
  function GetPage: string; override;
  function GetState: TExpertState; override;
  function GetStyle: TExpertStyle; override;
end;
TIExpert
ExptIntf
中声明。大多数重写方法的目的是将此专家紧密集成到IDE中。
Execute
方法是最重要的方法,可能具有如下实现:

procedure TNewMyDataModuleExpert.Execute;
var
  creator: TMyDataModuleCreator;
  modIntf: TIModuleInterface;
begin
  modIntf := nil;
  creator := TMyDataModuleCreator.Create;
  try
    modIntf := ToolServices.ModuleCreate(creator, [cmAddToProject, cmShowSource,
                                                   cmShowForm, cmUnNamed]);
  finally
    modIntf.Free;
    creator.Free;
  end;
end;
TMyDataModuleCreator = class(TIModuleCreator)
  function Existing: Boolean; override;
  procedure FormCreated(Form: TIFormInterface); override;
  function GetAncestorName: string; override;
  function GetFileName: string; override;
  function GetFileSystem: string; override;
  function GetFormName: string; override;
  function NewModuleSource(const UnitName, Form, Ancestor: string): string; override;
end;
请注意,这里还有另一个类,
TMyDataModuleCreator
。这个类负责最终创建新模块,声明如下:

procedure TNewMyDataModuleExpert.Execute;
var
  creator: TMyDataModuleCreator;
  modIntf: TIModuleInterface;
begin
  modIntf := nil;
  creator := TMyDataModuleCreator.Create;
  try
    modIntf := ToolServices.ModuleCreate(creator, [cmAddToProject, cmShowSource,
                                                   cmShowForm, cmUnNamed]);
  finally
    modIntf.Free;
    creator.Free;
  end;
end;
TMyDataModuleCreator = class(TIModuleCreator)
  function Existing: Boolean; override;
  procedure FormCreated(Form: TIFormInterface); override;
  function GetAncestorName: string; override;
  function GetFileName: string; override;
  function GetFileSystem: string; override;
  function GetFormName: string; override;
  function NewModuleSource(const UnitName, Form, Ancestor: string): string; override;
end;
TIModuleCreator
Editintf
中声明。这里最重要的方法是
NewModuleSource
,它应该返回您要为新模块生成的源代码。您在这里返回的将是新生成单元的确切源代码。例如,您可以添加注释、特定的uses条款或任何你喜欢的东西

另一个重要的方法是
GetAncestorName
返回字符串
'MyDataModule'
,不带通常的
T
前缀

在我的例子中,
Existing
方法总是返回
False
。对不起,现在我不记得为什么了。其他
string
返回方法返回空字符串

FormCreated
方法允许您在需要时对刚刚创建的对象执行操作


我想这对你会有用的!

这将受益于一个示例。Alex,谢谢你的详细回答。我仍在消化它。但是,我怀疑这只是简化了生成新表单的过程-我认为结果将与添加“base”相同“将单元添加到项目中,然后从中继承新的表单/数据模块。但我会查一查。谢谢。@坟墓:好的,汤姆,慢慢来。但是,关于这一点,我可以告诉您的是,结果与创建一个普通的数据模块并手动将其更改为从新类派生的结果不同。在这种情况下,DFM文件必须以
对象
开始,而不是以
继承的
开始,因为这是为了通知Delphi流媒体系统表单/模块使用了可视化继承。这就是为什么您将DFM更改为继承的,IDE将id更改回对象的原因。@tomber:您是否在设计包中调用了RegisterNoIcon来注册TMyDataModule类。我接受你关于它与继承不同的观点。。。我会查一查(但我相信你是对的)。不,我没有调用RegisterNoIcon-只是调用RegisterCustomModule。我应该吗?一些消息来源笼统地提到了这一点,但在这里似乎没有理由这样做。不确定。