RTTI和DevExpress

时间:2015-02-26 10:08:32

标签: devexpress delphi-xe rtti

我正在尝试获取并在VCL组件上设置一些属性值。有些是DevExpress,有些则不是。

我有一个小帮手类:

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 Components上我得不到正确的结果。

以下是如何重现:

在表单上放置TEditTcxTextEdit,然后编写以下代码:

  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

谁能告诉我我做错了什么?

1 个答案:

答案 0 :(得分:0)

问题在于这一行:RttiProperty.GetValue(aObject)我在原始对象上调用GetValue,但不一定是属性放在该对象上。

属性Color就是一个很好的例子:在TEdit上它被放置在“主要对象”上。您可以编写Edit1.Color := clBlue;但是在TcxTextEdit中,Color属性被放置在样式对象上,因此您必须编写: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;

然后它有效。

经过一些清理后,这是我的complpete帮手:

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.