2010-03-10 6 views
3

J'essaie d'utiliser RTTI pour ajouter un gestionnaire d'événements à un contrôle, qui peut déjà avoir un gestionnaire d'événements. Le code ressemble à ceci:Quelqu'un sait comment utiliser TValue.AsType <TNotifyEvent> correctement?

var 
    prop: TRttiProperty; 
    val: TValue; 
begin 
    prop := FContext.GetType(MyControl.ClassInfo).GetProperty('OnChange'); 
    val := prop.GetValue(MyControl); 
    FOldOnChange := val.AsType<TNotifyEvent>; 
    prop.SetValue(MyControl, TValue.From<TNotifyEvent>(self.MyOnChange)); 
end; 

Je veux que ce que je puisse le faire en MyOnChange:

begin 
    if assigned(FOldOnChange) then 
    FOldOnChange(Sender); 
    //additional code here 
end; 

Malheureusement, le compilateur ne semble pas que la ligne FOldOnChange := val.AsType<TNotifyEvent>;. Il dit

E2010 types incompatibles: « procédure, pointeur typées ou paramètre non typé » et « TNotifyEvent »

Quelqu'un sait pourquoi ou comment réparer? Il me semble juste ...

+0

méthode par rapport à résultat de la méthode dans le contexte des grèves pointeur de la méthode à nouveau ... –

Répondre

6

FOldOnChange est d'un type de pointeur de méthode, alors que AsType<TNotifyEvent> est une méthode. Le compilateur pense que vous essayez d'assigner la méthode au pointeur de la méthode. La solution consiste à ajouter () à l'appel de méthode pour le forcer et à utiliser la valeur de retour de la méthode comme valeur à affecter à FOldOnChange.

Voici un exemple complet:

uses SysUtils, Rtti; 

type 
    TEv = procedure(Sender: TObject) of object; 

    TObj = class 
    private 
    FEv: TEv; 
    public 
    property Ev: TEv read FEv write FEv; 
    class procedure Meth(Sender: TObject); 
    end; 

class procedure TObj.Meth(Sender: TObject); 
begin 
end; 

procedure P; 
var 
    ctx: TRttiContext; 
    t: TRttiType; 
    p: TRttiProperty; 
    v: TValue; 
    o: TObj; 
    e: TEv; 
begin 
    t := ctx.GetType(TObj); 
    p := t.GetProperty('Ev'); 
    o := TObj.Create; 
    try 
    // Set value explicitly 
    o.Ev := TObj.Meth; 
    // Get value via RTTI 
    v := p.GetValue(o); 
    //e := v.AsType<TEv>; // doesn't work 
    e := v.AsType<TEv>(); // works 
    finally 
    o.Free; 
    end; 
end; 

begin 
    try 
    P; 
    except 
    on e: Exception do 
     Writeln(e.Message); 
    end; 
end. 
+0

Aha! OK, ça a du sens. Merci! –

1

Le nouveau RTTI présenté en 2010 est fondamentalement juste un wrapper avancé autour de l'ancien TypInfo RTTI (pour l'instant). Dans TypInfo, les gestionnaires d'événements sont représentés par l'enregistrement TMethod. Essayez cette (non testé):

var 
    prop: TRttiProperty; 
    val: TValue; 
    evt: TNotifyEvent; 
begin 
    prop := FContext.GetType(MyControl.ClassInfo).GetProperty('OnChange'); 
    val := prop.GetValue(MyControl); 
    TMethod(FOldOnChange) := val.AsType<TMethod>; 
    evt := Self.MyOnChange; 
    prop.SetValue(MyControl, TValue.From<TMethod>(TMethod(evt)); 
end; 
+0

Aussi, jetez un oeil à cette question: http://stackoverflow.com/questions/2116013/howto-set-event-handlers-with-arbitraire-type-avec-rtti-in-delphi-2010 –

+0

J'ai vu cette question. ;) Mais cela n'aide pas avec ce problème, malheureusement. –

+2

"essentiellement juste un wrapper avancé autour de l'ancienne RTTI TypInfo" C'est un peu exagéré. Il y avait des changements significatifs au compilateur pour générer beaucoup plus d'informations pour ces "wrappers avancés" à opérer. Oui, les nouvelles données sont une extension de la RTTI existante, mais il s'agit d'une extension plutôt significative. –