2012-06-04 22 views
6

FMX TStyledControl'den miras alan sınıf yazmaya çalışıyorum. Stil güncellendiğinde, stil kaynak nesnelerini önbelleğe yükler.FireMonkey stil kaynaklarını RTTI ile yükleme

Özel denetimler içeren paket için proje grubu oluşturdum ve Delphi yardımında açıklandığı gibi FMX HD projesini test ediyorum. Paketi yükledikten ve test formuna TsgSlideHost yerleştirdikten sonra test uygulamasını çalıştırıyorum. İyi çalışıyor, ancak kapatıp RAD Studio paketini yeniden yüklemeyi denediğimde “rtl160.bpl'de hata” veya “geçersiz işaretçi işlemi” yazıyor.

TsgStyledControl tarafından LoadToCacheIfNeeded yordamında ne gibi bir sorun var gibi görünüyor, ama nedenini anlamıyorum. FMX stilleri veya herhangi bir şey ile RTTI kullanımı konusunda herhangi bir kısıtlama var mı?

TsgStyledControl kaynaklar: TsgStyledControl kullanılması

unit SlideGUI.TsgStyledControl; 

interface 

uses 
    System.SysUtils, System.Classes, System.Types, FMX.Types, FMX.Layouts, FMX.Objects, 
    FMX.Effects, System.UITypes, FMX.Ani, System.Rtti, System.TypInfo; 

type 
    TCachedAttribute = class(TCustomAttribute) 
    private 
    fStyleName: string; 
    public 
    constructor Create(const aStyleName: string); 
    property StyleName: string read fStyleName; 
    end; 

    TsgStyledControl = class(TStyledControl) 
    private 
    procedure CacheStyleObjects; 
    procedure LoadToCacheIfNeeded(aField: TRttiField); 
    protected 
    function FindStyleResourceAs<T: class>(const AStyleLookup: string): T; 
    function GetStyleName: string; virtual; abstract; 
    function GetStyleObject: TControl; override; 
    public 
    procedure ApplyStyle; override; 
    published 
    { Published declarations } 
    end; 

implementation 

{ TsgStyledControl } 

procedure TsgStyledControl.ApplyStyle; 
begin 
    inherited; 
    CacheStyleObjects; 
end; 

procedure TsgStyledControl.CacheStyleObjects; 
var 
    ctx: TRttiContext; 
    typ: TRttiType; 
    fld: TRttiField; 
begin 
    ctx := TRttiContext.Create; 
    try 
    typ := ctx.GetType(Self.ClassType); 
    for fld in typ.GetFields do 
     LoadFromCacheIfNeeded(fld); 
    finally 
    ctx.Free 
    end; 
end; 

function TsgStyledControl.FindStyleResourceAs<T>(const AStyleLookup: string): T; 
var 
    fmxObj: TFmxObject; 
begin 
    fmxObj := FindStyleResource(AStyleLookup); 
    if Assigned(fmxObj) and (fmxObj is T) then 
    Result := fmxObj as T 
    else 
    Result := nil; 
end; 

function TsgStyledControl.GetStyleObject: TControl; 
var 
    S: TResourceStream; 
begin 
    if (FStyleLookup = '') then 
    begin 
    if FindRCData(HInstance, GetStyleName) then 
    begin 
     S := TResourceStream.Create(HInstance, GetStyleName, RT_RCDATA); 
     try 
     Result := TControl(CreateObjectFromStream(nil, S)); 
     Exit; 
     finally 
     S.Free; 
     end; 
    end; 
    end; 
    Result := inherited GetStyleObject; 
end; 

procedure TsgStyledControl.LoadToCacheIfNeeded(aField: TRttiField); 
var 
    attr: TCustomAttribute; 
    styleName: string; 
    styleObj: TFmxObject; 
    val: TValue; 
begin 
    for attr in aField.GetAttributes do 
    begin 
    if attr is TCachedAttribute then 
    begin 
     styleName := TCachedAttribute(attr).StyleName; 
     if styleName <> '' then 
     begin 
     styleObj := FindStyleResource(styleName); 
     val := TValue.From<TFmxObject>(styleObj); 
     aField.SetValue(Self, val); 
     end; 
    end; 
    end; 
end; 

{ TCachedAttribute } 

constructor TCachedAttribute.Create(const aStyleName: string); 
begin 
    fStyleName := aStyleName; 
end; 

end. 

:

type 
    TsgSlideHost = class(TsgStyledControl) 
    private 
    [TCached('SlideHost')] 
    fSlideHost: TLayout; 
    [TCached('SideMenu')] 
    fSideMenuLyt: TLayout; 
    [TCached('SlideContainer')] 
    fSlideContainer: TLayout; 
    fSideMenu: IsgSideMenu; 
    procedure ReapplyProps; 
    procedure SetSideMenu(const Value: IsgSideMenu); 
    protected 
    function GetStyleName: string; override; 
    function GetStyleObject: TControl; override; 
    procedure UpdateSideMenuLyt; 
    public 
    constructor Create(AOwner: TComponent); override; 
    procedure ApplyStyle; override; 
    published 
    property SideMenu: IsgSideMenu read fSideMenu write SetSideMenu; 
    end; 
+0

Sorun, StyleObj öğesinin Val'a atanmadan önce atandığını doğrulayamamanız olabilir mi? Bu değilse, tasarım zamanı yerine çalışma zamanında test etmenizi öneririm. Böylece hata ayıklayıcıyı kullanabilir veya tasarım zamanında hataları yakalayan bir araç edinebilirsiniz. –

+1

StyleObj öğesinin sıfır olması durumunda, önbellek alanı da sıfırlanır. TsgSlideHost bunu kontrol ediyor. Bunu çalışma zamanında ayıklamaya çalıştım ve iyi çalışıyor. CodeSite logger, 3 alanın ne yüklendiğini ve StyleObj türünün doğru özelliklere sahip TLayout olduğunu söylüyor. AQTime profiler ayrıca herhangi bir bellek sızıntısı algılamaz. – HeMet

cevap

0

TRttiField.GetAttributes Kullanarak tasarım zamanlı olarak hatalara yol açar. Delphi XE2'de bir hata. Bakınız QC Report.

İlgili konular