2011-10-04 63 views
3

如果給出以下代碼片段,則使用GetPropValue(MyComponent,'MySubComponent.Prop1')會引發EPropertyError異常。 如何使用GetPropValue/SetPropValue檢索或設置SubProperties的值?獲取/設置子屬性使用RTTI

Type 
    TMySubComponent = class(TInterfacedPersitent) 
    private 
    FProp1: Integer; 
    published 
    property Prop1: integer read FProp1 write FProp1; 
    end; 

    TMyComponent = class(TCompoent) 
    private 
    FMySubComponent : TMySubcomponent; 
    published 
    property MySubComponent: TMySubComponent read FMySubComponent write FMySubComponent ; 
    end; 
+0

您正在使用哪個版本的delphi? – RRUZ

+0

@ RRUZ Delphi XE – iamjoosy

+0

是您的TMySubComponent類中的屬性IsSubComponent設置爲True嗎? – az01

回答

4

您在問題中使用的點符號不受支持。

您需要獲取SubComponent的Value,然後在各個屬性上執行Set和Get。

var 
    C: TRttiContext; 
    MyComp : TMyComponent; 
    MyCompType : TRttiInstanceType; 
    MySubCompType : TRttiInstanceType; 
    MySubComponentValue : TValue; 
begin 
    MyComp := TMyComponent.create(Self); 
    ... 
    // RTTI.Pas Method 
    MyCompType := c.GetType(TMyComponent.ClassInfo) as TRttiInstanceType; 
    MySubCompType := c.GetType(TMySubComponent.ClassInfo) as TRttiInstanceType; 
    MySubComponentValue := MyCompType.GetProperty('MySubComponent').GetValue(MyComp); 

    if Not MySubComponentValue.IsEmpty then 
    begin 
     MySubCompType.GetProperty('Prop1').SetValue(MySubComponentValue.AsObject,43); 
    end; 

//TypInfo.pas Method 
SubComp := GetObjectProp(MyComp,'MySubComponent'); 
if Assigned(SubComp) then 
begin 
    SetPropValue(SubComp,'Prop1',5); 
    prop1Value := GetPropValue(SubComp,'Prop1'); 
end; 

end; 

TypInfo.pas方法只適用於發佈的屬性,您可以使用RTTI.pas方法獲取公共屬性。

+0

感謝您的編輯。在我的情況下,所有的屬性都發布了。 – iamjoosy

6

正如Robert所說不支持點符號,但您可以輕鬆創建一個函數來設置或使用RTTI獲取子屬性值。檢查此示例

{$APPTYPE CONSOLE} 

uses 
    Rtti, 
    Classes, 
    SysUtils; 


Type 
    TMySubComponent = class(TInterfacedPersistent) 
    private 
    FProp1: Integer; 
    published 
    property Prop1: integer read FProp1 write FProp1; 
    end; 

    TMyComponent = class(TComponent) 
    private 
    FMySubComponent : TMySubcomponent; 
    published 
    property MySubComponent: TMySubComponent read FMySubComponent write FMySubComponent ; 
    end; 



procedure SetObjValueEx(const ObjPath:string;AInstance:TObject;AValue:TValue); 
Var 
c   : TRttiContext; 
Prop   : string; 
SubProp  : string; 
pm   : TRttiProperty; 
p   : TRttiProperty; 
Obj   : TObject; 
begin 
Prop:=Copy(ObjPath,1,Pos('.',ObjPath)-1); 
SubProp:=Copy(ObjPath,Pos('.',ObjPath)+1); 
c := TRttiContext.Create; 
try 
    for pm in c.GetType(AInstance.ClassInfo).GetProperties do 
    if CompareText(Prop,pm.Name)=0 then 
    begin 
    p := c.GetType(pm.PropertyType.Handle).GetProperty(SubProp); 
     if Assigned(p) then 
     begin 
     Obj:=pm.GetValue(AInstance).AsObject; 
     if Assigned(Obj) then 
      p.SetValue(Obj,AValue); 
     end; 
     break; 
    end; 
finally 
    c.Free; 
end; 
end; 


function GetObjValueEx(const ObjPath:string;AInstance:TObject):TValue; 
Var 
c   : TRttiContext; 
Prop   : string; 
SubProp  : string; 
pm   : TRttiProperty; 
p   : TRttiProperty; 
Obj   : TObject; 
begin 
Prop:=Copy(ObjPath,1,Pos('.',ObjPath)-1); 
SubProp:=Copy(ObjPath,Pos('.',ObjPath)+1); 
c := TRttiContext.Create; 
try 
    for pm in c.GetType(AInstance.ClassInfo).GetProperties do 
    if CompareText(Prop,pm.Name)=0 then 
    begin 
    p := c.GetType(pm.PropertyType.Handle).GetProperty(SubProp); 
     if Assigned(p) then 
     begin 
     Obj:=pm.GetValue(AInstance).AsObject; 
     if Assigned(Obj) then 
      Result:=p.GetValue(Obj); 
     end; 
     break; 
    end; 
finally 
    c.Free; 
end; 
end; 

Var 
    MyComp : TMyComponent; 
begin 
    try 
    MyComp:=TMyComponent.Create(nil); 
    try 
     MyComp.MySubComponent:=TMySubComponent.Create; 
     //Set the value of the property 
     SetObjValueEx('MySubComponent.Prop1',MyComp,777); 
     //Get the value of the property 
     Writeln(Format('The value of MySubComponent.Prop1 is %d',[GetObjValueEx('MySubComponent.Prop1',MyComp).AsInteger])); 
    finally 
     MyComp.Free; 
    end; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    Readln; 
end. 
+0

代碼是沉默的SubComponent是零。 –

+0

@RRUZ,感謝這個優雅的解決方案。 – iamjoosy

+0

@RobertLove你是什麼意思? 'if Assigned(Obj)then'行檢查子組件。 – RRUZ