In Part 1, I mentioned that I was writing a component which will eventually be single source, and run under both Win32 and .NET, with the same behaviour.

Well, I've completed it. In Delphi, TComponent has a method named Loaded. Loaded is a virtual method which you can override to initialize any data, that depends on other components, etc. Similarly, in CLR, there is a method named InitLayout, which needs to be overridden, so that you can initialize your component. InitLayout is called after your WinForm component is added to a WinForm.

At the point where InitLayout is called, FindForm is guaranteed to return a valid WinForm instance and Parent will return the parent to which the component is currently attached.

In order for single-sourced components to behave similarly on both Win32 and .NET, there is a necessity to refactor the actions to be taken when a property accessor is called.

For example, suppose I have a property named Magnification, declared thus,

published
  property Magnification: Integer read FMagnification write SetMagnification;

and SetMagnification is declared thus,

procedure TMyComp.SetMagnification(Value: Integer);
begin
   if Value <> FMagnification then
     FMagnification := Value;
// Code to modify the size of the component here, and
// in addition, modify the WinForm itself
end;

The block of code that modifies the size of the component, and modify the WinForm itself has to be moved into another procedure, or in other words, refactored. Then, SetMagnification will now look like this,

procedure TMyComp.SetMagnification(Value: Integer);
begin
   if Value <> FMagnification then
     FMagnification := Value;
  UpdateMagnification;
end;

procedure TMyComp.UpdateMagnification;
begin
  if Assigned(Parent) then
    begin 
// Modify the size of the component here, and in addition, modify the WinForm
// itself
    end;
end;

And, then, in InitLayout,

procedure TMyComp.InitLayout;
begin
   inherited;
   UpdateMagnification;
end;

Why the block of code in UpdateMagnification has to be moved there is because, it needs to refer to its Parent in order to update the size of the Parent. However, for a WinForm component, when a WinForm component is created, its properties are set, before the component is added to its Parent. That means, something like,

MyComp := TMyComp.Create;
MyComp.Magnification := 1;
...
... // creation of other components
Controls.Add(MyComp);

If I were to call UpdateMagnification at the point where the property Magnification is set without checking whether Parent is assigned, it is guaranteed to fail. Hence, InitLayout is the last chance for any component to initialize all it's values correctly.

I hope I'm clear on this part... If not, feel free to ask questions to clarify.