| hoofdstuk |
23. 24. 25.  |
| onderwerp |
24.1. 24.2. Events 24.3.  |
| rubrieken | 




|
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
Een applicatie kan je bekijken als een reeks van routines die na elkaar worden aangeroepen. Tot nu toe hebben we steeds een applicatie vorm gegeven door in de code ( al dan niet gebaseerd op invoer van de gebruiker ) te bepalen welke routine na welke andere procedure wordt uitgevoerd.
In de realiteit is dit vaak anders, het valt vaak voor dat applicatie ( of althans grote delen daarvan ) "eventdriven" zijn. Waarmee bedoeld wordt dat het optreden van die gebeurtenissen eigenlijk het programmaverloop gaan bepalen.
Events zijn gebeurtenissen die kunnen optreden in een applicatie.
Een aantal voorbeelden van dergelijke events die kunnen optreden : form_load ( bij het laden van het venster ), button_click ( bij het klikken op een knop ), textbox_changed ( bij het wijzigen van de inhoud van een tekstvak ), ... Dit zijn allemaal voorbeelden van events die optreden bij het gebruiken van de grafische user interface ( GUI ) van een applicatie.
Maar ook andere soorten van events zijn nuttig en bruikbaar, bijvoorbeeld : "berekening uitgevoerd", "data uit database ingeladen", ...
We kunnen onze eigen klassen ook "eventsources" ( "eventsenders" ) maken. We doen dit om clients van deze klasse op basis van het optreden van dergelijke gebeurtenis/event een bepaalde actie te laten uitvoeren. Deze actie kunnen we definiëren via een "eventhandler", die gekoppeld wordt aan een event van een eventsource. 24.2.1. Event DefinitieEen event voegen we toe aan een eventsource op volgende wijze : <accessmodifier> Event <identifier>(<argumentslist>) <type-specifier>
Deze eventsource zal de event doen optreden via een RaiseEvent statement : RaiseEvent <identifier>(<argumentslist>) Visual Basic 2010 Broncode Option Strict OnOption Explicit OnNamespace Example1 Class SomeEventSource Delegate Sub SomeDelegate() Public Event SomeEvent As SomeDelegate Public Sub RaiseSomeEvent() RaiseEvent SomeEvent() End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
boven
24.2.2. Koppeling at Compiletime - WithEvents Veld en Handles ClausuleEen client kan bij het gebruik van een eventsource het optreden van de event ( moment van RaiseEvent ) koppelen aan een bepaalde actie ( eventhandler, of ook "eventtarget" genoemd ). Deze ( statische ) koppeling kan at compiletime gebeuren door de eventsource als WithEvents veld te declareren, en de eventhandler te voorzien van een Handles clausule die verwijst naar de event van de eventsource die wordt afgehandeld. Visual Basic 2010 Broncode Namespace Example1 Class Client Private Shared WithEvents m_SomeEventSource As New SomeEventSource Public Shared Sub Main() m_SomeEventSource.RaiseSomeEvent() Console.ReadLine() End Sub Private Shared Sub someEventHandler() _ Handles m_SomeEventSource.SomeEvent Console.WriteLine( "someEventHandler") End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output someEventHandler Een eventhandler is steeds een procedure, met of zonder ( "gewone" ) argumenten, optionele argumenten of parameterarrays zijn niet toegestaan.
De eigenlijke eventsource is het object waarnaartoe het WithEvents veld verwijst. Visual Basic 2010 Broncode Namespace Example2 Class SomeEventSource Private m_ID As Integer Public Property ID() As Integer Get ID = m_ID End Get Set( ByVal value As Integer) m_ID = value End Set End Property Delegate Sub SomeDelegate( ByVal sender As SomeEventSource) Public Event SomeEvent As SomeDelegate Public Sub RaiseSomeEvent() RaiseEvent SomeEvent( Me) End Sub End Class Class Client Private Shared WithEvents m_SomeEventSource As SomeEventSource Public Shared Sub Main() Dim object1 As New SomeEventSource With {.ID = 1} Dim object2 As New SomeEventSource With {.ID = 2} m_SomeEventSource = object1 m_SomeEventSource.RaiseSomeEvent() object1.RaiseSomeEvent() m_SomeEventSource = object2 m_SomeEventSource.RaiseSomeEvent() object2.RaiseSomeEvent() object1.RaiseSomeEvent() Console.ReadLine() End Sub Private Shared Sub someEventHandler( ByVal sender As SomeEventSource) _ Handles m_SomeEventSource.SomeEvent Console.WriteLine( "someEventHandler " & _ "( eventsource id : " & sender.ID & " )") End Sub Private Shared Sub setEventSource( _ ByVal someEventSource As SomeEventSource) m_SomeEventSource = SomeEventSource End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output someEventHandler ( eventsource id : 1 )
someEventHandler ( eventsource id : 1 )
someEventHandler ( eventsource id : 2 )
someEventHandler ( eventsource id : 2 ) Enkel het object waarnaartoe het WithEvents veld m_SomeEventSource verwijst is de aan een eventhandler gekoppelde eventsource. Op regels (1), (2), (3) en (4) verwijzen de expressies m_SomeEventSource, object1 en object2 dan ook naar de eigenlijke eventsource. De object1 expressie op regel (5) echter, verwijst naar een instantie van SomeEventSource die niet meer gekoppeld is aan de eventhandler.
Een typisch gebruik van argumenten voor een event wordt in bovenstaand voorbeeld geïllustreerd. Het sender argument is van het eventsourcetype, en kan zo door de eventhandler worden gebruikt zijn afhandeling te baseren op de identiteit of toestand van het eigenlijke eventsource object. boven
24.2.3. Eventhandling PatternEen generiek EventHandler(Of TEventArgs As System.EventArgs)-event type is reeds voorgedefinieerd. Deze is bruikbaar indien je het eventhandling pattern van het .NET Framework wenst toe te passen (1).
Dit pattern bestaat erin bij het optreden van de event de eventsource door te geven ( zoals in vorig voorbeeld ) en ook de "eventarguments" door te geven. Dit doorgeven van deze event argumenten zou in de vorm van een afgeleide EventArgs moeten gebeuren. Dit eventargumententype fungeert als containertype voor de eventargumenten die extra informatie over de event of eventsource kunnen opleveren naar de eventhandler toe.
Bij het doen optreden van deze event door de eventsource, wordt het eventsource object zelf ( Me ) en een instantie van het generiek actueel parametertype ( TEventArgs ) doorgegeven.
De eventhandler van de client dien een Object-source argument en een TEventArgs argument te definiëren.
Het actueel generiek parametertype ( TEventArgs ) moet afgeleid zijn van het voorgedefinieerde type System.EventArgs (2). Visual Basic 2010 Broncode Namespace Example3 Class Product Public Event PriceChanged As EventHandler( Of PriceChangedEventArgs) Protected Sub OnPriceChanged() RaiseEvent PriceChanged( Me, New PriceChangedEventArgs(Price)) End Sub Private m_Price As Decimal Public Property Price() As Decimal Get Price = m_Price End Get Set( ByVal value As Decimal) m_Price = value OnPriceChanged() End Set End Property End Class Class PriceChangedEventArgs : Inherits EventArgs Private ReadOnly m_Price As Decimal Public Sub New( ByVal price As Decimal) m_Price = price End Sub Public ReadOnly Property Price() As Decimal Get Price = m_Price End Get End Property End Class Class Client Private Shared WithEvents product1 As New Product Public Shared Sub Main() product1.Price = 5 product1.Price = 10 Console.ReadLine() End Sub Private Shared Sub product1_PriceChanged( _ ByVal sender As Object, ByVal e As PriceChangedEventArgs) _ Handles product1.PriceChanged Console.WriteLine( "New price : " & e.Price) End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output New price : 5
New price : 10 In onderstaand voorbeeld wordt geïllustreerd hoe :
- een eventsource meerdere events kan bevatten - een eventhandler aan meerdere events van meerdere eventsources kan gekoppeld worden - een event van een eventsource aan meerdere eventhandlers kan gekoppeld worden - niet alle events van een eventsource moeten afgehandeld worden - de volgorde van optreden van statisch gekoppelde eventhandlers onvoorspelbaar is Visual Basic 2010 Broncode Namespace Example4 Class SomeFirstEventSource Public Event SomeFirstEvent() Public Event SomeSecondEvent() Public Sub RaiseEvents() RaiseEvent SomeFirstEvent() RaiseEvent SomeSecondEvent() End Sub End Class Class SomeSecondEventSource Public Event SomeFirstEvent() Public Event SomeSecondEvent() Public Sub RaiseEvents() RaiseEvent SomeFirstEvent() RaiseEvent SomeSecondEvent() End Sub End Class Class Client Private Shared WithEvents m_SomeFirstEventSource As _ New SomeFirstEventSource Private Shared WithEvents m_SomeSecondEventSource As _ New SomeSecondEventSource Public Shared Sub Main() m_SomeFirstEventSource.RaiseEvents() m_SomeSecondEventSource.RaiseEvents() Console.ReadLine() End Sub Private Shared Sub someFirstEventHandler() _ Handles m_SomeFirstEventSource.SomeFirstEvent, _ m_SomeFirstEventSource.SomeSecondEvent Console.WriteLine( "someFirstEventHandler") End Sub Private Shared Sub someSecondEventHandler() _ Handles m_SomeFirstEventSource.SomeFirstEvent, _ m_SomeSecondEventSource.SomeSecondEvent Console.WriteLine( "someSecondEventHandler") End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output someSecondEventHandler
someFirstEventHandler
someFirstEventHandler
someSecondEventHandler boven
24.2.4. Koppeling at Runtime - AddHandler en RemoveHandlerIn voorgaande voorbeelden werden de events van de eventsources steeds statisch ( at compiletime ) gekoppeld aan de eventhandlers. Ook dynamische koppeling ( at runtime ) is mogelijk. Deze werkwijze is zelfs flexibeler.
We hebben geen WithEvents gedeclareerde velden nodig ( die de eventsources zijn ) en we dienen bij de eventhandler geen Handles clause op te nemen.
Wat we wel nodig hebben is een AddHandler statement om aan te geven ( tijdens runtime ) welke procedure we koppelen aan welke event van welke eventsource. Eens dit statement uitgevoerd is de koppeling gemaakt en zal bij het optreden van die event van die eventsource de eventhandler worden aangeroepen.
De mogelijkheid bestaat nu ( in tegenstelling tot bij statische koppeling ) om die eventhandler weer los te koppelen van de event van die eventsource. Dit kan aan de hand van een RemoveHandler statement, waarbij je dezelfde informatie opgeeft als bij de AddHandler.
Het is een flexibelere oplossing in de zin dat at runtime kan bepaald worden wanneer en welke routine een event kan afhandelen.
In tegenstelling tot statische koppeling waarbij eender welk object waarnaartoe de WithEvents member wijst de eventsource is, is bij dynamisch koppeling elk object waarnaartoe je als eventsource verwijst in een AddHandler statement een eventsource. Visual Basic 2010 Broncode Namespace Example5 Class SomeEventArgs : Inherits EventArgs Private ReadOnly m_EventArgsCounter As Integer Public Sub New( ByVal counter As Integer) m_EventArgsCounter = counter End Sub Public ReadOnly Property EventCounter() As Integer Get EventCounter = m_EventArgsCounter End Get End Property End Class Class SomeEventSource Private m_ID As Integer Public Property ID() As Integer Get ID = m_ID End Get Set( ByVal value As Integer) m_ID = value End Set End Property Public Event SomeEvent As EventHandler( Of SomeEventArgs) Public Sub RaiseSomeEvent() Static counter As Integer = 1 RaiseEvent SomeEvent( Me, New SomeEventArgs(counter)) counter += 1 End Sub End Class Class Client Public Shared Sub Main() Dim someFirstEventSource As New SomeEventSource With {.ID = 1} Dim someSecondEventSource As SomeEventSource someFirstEventSource.RaiseSomeEvent() AddHandler someFirstEventSource.SomeEvent, AddressOf someEventHandler someFirstEventSource.RaiseSomeEvent() someSecondEventSource = someFirstEventSource someFirstEventSource.RaiseSomeEvent() someSecondEventSource.RaiseSomeEvent() someFirstEventSource = New SomeEventSource With {.ID = 2} someFirstEventSource.RaiseSomeEvent() someSecondEventSource.RaiseSomeEvent() AddHandler someFirstEventSource.SomeEvent, AddressOf someEventHandler someFirstEventSource.RaiseSomeEvent() someSecondEventSource.RaiseSomeEvent() RemoveHandler someSecondEventSource.SomeEvent, _ AddressOf someEventHandler someFirstEventSource.RaiseSomeEvent() someSecondEventSource.RaiseSomeEvent() AddHandler someFirstEventSource.SomeEvent, AddressOf someEventHandler someFirstEventSource.RaiseSomeEvent() RemoveHandler someFirstEventSource.SomeEvent, _ AddressOf someEventHandler someFirstEventSource.RaiseSomeEvent() Console.ReadLine() End Sub Private Shared Sub someEventHandler( ByVal sender As Object, _ ByVal e As SomeEventArgs) Console.WriteLine( "someEventHandler " & _ "( eventsource id : " & _ DirectCast(sender, SomeEventSource).ID & ", " & _ "event-counter : " & e.EventCounter & " )") End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output someEventHandler ( eventsource id : 1, event-counter : 2 )
someEventHandler ( eventsource id : 1, event-counter : 3 )
someEventHandler ( eventsource id : 1, event-counter : 4 )
someEventHandler ( eventsource id : 1, event-counter : 5 )
someEventHandler ( eventsource id : 2, event-counter : 2 )
someEventHandler ( eventsource id : 1, event-counter : 6 )
someEventHandler ( eventsource id : 2, event-counter : 3 )
someEventHandler ( eventsource id : 2, event-counter : 4 )
someEventHandler ( eventsource id : 2, event-counter : 4 )
someEventHandler ( eventsource id : 2, event-counter : 5 ) Ook bij koppeling at runtime kan :
- een eventsource meerdere events bevatten - een eventhandler aan meerdere events van meerdere eventsources worden gekoppeld - een event van een eventsource aan meerdere eventhandlers worden gekoppeld - niet alle events van een eventsource afgehandeld worden
De volgorde van optreden van de dynamisch gekoppelde eventhandlers is hier wel duidelijk, ze zullen in dezelfde volgorde als volgorde van koppeling worden uitgevoerd.
Als verschillende malen dezelfde eventhandler gekoppeld werd aan een event van dezelfde eventsource, zal bij het verwijderen van die eventhandler van die event, slechts een van die koppelingen verwijderd worden. boven
24.2.5. Overerven van EventsEen afgeleide klasse ( SomeDerivedEventSource ) erft events over van de basis klasse ( SomeBaseEventSource ). Als de method RaiseEvents op een SomeDerivedEventSource object wordt aangeroepen, zullen dan ook de overgeërfde events optreden.
Men kan geen overgeërfde events "raisen", een event moet men altijd doen optreden vanuit het type waarin de event gedefenieerd is. Vandaar dat er vaak een Protected "OnEvent" method wordt voorzien die de event zal raisen in de eventsource. Deze protected method kan dan wel worden aangeroepen in de afgeleide eventsource.
Het is mogelijk in de eventsource zelf ( of in afgeleide types ) een eventhandler te voorzien en te koppelen aan een event van deze eventsource. Deze koppeling kan zowel at run- als at compiletime gebeuren. Visual Basic 2010 Broncode Namespace Example6 Class SomeBaseEventSource Public Event SomeFirstEvent() Protected Event someSecondEvent() Private Event someThirdEvent() Private Sub someEventHandler() Handles Me.someThirdEvent Console.WriteLine( "SomeEventSource.someEventHandler") End Sub Public Sub RaiseEvents() RaiseEvent SomeFirstEvent() RaiseEvent someSecondEvent() End Sub End Class Class SomeDerivedEventSource : Inherits SomeBaseEventSource Private Sub someEventHandler() Handles MyBase.someSecondEvent Console.WriteLine( "SomeDerivedEventSource.someEventHandler") End Sub End Class Class Client Private Shared WithEvents m_SomeDerivedEventSource As _ New SomeDerivedEventSource() Public Shared Sub Main() m_SomeDerivedEventSource.RaiseEvents() Console.ReadLine() End Sub Private Shared Sub someEventHandler() _ Handles m_SomeDerivedEventSource.SomeFirstEvent Console.WriteLine( "someEventHandler") End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output someEventHandler
SomeDerivedEventSource.someEventHandler Toch is het op zen minst gesteld vreemd de events van een eventsource in de eventsource zelf af te handelen. Events worden typisch gebruikt in situaties waar het type ( in dit geval eventsourcetype ) niet beschikt over de kennis wat er moet gebeuren als deze event zich voordoet. Een Button bijvoorbeeld weet immers ook niet wat er moet gebeuren bij het klikken op deze knop binnen een specifieke applicatie die van deze knop gebruikt maakt.
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
| hoofdstuk |
23. 24. 25.  |
| onderwerp |
24.1. 24.2. Events 24.3.  |
| broncode |
Download Events.vb of Events.cs |
| datum |
laatst gewijzigd op woensdag 1 oktober 2008, laatst gepubliceerd op zondag 31 juli 2011 |
|