Autor Beitrag
BadDog
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Do 05.08.04 09:49 
Hallo allerseits.

Es geht darum, einen Eventhandler über die Reflection-API des .NET Frameworks hinzuzufügen. Ich kann ja für ein Beliebiges Objekt sagen:
ausblenden Delphi-Quelltext
1:
meinObjekt.getType.getEvent('EventName').AddEventHandler(meinObjekt, meinDelegate)					

Das Problem besteht darin den Delegate zu erzeugen.
Normalerweise bietet Delphi .NET ja garnicht die Möglichkeit Delegates zu erzeugen sondern man sagt einfach Include(irgendEinObjekt.OnIrgendwas, @MeineEventProzedur)
Was er dann genau macht weiß ich nicht, würde mich aber mal interessieren.

Ich kann indirekt einen Delegate erzeugen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  Var 
    TestDelegate : Delegate;

begin
  TestDelegate := @MeineEventProzedur;
end;

Erzeugt einen Delegate einer Klasse namens $Unnamed1 (Oder ähnlich),
die direkt vom MulticastDelegate abgeleitet ist.
Diesen Delegate kann ich natürlich nicht für beispielsweise ein TreeViewEvent benutzen,
da hier ein TreeViewEventHandler erwartet wird.

Mein zweiter Ansatz war folgender:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
  Var
    TestDelegate : Delegate;

begin

  TestDelegate := Delegate.CreateDelegate(irgendeinObjekt.getType.GetEvent ('OnIrgendwas').EventHandlerType, meinObjekt 'MeineEventProzedur');

end;

Hier sagt er leider immer "Konnte nicht zur Zielmethode gebunden werden",
egal ob MeineEventProzedur private, public, published ist, oder
gar nicht existiert.
Er scheint sie einfach nicht zu finden, obwohl sie durchaus über Reflection sichtbar ist.
Die Frage die ich mir stelle: Ist es überhaupt möglich in Delphi .NET einen EventHandler per Reflection hinzuzufügen?
Muss ich vielleicht bei der Methodendeklaration von MeineEventProzedur noch irgendwas beachten?

Ich hoffe das war verständlich und Irgendjemand weiß mehr.

Danke
Fab

Moderiert von user profile iconChristian S.: Code- durch Delphi-Tags ersetzt
DerSascha
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Do 09.09.04 15:42 
Ich habe, wenn ich Deine Ausführung richtig verstehe, das gleiche Problem. Ich meine einen möglichen Lösungsansatz in dem Beispiel von Rick Ross aus Delphi for .NET ausgemacht zu haben. Nur verstehen tu ich's noch nicht :-).

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
program AsyncDelegate;
{$APPTYPE CONSOLE}
//
// This example demonstrates how to call a delegate asynchronously using
// BeginInvoke() and EndInvoke()
//
uses
  System.Reflection,
  System.Threading;

type
  TMyDelegate = procedure of object;

  TMyClass = class
  private 
    FOnDoSomething : TMyDelegate;
  public
    procedure CallDelegate;
    property  OnDoSomething : TMyDelegate read FOnDoSomething write FOnDoSomething;
  end;

  TAnotherClass = class
  public
    procedure DoFoo;
  end;

procedure TMyClass.CallDelegate;
var
  obj : System.Object;
  t : System.Type;
  m : MethodInfo;
  parms : array [0..1of System.Object;
begin
  writeln('CallDelegate');
  if Assigned(FOnDoSomething) then
  begin
    // Normally this would be @FOnDoSomething.BeginInvoke(nil, nil);
    // but the compiler doesn't support BeginInvoke, since
    // it thinks it's just a pointer to a method.
    //
    // the work around uses reflection to invoke the method
    // first cast the "method pointer" to an object
    obj := System.Object(@FOnDoSomething);
    t := obj.GetType;
    m := t.GetMethod('BeginInvoke');
    parms[0] := nil;
    parms[1] := nil;
    m.Invoke(obj, parms);
  end;
end;


procedure TAnotherClass.DoFoo;
begin
  writeln(AppDomain.GetCurrentThreadID,' DoFoo');
end;

var
  c : TMyClass;
  ac : TAnotherClass;
begin
  c := TMyClass.Create;
  ac := TAnotherClass.Create;
  writeln(AppDomain.GetCurrentThreadID,' assigning the delegate');
  c.OnDoSomething := @ac.DoFoo;
  writeln(AppDomain.GetCurrentThreadID,' calling the delegate');
  c.CallDelegate;
  // give the delegate some time to call it...
  Thread.Sleep(2000);
  writeln(AppDomain.GetCurrentThreadID,' Done');
end.


Möglicherweise ist da die Lösung des Problems enthalten. Ich, für meinen Teil, werde da noch nicht ganz schlau raus. Du kannst das sicher besser und kannst mir danach in einfachen Worten erklären, wie man das nun zu benutzen hat ;-).

Gruß.

Moderiert von user profile iconChristian S.: Code- durch Delphi-Tags ersetzt.