About the author
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 itselfend;
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 componentsControls.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.
Continued discussion of undocumented Delphi 8 Property Access Specifiers, and other ways of adding and removing delegates / events handlers, including clearing the list of all the delegates / event handlers.
This article discusses the new Delphi 8 property access specifiers.
A method pointer is now the same as a global procedure, ie, procedure of object = procedure.