RTTI 和 DevExpress
RTTI and DevExpress
我试图在 VCL 组件上获取和设置一些 属性 值。有些是 DevExpress,有些不是。
我写了一个小帮手class:
type
RttiHelper = class
strict private
public
class function GetPropertyValue(const aObject: TObject; const aPropertyName, aSecondLevel: string): TValue; inline;
class function GetPropertyValue2(const aObject: TObject; const aPropertyName, aSecondLevel: string): TValue; inline;
class procedure GetProperty(const aObject: TObject; const aPropertyName, aSecondLevel: string; var aRttiProperty: TRttiProperty); inline;
end;
{ TRttiHelper }
class procedure RttiHelper.GetProperty(const aObject: TObject; const aPropertyName, aSecondLevel: string; var aRttiProperty: TRttiProperty);
var
NextLevel: TObject;
begin
aRttiProperty := TRttiContext.Create.GetType(aObject.ClassType).GetProperty(aPropertyName);
if aRttiProperty = nil then // Try harder: Look after the property in next level
begin
aRttiProperty := TRttiContext.Create.GetType(aObject.ClassType).GetProperty(aSecondLevel);
if aRttiProperty <> nil then
begin
NextLevel := aRttiProperty.GetValue(aObject).AsObject;
if NextLevel = nil then
exit;
aRttiProperty := TRttiContext.Create.GetType(NextLevel.ClassType).GetProperty(aPropertyName);
end;
end;
end;
class function RttiHelper.GetPropertyValue(const aObject: TObject; const aPropertyName, aSecondLevel: string): TValue;
var
RttiProperty: TRttiProperty;
aInstance, Properties: TObject;
begin
RttiProperty := TRttiContext.Create.GetType(aObject.ClassType).GetProperty(aPropertyName);
aInstance := aObject;
if RttiProperty = nil then // Try harder: Look after the property in next level
begin
RttiProperty := TRttiContext.Create.GetType(aObject.ClassType).GetProperty(aSecondLevel);
if RttiProperty <> nil then
begin
Properties := RttiProperty.GetValue(aObject).AsObject;
aInstance := Properties;
if Properties = nil then
exit(nil);
RttiProperty := TRttiContext.Create.GetType(Properties.ClassType).GetProperty(aPropertyName);
end;
end;
if RttiProperty = nil then // Nothing found
exit(nil);
Result := RttiProperty.GetValue(aInstance);
end;
class function RttiHelper.GetPropertyValue2(const aObject: TObject; const aPropertyName, aSecondLevel: string): TValue;
var
RttiProperty: TRttiProperty;
begin
RttiHelper.GetProperty(aObject, aPropertyName, aSecondLevel, RttiProperty);
if RttiProperty <> nil then
Result := RttiProperty.GetValue(aObject)
else
Result := nil;
end;
最好我想调用 GetProperty
方法然后获取或设置值但是在 DevExpress 组件上我没有得到正确的结果。
重现方法如下:
在窗体上放置一个TEdit
和TcxTextEdit
,然后编写如下代码:
Edit1.Text := RttiHelper.GetPropertyValue2(Edit1, 'Color', 'Style').AsVariant;
cxTextEdit1.Text := RttiHelper.GetPropertyValue2(cxTextEdit1, 'Color', 'Style').AsVariant;
如果我使用这段代码,它会很好地工作:
Edit1.Text := RttiHelper.GetPropertyValue(Edit1, 'Color', 'Style').AsVariant;
cxTextEdit1.Text := RttiHelper.GetPropertyValue(cxTextEdit1, 'Color', 'Style').AsVariant
谁能告诉我我做错了什么?
问题出在这一行:RttiProperty.GetValue(aObject)
我在原始对象上调用了 GetValue,但不确定 属性 是否放在该对象上。
属性 颜色例如是一个很好的例子:在 TEdit 上它被放置在 "Main Object" 上。您可以编写 Edit1.Color := clBlue;
,但在 TcxTextEdit 中,颜色 属性 位于样式对象上,因此您必须编写:cxTextEdit1.Style.Color := clBlue
。因为我需要在正确的对象上调用 RttiProperty.GetValue(aObject)
。
为了做到这一点,我从
中更改了 GetProperty
的声明
class procedure GetProperty(const aObject: TObject; const aPropertyName, aSecondLevel: string; var aRttiProperty: TRttiProperty);
收件人:
class procedure GetProperty(var aObject: TObject; const aPropertyName, aSecondLevel: string; var aRttiProperty: TRttiProperty);
实施更改为:
class procedure RttiHelper.GetProperty(var aObject: TObject; const aPropertyName, aSecondLevel: string; var aRttiProperty: TRttiProperty);
var
NextLevel: TObject;
begin
aRttiProperty := ctx.GetType(aObject.ClassType).GetProperty(aPropertyName);
if aRttiProperty = nil then // Try harder: Look after the property in next level
begin
aRttiProperty := ctx.GetType(aObject.ClassType).GetProperty(aSecondLevel);
if aRttiProperty <> nil then
begin
NextLevel := aRttiProperty.GetValue(aObject).AsObject;
if NextLevel = nil then
exit;
aObject := NextLevel;
aRttiProperty := ctx.GetType(NextLevel.ClassType).GetProperty(aPropertyName);
end;
end;
end;
然后就可以了。
经过一些清理后,这是我的完整帮手:
unit RttiHelperU;
interface
uses
RTTI;
type
RttiHelper = class
strict private
class var ctx: TRttiContext;
public
class function GetProperty(var aObject: TObject; const aPropertyName, aSecondLevel: string): TRttiProperty;
class function GetPropertyValue(aObject: TObject; const aPropertyName, aSecondLevel: string): TValue;
class function SetPropertyValue(aObject: TObject; const aPropertyName, aSecondLevel: string; const aValue: TValue): boolean;
end;
implementation
class function RttiHelper.GetProperty(var aObject: TObject; const aPropertyName, aSecondLevel: string): TRttiProperty;
var
NextLevel: TObject;
begin
Result := ctx.GetType(aObject.ClassType).GetProperty(aPropertyName);
if Result = nil then // Try harder: Look after the property in next level
begin
Result := ctx.GetType(aObject.ClassType).GetProperty(aSecondLevel);
if Result <> nil then
begin
NextLevel := Result.GetValue(aObject).AsObject;
if NextLevel = nil then
exit(nil);
aObject := NextLevel;
Result := ctx.GetType(NextLevel.ClassType).GetProperty(aPropertyName);
end;
end;
end;
class function RttiHelper.GetPropertyValue(aObject: TObject; const aPropertyName, aSecondLevel: string): TValue;
var
RttiProperty: TRttiProperty;
begin
RttiProperty := GetProperty(aObject, aPropertyName, aSecondLevel);
if RttiProperty <> nil then
Result := RttiProperty.GetValue(aObject)
else
Result := nil;
end;
class function RttiHelper.SetPropertyValue(aObject: TObject; const aPropertyName, aSecondLevel: string; const aValue: TValue): boolean;
var
RttiProperty: TRttiProperty;
begin
Result := False;
RttiProperty := GetProperty(aObject, aPropertyName, aSecondLevel);
if RttiProperty = nil then
exit;
try
RttiProperty.SetValue(aObject, aValue);
Result := true;
except
end;
end;
end.
我试图在 VCL 组件上获取和设置一些 属性 值。有些是 DevExpress,有些不是。
我写了一个小帮手class:
type
RttiHelper = class
strict private
public
class function GetPropertyValue(const aObject: TObject; const aPropertyName, aSecondLevel: string): TValue; inline;
class function GetPropertyValue2(const aObject: TObject; const aPropertyName, aSecondLevel: string): TValue; inline;
class procedure GetProperty(const aObject: TObject; const aPropertyName, aSecondLevel: string; var aRttiProperty: TRttiProperty); inline;
end;
{ TRttiHelper }
class procedure RttiHelper.GetProperty(const aObject: TObject; const aPropertyName, aSecondLevel: string; var aRttiProperty: TRttiProperty);
var
NextLevel: TObject;
begin
aRttiProperty := TRttiContext.Create.GetType(aObject.ClassType).GetProperty(aPropertyName);
if aRttiProperty = nil then // Try harder: Look after the property in next level
begin
aRttiProperty := TRttiContext.Create.GetType(aObject.ClassType).GetProperty(aSecondLevel);
if aRttiProperty <> nil then
begin
NextLevel := aRttiProperty.GetValue(aObject).AsObject;
if NextLevel = nil then
exit;
aRttiProperty := TRttiContext.Create.GetType(NextLevel.ClassType).GetProperty(aPropertyName);
end;
end;
end;
class function RttiHelper.GetPropertyValue(const aObject: TObject; const aPropertyName, aSecondLevel: string): TValue;
var
RttiProperty: TRttiProperty;
aInstance, Properties: TObject;
begin
RttiProperty := TRttiContext.Create.GetType(aObject.ClassType).GetProperty(aPropertyName);
aInstance := aObject;
if RttiProperty = nil then // Try harder: Look after the property in next level
begin
RttiProperty := TRttiContext.Create.GetType(aObject.ClassType).GetProperty(aSecondLevel);
if RttiProperty <> nil then
begin
Properties := RttiProperty.GetValue(aObject).AsObject;
aInstance := Properties;
if Properties = nil then
exit(nil);
RttiProperty := TRttiContext.Create.GetType(Properties.ClassType).GetProperty(aPropertyName);
end;
end;
if RttiProperty = nil then // Nothing found
exit(nil);
Result := RttiProperty.GetValue(aInstance);
end;
class function RttiHelper.GetPropertyValue2(const aObject: TObject; const aPropertyName, aSecondLevel: string): TValue;
var
RttiProperty: TRttiProperty;
begin
RttiHelper.GetProperty(aObject, aPropertyName, aSecondLevel, RttiProperty);
if RttiProperty <> nil then
Result := RttiProperty.GetValue(aObject)
else
Result := nil;
end;
最好我想调用 GetProperty
方法然后获取或设置值但是在 DevExpress 组件上我没有得到正确的结果。
重现方法如下:
在窗体上放置一个TEdit
和TcxTextEdit
,然后编写如下代码:
Edit1.Text := RttiHelper.GetPropertyValue2(Edit1, 'Color', 'Style').AsVariant;
cxTextEdit1.Text := RttiHelper.GetPropertyValue2(cxTextEdit1, 'Color', 'Style').AsVariant;
如果我使用这段代码,它会很好地工作:
Edit1.Text := RttiHelper.GetPropertyValue(Edit1, 'Color', 'Style').AsVariant;
cxTextEdit1.Text := RttiHelper.GetPropertyValue(cxTextEdit1, 'Color', 'Style').AsVariant
谁能告诉我我做错了什么?
问题出在这一行:RttiProperty.GetValue(aObject)
我在原始对象上调用了 GetValue,但不确定 属性 是否放在该对象上。
属性 颜色例如是一个很好的例子:在 TEdit 上它被放置在 "Main Object" 上。您可以编写 Edit1.Color := clBlue;
,但在 TcxTextEdit 中,颜色 属性 位于样式对象上,因此您必须编写:cxTextEdit1.Style.Color := clBlue
。因为我需要在正确的对象上调用 RttiProperty.GetValue(aObject)
。
为了做到这一点,我从
中更改了GetProperty
的声明
class procedure GetProperty(const aObject: TObject; const aPropertyName, aSecondLevel: string; var aRttiProperty: TRttiProperty);
收件人:
class procedure GetProperty(var aObject: TObject; const aPropertyName, aSecondLevel: string; var aRttiProperty: TRttiProperty);
实施更改为:
class procedure RttiHelper.GetProperty(var aObject: TObject; const aPropertyName, aSecondLevel: string; var aRttiProperty: TRttiProperty);
var
NextLevel: TObject;
begin
aRttiProperty := ctx.GetType(aObject.ClassType).GetProperty(aPropertyName);
if aRttiProperty = nil then // Try harder: Look after the property in next level
begin
aRttiProperty := ctx.GetType(aObject.ClassType).GetProperty(aSecondLevel);
if aRttiProperty <> nil then
begin
NextLevel := aRttiProperty.GetValue(aObject).AsObject;
if NextLevel = nil then
exit;
aObject := NextLevel;
aRttiProperty := ctx.GetType(NextLevel.ClassType).GetProperty(aPropertyName);
end;
end;
end;
然后就可以了。
经过一些清理后,这是我的完整帮手:
unit RttiHelperU;
interface
uses
RTTI;
type
RttiHelper = class
strict private
class var ctx: TRttiContext;
public
class function GetProperty(var aObject: TObject; const aPropertyName, aSecondLevel: string): TRttiProperty;
class function GetPropertyValue(aObject: TObject; const aPropertyName, aSecondLevel: string): TValue;
class function SetPropertyValue(aObject: TObject; const aPropertyName, aSecondLevel: string; const aValue: TValue): boolean;
end;
implementation
class function RttiHelper.GetProperty(var aObject: TObject; const aPropertyName, aSecondLevel: string): TRttiProperty;
var
NextLevel: TObject;
begin
Result := ctx.GetType(aObject.ClassType).GetProperty(aPropertyName);
if Result = nil then // Try harder: Look after the property in next level
begin
Result := ctx.GetType(aObject.ClassType).GetProperty(aSecondLevel);
if Result <> nil then
begin
NextLevel := Result.GetValue(aObject).AsObject;
if NextLevel = nil then
exit(nil);
aObject := NextLevel;
Result := ctx.GetType(NextLevel.ClassType).GetProperty(aPropertyName);
end;
end;
end;
class function RttiHelper.GetPropertyValue(aObject: TObject; const aPropertyName, aSecondLevel: string): TValue;
var
RttiProperty: TRttiProperty;
begin
RttiProperty := GetProperty(aObject, aPropertyName, aSecondLevel);
if RttiProperty <> nil then
Result := RttiProperty.GetValue(aObject)
else
Result := nil;
end;
class function RttiHelper.SetPropertyValue(aObject: TObject; const aPropertyName, aSecondLevel: string; const aValue: TValue): boolean;
var
RttiProperty: TRttiProperty;
begin
Result := False;
RttiProperty := GetProperty(aObject, aPropertyName, aSecondLevel);
if RttiProperty = nil then
exit;
try
RttiProperty.SetValue(aObject, aValue);
Result := true;
except
end;
end;
end.