Beheersen wanneer een event wordt verwerkt of niet

Inleiding

Events zijn een krachtig hulpmiddel bij het programmeren met Excel. Events maken het mogelijk te reageren op acties van de gebruiker zoals het bewerken van een cel of het klikken van de knop Afdrukken. Wanneer een applicatie gebruik maakt van events, dan is het ook vaak nodig de controle te hebben over het feit of de code in het event wel of niet wordt uitgevoerd (bijvoorbeeld om te voorkomen dat de event code in een oneindige lus geraakt of om programmacode de mogelijkheid te geven acties uit te voeren die het event voorkomt).

Voorbeeld

Er zijn verschillende manieren om event code uit te schakelen. Eén ervan is middels Application.EnableEvents=False. Daarmee worden helaas alle application events uitgeschakeld, inclusief event handlers die invoegtoepassingen mogelijk gebruiken. En als de code vastloopt, dan blijven de events uitgeschakeld! Een ander nadeel is dat deze optie niet werkt voor de event code van userforms en event code van controls op werkbladen.

Een andere methode is middels gebruikmaking van een globale variabele, wiens waarde wordt getest in elke relevante event subroutine. Dit wordt echter niet gezien als een goede programmeer gewoonte (hoewel ik deze regelmatig zelf ook toepas). Hieronder toon ik een meer algemene benadering die gebruik maakt van een boolean variabele binnen de klasse module die de event code bevat. Als voorbeeld gebruik ik de Thisworkbook module, maar in principe kan deze methode in elke willekeurige klasse module worden toegepast (de Thisworkbook module, de werkblad modules en modules van userforms zijn in feite klasse modules).

Stel dat voorkomen moet worden dat de gebruiker de werkmap sluit. Daartoe kan de volgende Workbook_BeforeClose routine worden geschreven in de Thisworkbook module:

Option Explicit

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    MsgBox "You are not allowed to close this file!", vbInformation + vbOKOnly
    Cancel = True
End Sub

Het is echter wel nodig, dat programmacode van de applicatie het bestand kan sluiten. Hiertoe wordt een publieke variabele gedeclareerd bovenaan in de Thisworkbook module:

Option Explicit

Public NoEvents As Boolean

En in de BeforeClose event, wordt de waarde van deze variabele getest:

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    If NoEvents Then Exit Sub
    MsgBox "You are not allowed to close this file!", vbInformation + vbOKOnly
    Cancel = True
End Sub

Deze code moet natuurlijk ook nog in gebruik genomen worden. In ieder subroutine waarmee het bestand gesloten zou kunnen worden kan dit als volgt:

Sub CloseMe()
    ThisWorkbook.NoEvents = True
    ThisWorkbook.Close
End Sub

Natuurlijk moet bNoEvents weer terug op False gezet worden als u deze heeft gebruikt om bijvoorbeeld een ander event te voorkomen:

    ThisWorkbook.NoEvents = False

Het grote voordeel van deze methode boven het gebruik van
Application.EnableEvents=False
is dat als de code wordt gereset, bijvoorbeeld als de gebruiker op End klikt bij een runtime error, de variabele bNoEvents automatisch op False gezet wordt en dus de events gewoon blijven werken. Deze methode geeft ook meer controle over de events, daar één enkel event kan worden uitgeschakeld, door toevoegen van meerdere variabelen:

Public NoCloseEvent As Boolean
Public NoPrintEvent As Boolean


Vragen, suggesties en opmerkingen

Al het commentaar over deze pagina:


Commentaar van: John Philippen (12-5-2020 19:58:00) deeplink naar dit commentaar

Beste Jan Karel,
ik zit met de volgende uitdaging.
Ik heb een formulier met verschillende tekstvakken.
In één van de tekstvakken moet het bedrag ingevuld worden.
In een ander vak (combobox) moet door middel van een J aangegeven worden of er sprake is van KIA (kleinschaligheidsinvesteringsaftrek).
Als iemand daar een J invult wordt aan de hand van het bedrag gecontroleerd of daar wel een J mag staan. Indien een J niet plausibel is, komt een waarschuwing. Het kan echter zijn dat de J op basis van het bedrag legitiem is.
Als de gebruiker dan achteraf het bedrag wijzigt, dient gecontroleerd te worden of KIA dan nog wel legitiem is. Ook dat werkt.
Nu wil ik echter als het niet legitiem is wil ik dat de combobox na de waarschuwing via setfocus geselecteerd wordt. Als ik dat echter doet, komt hij in een loop terecht en verschijnt de melding nog twee keer. Ik weet dat ik een formulierevent niet kan uitschakelen. Maar hoe zou ik dit het beste kunnen triggeren.
Indien gewenst mail ik je het bestand
m.v.g.
John Philippen


Commentaar van: Jan Karel Pieterse (13-5-2020 09:29:00) deeplink naar dit commentaar

Hoi John,

Kom je er met de info op deze pagina niet uit dan?


Commentaar van: john philippen (13-5-2020 12:55:00) deeplink naar dit commentaar

Nee,
het gaat immers om een formulierevent,
en die kun je niet uitschakelen.


Commentaar van: Jan Karel Pieterse (13-5-2020 16:31:00) deeplink naar dit commentaar

Hoi John,

Juist wel, met de techniek die ik hierboven beschreven heb. Dus bovenaan de module achter de userform zet je

Dim NoEvents As Boolean


Dan zet je in iedere event routine van je userform als eerste regel:

    If NoEvents Then Exit Sub


En in code in je formulier dat een event zou kunnen triggeren, maar jij het niet wilt:

    NoEvent = True
    'Hier code die een event veroorzaken kan
    NoEvent = True


Heeft u vragen, suggesties of opmerkingen? Gebruik dan dit formulier.

Mocht uw vraag niet direct relevant zijn voor deze pagina, maar een algemene Excel vraag betreffen, dan adviseer ik om deze hier te stellen: excelexperts.nl/forum/index.php.




Als u VBA code in uw commentaar plaatst, gebruik dan [VB] tags: [VB]Uw code[/VB].