Results 1 to 10 of 10

Thread: Events

  1. #1

    Events

    Misschien een simpele vraag, maar ik kon het nergens terug vinden.

    Hoe maak ik een event bij een object, zodat ik deze met Include en Exclude kan gebruiken. In de vorige versies van Delphi ging dat bijvoorbeeld zo:
    Code:
    type
      TMyEvent = procedure(Sender: TObject) of object
      
      TMyObject = class
      private
        FOnEvent: TMyEvent;
      public
        property OnEvent: TMyEvent read FOnEvent write FOnEvent;
      end;
    Maar hoe doe ik dit nu in Delphi 8?

  2. #2
    Niet goed genoeg gezocht, antwoord zelf gevonden hier, voorbeeld:
    Code:
    1: program multievent; 
    2: 
    3: {$APPTYPE CONSOLE} 
    4: 
    5: uses 
    6: SysUtils; 
    7: 
    8: type 
    9: TMyEvent = procedure (Sender: TObject; Msg: string) of object; 
    10: 
    11: TClassWithEvent = class 
    12: private 
    13: FAnEvent: TMyEvent; 
    14: public 
    15: procedure FireEvent; 
    16: property AnEvent: TMyEvent add FAnEvent remove FAnEvent; 
    17: end; 
    18: 
    19: TListener = class 
    20: procedure EventHandler(Sender: TObject; Msg: string);
    21: end; 
    22: 
    23: { TClassWithEvent } 
    24: 
    25: procedure TClassWithEvent.FireEvent; 
    26: begin 
    27: if Assigned(FAnEvent) then 
    28: FAnEvent(Self, '*multicast event*'); 
    29: end; 
    30: 
    31: { TListener } 
    32: 
    33: procedure TListener.EventHandler(Sender: TObject; Msg: string); 
    34: begin 
    35: WriteLn('Event was fired. Message is: ', Msg); 
    36: end; 
    37: 
    38: var 
    39: L1, L2: TListener; 
    40: CWE: TClassWithEvent; 
    41: begin 
    42: L1 := TListener.Create; // create objects 
    43: L2 := TListener.Create; 
    44: CWE := TClassWithEvent.Create; 
    45: Include(CWE.AnEvent, L1.EventHandler); // assign event handler 
    46: Include(CWE.AnEvent, L2.EventHandler); // assign event handler 
    47: CWE.FireEvent; // cause event to fire 
    48: Exclude(CWE.AnEvent, L1.EventHandler); // disconnect event handler 
    49: Exclude(CWE.AnEvent, L2.EventHandler); // disconnect event handler 
    50: ReadLn; 
    51: end
    Quote van boven genomede website.

  3. #3
    Heb toch nog een probleem:

    Ik heb de volgende interface:
    Code:
      ICustomer = interface
        procedure SetName(const Value: String);
        function GetName: String;
        procedure SetAddress(const Value: String);
        function GetAddress: String;
        function Compare(Customer: ICustomer): Integer;
      end;
    Met de volgende klasse:
    Code:
      TCustomer = class(TInterfacedObject, ICustomer)
      private
        FName: &String;
        FAddress: &String;
        FObservers: ArrayList;
        FCustomerChanged: TCustomerChangedEvent;
        procedure DoCustomerChangedEvent;
      public
        constructor Create;
    
        procedure SetName(const Value: String);
        function GetName: String;
        procedure SetAddress(const Value: String);
        function GetAddress: String;
        function Compare(Customer: ICustomer): Integer;
    
        property CustomerChanged: TCustomerChangedEvent read FCustomerChanged
          write FCustomerChanged;
      end;
    Nu wil ik mbv Include een event-handler aan het event CustomerChanged toevoegen. Maar omdat ik gebruik maak van de interface kent deze de property CustomerChanged niet. Ik kan de property wel toevoegen aan de interface, maar deze moet dan weer een Set-ter en een Get-ter hebben. En daarop mag ik weer niet Include/Exculde gebruiken, wat wel verplicht is.

    Iemand enig idee hoe ik dit oplos?

  4. #4
    Ik denk niet dat je interfaces en events door elkaar moet gaan gebruiken. Een interface gebruik je om een object aan te spreken zonder dat je enig idee hebt wat voor object het is ("wat kun je" in plaats van "wie ben je"). Bij een event lijkt me dat je precies weet welk object je het over hebt.

    Maar goed, het is zeker mogelijk natuurlijk. Maar dan zou ik het wel meer op een Interface manier oplossen, dus bijvoorbeeld een method ConnectMe(AObject: TObject) die het meegegeven object als listener toevoegd aan het event.
    Marcel

  5. #5
    Maar ik gebruik overal binnen mijn systeem de interface (dus ICustomer). Dus hoe kan in er dan voor zorgen dat het dan gaat werken? Is dit te realiseren met een setter en een getter?

  6. #6
    SillyMember
    Join Date
    May 2003
    Location
    Gent
    Posts
    7,725
    In tegenstelling tot Marcel zie ik persoonlijk geen redenen om Events (geïmplementeerd met Delegates) en Interfaces niet door elkaar te gebruiken. Bij een interface heb je inderdaad geen weet van de implementor (het object), daarvoor dienen interfaces tenslotte. Dat de ontvanger van een event zou moeten weten wie de implementor is, daar ben ik het dan weer niet mee eens: het is eigenlijk voldoende dat de interface gekend is. De oplossing die Marcel aandraagt (Observer Design Pattern, eigenlijk) is altijd mogelijk maar Delegation via Events (het Event Pattern bij wijze van spreken) heeft een aantal voordelen. En één van de voordelen is dat de zetter van de delegate zelf geen implementor moet zijn van een door de klasse met event gekende interface. (Zie ook Exploring the Observer Pattern )

    Het echte probleem ligt 'm in de combinatie van een aantal keuzes die ze bij Borland gemaakt hebben om
    1) Delegates te implementeren als een soort Procedural types, en met ongeveer dezelfde syntax: op zich misschien niet zo onlogisch, maar het zijn klassen dus moet je er ook voor zorgen dat je ze op die manier kan benaderen. De nodige code wordt door de compiler gegenereerd op de achtergrond. Hier zijn trouwens nog andere problemen mee: op MultiCastDelegates kan je normaal BeginInvoke en EndInvoke oproepen (Asynchroon), de nodige code (methods) wordt wel gegenereerd, maar je kan er niet aan zonder reflection te gebruiken.
    2) de min-of-meer Delphi Win32 compatibele vorm van syntax voor properties in Delphi for .NET die vereist dat je de getter en/of setter opgeeft (of Fields, maar dat kan dan weer niet in interfaces, natuurlijk)
    3) De min-of-meer Delphi Win32 compatibele vorm van syntax voor Interfaces (en de noodzaak om ook voor properties in Interfaces de getter/setter te declareren).
    4) De speciale property (syntax) vereist voor een MultiCastDelegate: add en remove op een Field!, nodig voor de Include en Exclude methods. Op de achtergrond wordt aan de klasse met deze Event op de achtergrond twee methods toegevoegd: add_MijnEventProperty en remove_MijnEventPropery (zie ook verder)
    1 + 2 + 3 + 4 samen zorgen voor syntactische problemen wat betreft de intentie van de TS.

    Dus, wat eigenlijk zo zou moeten kunnen (hier VB.NET), kan voor zover ik weet niet in Delphi 8, om louter syntactische redenen!
    Code:
    Public Delegate Sub MijnDelegate(ByVal Sender As Object, ByVal e As EventArgs)
    
    Public Interface IMijnInterface
        Event Boodschap As MijnDelegate
        Sub Send()
    End Interface
    
    Public Class MijnKlasse
        Implements IMijnInterface
        // Event mag protected, is dan enkel via interface beschikbaar
        // maar voor deze test: public
        Public Event Boodschap As MijnDelegate Implements IMijnInterface.Boodschap
        Sub Send() Implements IMijnInterface.Send
            RaiseEvent Boodschap(Me, System.EventArgs.Empty)
        End Sub
    End Class
    
    // En dan b.v.:
    Private Sub Ontvang(ByVal Sender As Object, ByVal e As System.EventArgs)
      ListBox1.Items.Add(Sender.GetType.ToString)
    End Sub
    
    Private Sub Ontvang2(ByVal Sender As Object, ByVal e As System.EventArgs)
      ListBox2.Items.Add(Sender.GetType.ToString)
    End Sub
    
    Private Sub Test()
      // met klasse, multicast
      Dim obj As New MijnKlasse
      AddHandler obj.Boodschap, AddressOf Ontvang
      AddHandler obj.Boodschap, AddressOf Ontvang2
      
      // met interface, multicast
      Dim objI As IMijnInterface = New MijnKlasse
      AddHandler objI.Boodschap, AddressOf Ontvang
      AddHandler objI.Boodschap, AddressOf Ontvang2
    
      obj.Send()
      objI.Send()
    End Sub
    In Delphi 8 ben ik nooit verder gekomen dan volgende code.
    Noteer alvast het verschil tussen de read/write syntax en de add/remove syntax voor event properties. In het eerste laatste geval is het multicast, in het eerste geval niet (zoals events in Delphi Win32).

    Code:
      MyEvent = procedure(Sender: System.Object; e: System.EventArgs);
    
      IMyInterface = Interface
        procedure add_MyEvent(AnEvent: MyEvent);
        procedure remove_MyEvent(AnEvent: MyEvent);
        procedure Fire;
      end;
    
      MyClass = class(System.Object, IMyInterface )
      strict private
        FMyEvent: MyEvent;
      public
        // IMyInterface
        // Noteer dat add_MyEvent en remove_MyEvent
        // door de Multicast Event property MyEvent op de achtergrond
        // worden gegenereerd
        procedure Fire;
        property MyEvent:MyEvent add FMyEvent remove FMyEvent;
      end;
    
    //...
    procedure TWinForm.Test;
    var
      AMyClass: MyClass;
      AMyInterface: IMyInterface;
    begin
      AMyClass := MyClass.Create;
      Include(AMyClass.MyEvent, Ontvang);
      Include(AMyClass.MyEvent, Ontvang2);
      AMyInterface := MyClass.Create;
      AMyInterface.add_MyEvent(Ontvang);
      AMyInterface.add_MyEvent(Ontvang2);
      AMyClass.Fire;
      AMyInterface.Fire;
    end;
    
    procedure TWinForm.Ontvang(Sender: TObject; e: System.EventArgs);
    begin
      ListBox1.Items.Add(Sender.ClassType.ClassName)
    end;
    
    procedure TWinForm.Ontvang2(Sender: TObject; e: System.EventArgs);
    begin
      ListBox2.Items.Add(Sender.ClassType.ClassName)
    end;
    
    // MyClass
    procedure MyClass.Fire;
    begin
      if Assigned(FMyEvent) then  FMyEvent(Self,nil);
    end;
    All methodologies are based on fear. -- Kent Beck.

  7. #7
    Heel erg bedankt. Het lijkt goed te werken.
    Ben jij zelf tevreden met deze oplossing? Of is het een soort van houtje-touwtje oplossing?

  8. #8
    SillyMember
    Join Date
    May 2003
    Location
    Gent
    Posts
    7,725
    Neen, ik ben er niet echt tevreden mee
    Ik wil iets als de VB.NET interface (hé, nooit gedacht dat ik dat ooit zou zeggen).
    Noteer dat als je geen Multicast event wil (dus zoals een traditionele Delphi Win32 event), dan kan het zo:
    Code:
      IDelphi = interface
        procedure RaiseEvent;
        // property DelphiEvent
        procedure set_DelphiEvent(const Value: MyEvent);
        function get_DelphiEvent: MyEvent;
        property DelphiEvent: MyEvent read get_DelphiEvent write set_DelphiEvent;
      end;
    
      TDelphi = class(System.Object, IDelphi)
      strict private
        FDelphiEvent: MyEvent;
      protected
        // IDelphi
        procedure set_DelphiEvent(const Value: MyEvent);
        function get_DelphiEvent: MyEvent;
        procedure RaiseEvent;
      public
      end;
    Met in de implementatie dan een gewone getter en setter en dan:
    Code:
    procedure MainForm.Test;
    var
      ADelphi: IDelphi;
    begin
      ADelphi := TDelphi.Create;
      ADelphi.DelphiEvent := Ontvang;
      ADelphi.DelphiEvent := Ontvang2;
      // Enkel Ontvang2 wordt opgeroepen
      ADelphi.RaiseEvent;
    end;
    All methodologies are based on fear. -- Kent Beck.

  9. #9
    al gevonden
    Last edited by Vortex; 26-Jul-04 at 19:51.

  10. #10
    SillyMember
    Join Date
    May 2003
    Location
    Gent
    Posts
    7,725
    Originally posted by Vortex
    al gevonden
    Goed nieuws!
    Nu nog wat en waar?
    All methodologies are based on fear. -- Kent Beck.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. Toevoegen events / properties aan Form
    By nico.callewaert in forum Algemeen
    Replies: 6
    Last Post: 10-May-07, 15:02
  2. Events versus sendmessage
    By cpri in forum Algemeen
    Replies: 8
    Last Post: 30-Jan-04, 12:46
  3. Replies: 9
    Last Post: 01-Nov-03, 17:19
  4. Meerdere (sub) classes en events
    By Vos in forum Algemeen
    Replies: 12
    Last Post: 24-Feb-03, 23:36
  5. Events ?
    By Richard in forum Algemeen
    Replies: 3
    Last Post: 02-Dec-01, 16:02

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •