2
votes

I'm using RAD Studio XE5 to build my application.

I saw that is was not very practical to try tu publish properties on a TForm. It then has to be registered and installed as a package, then it's not practical for heavy development.

So, I decided I would create a non visual component (TFormPropertiesEditor) that would be used to fill up form properties. A way of standardising my forms.

The component would be dropped on the base form, a form of which every other form inherits (let's call it TBaseForm). So, the component would be dropped only once on the 'base' form, then with inheritance, every other form would have it too.

The created component would detect the class of its Owner (BaseForm or its descendents) and create an object accessible through the 'Properties' property, whose class would be conditional to the owner class.

This way, when inspecting the component on a TBaseForm, I would have access to the TBaseFormProperties only. When inspecting the component on a TSecondForm, I would also have access to the TSecondFormProperties. Only, the component would be intelligent enough to detect which PropertyClass it should expose as the Properties property.

The component would inspect the form, through the GetPropertiesClass, defined as :

function TBaseForm.GetPropertiesClass : TPropertiesClass;
begin
  Result := TBaseFormProperties;
end;

function TSecondForm.GetPropertiesClass : TPropertiesClass;
begin
  Result := TSecondFormProperties;
end;

Each form has a corresponding TProperties descendent, like so :

TBaseForm ------------ TSecondForm ------------- ...
    |
TBaseFormProperties -- TSecondFormProperties --- ...

For example :

If the Form on which the component is placed is TBaseForm, FProperties would be a TBaseFormProperties. If the form is a TSecondForm, FProperties would be TSecondFormProperties. Naturally, TSecondFormProperties would inherit from TBaseFormProperties.

Though, when I place the component on the form, it seems to be unable to detect of which class the component is.

function TFormPropertiesEditor.GetPropertiesClass: TFormPropertiesClass;
begin
  Result :=  TBaseForm(Owner).GetPropertiesClass;  
end;

It looks like the TBaseForm(Owner) part is causing the problem. The interpreter is stuck on the TBaseForm, and will not consider if Owner is of type TSecondForm or TThirdForm.

Interfaces

So, to get around the TBaseForm(Owner) typecasting, I decided to use an interface. So if I use an interface that declares the GetPropertiesClass:

IMasterForm = interface(IInterface)
  ['{B6122F34-65C4-4701-8A5E-50C8DABF5516}']
  function GetPropertiesClass : TFormPropertiesClass;
  end;


type
  TBaseForm = class(TForm, IMasterForm)
    MyFormPropertiesEditor1: TMyFormPropertiesEditor;
  private
    { Déclarations privées }
  public
    function GetPropertiesClass : UCommon.TFormPropertiesClass;
  end;     

The following :

function TFormPropertiesEditor.GetPropertiesClass : TFormPropertiesClass;
begin
  Result := (Owner as IMasterForm).GetPropertiesClass;
end;

Results into an Interface not supported error.

Abstract Ancestor Method

Then, I decided to add an extra layer of ancestry. I've added a class, TMasterForm, from which TBaseForm inherits. This TMasterForm declares GetPropertiesClass as abstract and virtual :

TMasterForm = class(TForm, IMasterForm)
    public
      function GetPropertiesClass : TFormPropertiesClass; virtual; abstract;
  end;


type
  TBaseForm = class(TMasterForm)
  private
    { Déclarations privées }
  public
    function GetPropertiesClass : UCommon.TFormPropertiesClass; override;
  end;

But then, I get an AV because I think the IDE tries to access TMasterClass.GetPropertiesClass, which is of course not implemented.

How can this TypeCasting be accomplished? Any idea how could I proceed ?

Thank you very much in advance

Download Sample Project https://www.wetransfer.com/downloads/b524438609fc04257af803a8e3dd2eca20141225161239/764d108d335b9d296c3004dfea04a54620141225161240/9c8cc0

2
You didn't register your base form with the IDE. So at design time the form that you see is not of type TBaseForm. What you are attempting isn't going to work. I think that all your work is in vain. Back to the drawing board. - David Heffernan
Perhaps you need RegisterCustomModule... - Free Consulting
@DavidHeffernan I don't think he is going about this the wrong way. Doesen't custom propertie editors of certain components use similar approach like this. - SilverWarior
@Silver I don't see how the IDE is going to instantiate TBaseForm or indeed any derived classes. How will it know to do that? - David Heffernan
Regarding your edit, did you read my comments? How is the IDE going to execute your code? - David Heffernan

2 Answers

2
votes

The basic problem here is that the IDE does not instantiate your form at designtime. So, no matter what code you put in the form class, it won't be executed by the IDE. This is because you did not register the form with the IDE.

If you wish the IDE to have knowledge of your forms then you need to register them with the IDE. And at that point all your code becomes needless because you are back to doing what you are attempting to avoid. Namely registering the forms with the IDE. You are stuck in a Catch 22 situation. If you need the IDE to know about the forms then you need to register them. At which point you may as well just surface the properties directly in the Object Inspector.

-1
votes

The problem in your code is that you are not inheriting your GetPropertiesClass method properly.

Infact you are not inheriting it across the class family.

In your code each class type has its own version of GetPropertiesClass method and therefore since you are typecasting the Owner to a TBaseForm class the method from TBaseForm is being used even if Owner is of TSecondForm class.

So you need to make sure that GetPropertiesClass in TBaseForm class is virtual and that merhod GetPropertiesClass in TSecondForm is overrided.

This will ensure that TSecondForm.GetProperties method will be called even when you are typecasting Owner to TBaseClass when the owner is of TSeconfForm class.