How to define a class with published method in a separate unit that is available at design-time to other units?

别来无恙 提交于 2020-06-17 09:15:25

问题


To overcome a bug in 10.3.3 (see QC report https://quality.embarcadero.com/browse/RSP-29565) relating to TFDTable detailed elsewhere (Delphi TFDTable open fails when indexname is set), I want to be able to define a class with a method in a common unit that can be assigned (programmatically) as a BeforeOpen event in the relevant DFM for TFDTable components defined on a Form or DataModule.

I realize that this question has been asked before (e.g. How to make a separate unit for event methods, which IDE allows me to assign to component events at design time?), but the solutions batted about there match what I have done, and they do not work.

So, in a unit that must already be listed in the uses clause of the units using TFDTable, I define my class thus:

Common_unit:

type
  TmyMethodHolder = class(TComponent)
  published
    procedure FDTableBeforeOpen(DataSet: TDataSet);
  end;

...

var
  myMethodHolder : TmyMethodHolder=nil;

...

procedure TmyMethodHolder.FDTableBeforeOpen(DataSet: TDataSet);
begin
  // this procedure below is also defined within this "common_unit" 
  FDTableSetCatalogName(Dataset);
end;

...

initialization
  myMethodHolder := TmyMethodHolder.Create(nil);
finalization
  myMethodHolder.Free;

In the Registration unit, the component (and the class - though this seems to make no difference) are registered as follows:

RegisterComponents('MyComponents', [TmyMethodHolder]);
RegisterClass(TmyMethodHolder);

Finally, in a test unit, I define a Form with a TFDTable. That unit uses the "common_unit" above:

unit FDTable_Bug_Demo2;

interface

uses
  ... Common_Unit, ....

type

  TForm2 = class(TForm)
    DBGrid1: TDBGrid;
    Button1: TButton;
    FDConnection1: TFDConnection;
    DataSource1: TDataSource;
    edServer: TLabeledEdit;
    edDatabase: TLabeledEdit;
    edUserName: TLabeledEdit;
    edPassword: TLabeledEdit;
    Button2: TButton;
    Button3: TButton;
    FDTable1: TFDTable;
    ...

With the above in place, I can assign the BeforeOpen event of FDTable1 at runtime like so, and everything works as expected:

FDTable1.BeforeOpen := myMethodHolder.FDTableBeforeOpen;

However, I cannot assign the BeforeOpen event of FDTable1 at design-time (to e.g. myMethodHolder.FDTableBeforeOpen). The IDE complains that it is not a valid identifier.

Even if I drop a TMyMethodHolder component onto the Form as myMethodHolder1 (which rather defeats my purpose), I cannot assign the BeforeOpen event to myMethodHolder1.FDTableBeforeOpen. Again, not a valid identifier.

I assume what I am trying to do is possible, and I have just missed something basic. Help please.


回答1:


As per Remy Lebeau's comment, this looks like the best avenue of attack:

Why not just create an interposer class named TFDTable that derives from FireDAC.Comp.Client.TFDTable? It can override the virtual DoBeforeOpen() method, and you don't have to install it into the IDE if it is in another unit, just make sure that unit is in the Form/DataModule's uses clause after the FireDAC.Comp.Client unit, so that your TFDTable is the last one in scope so the DFM will stream it instead



来源:https://stackoverflow.com/questions/62397448/how-to-define-a-class-with-published-method-in-a-separate-unit-that-is-available

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!