Why are some properties repeated (such as Action
and Align
) where others are not (AlignWithMargins
) when TRttiContext.GetType is called on a VCL Control?
uses
System.RTTI,
System.Generics.Collections,
System.Generics.Defaults;
//....
procedure TForm11.btnShowPropertiesClick(Sender: TObject);
var
R: TRttiContext;
Props: TArray<TRttiProperty>;
Prop : TRttiProperty;
begin
memo1.Clear;
R := TRttiContext.Create;
Props := R.GetType(Sender.ClassType).GetProperties;
//Sort properties by name
TArray.Sort<TRttiProperty>(props,
TComparer<TRttiProperty>.Construct(
function(const Left, Right: TRttiProperty): Integer
begin
result := CompareText(Left.Name, Right.Name);
end
)
);
for prop in Props do
begin
try
Memo1.Lines.Add(
Prop.Name + ' : ' +
Prop.PropertyType.ToString + ' = ' +
Prop.GetValue(Sender).ToString);
except
Memo1.Lines.Add(Prop.Name + ' generated an exception');
end;
end;
end;
Output
Action : TBasicAction = (empty) Action : TBasicAction = (empty) Align : TAlign = alNone Align : TAlign = alNone AlignDisabled : Boolean = False AlignWithMargins : Boolean = False Anchors : TAnchors = [akLeft,akTop] Anchors : TAnchors = [akLeft,akTop] BiDiMode : TBiDiMode = bdLeftToRight BiDiMode : TBiDiMode = bdLeftToRight ...
If you would add Prop.Parent.Name
to the loop that populates the memo you could have easily found out the cause:
for prop in Props do
begin
try
Memo1.Lines.Add(
Prop.Parent.Name + '.' + { added }
Prop.Name + ' : ' +
Prop.PropertyType.ToString + ' = ' +
Prop.GetValue(Sender).ToString);
except
Memo1.Lines.Add(Prop.Name + ' generated an exception');
end;
end;
The code above produces:
TButton.Action : TBasicAction = (empty)
TControl.Action : TBasicAction = (empty)
TControl.Align : TAlign = alNone
TButton.Align : TAlign = alNone
TWinControl.AlignDisabled : Boolean = False
TControl.AlignWithMargins : Boolean = False
TControl.Anchors : TAnchors = [akLeft,akTop]
TButton.Anchors : TAnchors = [akLeft,akTop]
TButton.BiDiMode : TBiDiMode = bdLeftToRight
TControl.BiDiMode : TBiDiMode = bdLeftToRight
...
Now you can clearly see that that GetProperties
enumerates properties that were reintroduced in descendant class with higher visibility or altered order. This is typical for controls when TCustomMyControl
defines SomeProperty
with protected
visibility and TMyControl
reintroduces it at published
level.
You can try adding interposer class for TButton
before the TForm11
declaration:
type
TButton = class(Vcl.StdCtrls.TButton)
published
property AlignWithMargins;
end;
The output would reflect the change. I added fully qualified name of property's declaring type (Prop.Parent.QualifiedName
) to make it more obvious that TButton
comes from my own unit.
Vcl.StdCtrls.TButton.Action : TBasicAction = (empty)
Vcl.Controls.TControl.Action : TBasicAction = (empty)
Vcl.Controls.TControl.Align : TAlign = alNone
Vcl.StdCtrls.TButton.Align : TAlign = alNone
Vcl.Controls.TWinControl.AlignDisabled : Boolean = False
Vcl.Controls.TControl.AlignWithMargins : Boolean = False
Unit1.TButton.AlignWithMargins : Boolean = False
Vcl.Controls.TControl.Anchors : TAnchors = [akLeft,akTop]
Vcl.StdCtrls.TButton.Anchors : TAnchors = [akLeft,akTop]
Vcl.StdCtrls.TButton.BiDiMode : TBiDiMode = bdLeftToRight
Vcl.Controls.TControl.BiDiMode : TBiDiMode = bdLeftToRight
...
This kind of behavior is not limited to controls. It can be observed on any class that reintroduces properties from an ancestor class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With