Search code examples
.netvb.neteventsaddhandler

Difference between Handles declaration and AddHandler for SystemEvents in VB.NET


I'm using a device driver which I need to close when the system goes to sleep. I thought I could add a handler for the SystemEvents.PowerModeChanged event to ApplicationEvents.vb as follows:

Public Sub SystemEvents_PowerModeChanged(sender As Object, e As PowerModeChangedEventArgs) _
        Handles SystemEvents.PowerModeChanged

    If e.Mode = PowerModes.Suspend Then
        logger.Trace("The computer is suspending. Closing device.")
        'Close device
    ElseIf e.Mode = PowerModes.Resume Then
        logger.Trace("The computer is resuming operation from suspend mode. Opening device.")
        ' Open device
    End If
End Sub

to handle the event using the Handles keyword. However, there's a compilation error on the Handles clause:

Handles clause requires a WithEvents variable defined in the containing type or one of its base types.

WithEvents seems to always be defined for the other events I encounter in .NET, so why is this one different? I would prefer to use the Handles clause, because this automates the addition and removal of the handler. It also keeps the functionality self-contained instead of spreading it between the initializer, destructor, and the function itself. Is it possible to use the Handles declaration on this event?

A clue to this problem is that the following code does work:

AddHandler SystemEvents.PowerModeChanged, AddressOf SystemEvents_PowerModeChanged

Solution

  • The events for the SystemEvents class are different from the kind you are used to, they are static events. "Shared" in vb.net speak. You can reason this out by realizing there is only ever one "system". So only ever one source for the event.

    Which makes this text in the MSDN article for WithEvents relevant:

    You must declare WithEvents variables to be object variables so that they can accept class instances.

    You cannot create an object variable of type SystemEvents. So you can't use the WithEvents keyword. So you can't use the Handles clause either. Falling back to AddHandler is a rock-hard requirement.

    And, very important, you'll have to explicitly use RemoveHandler when you are no longer interested in the event. Such as in the FormClosed event handler of a Form. Necessary so SystemEvents stops triggering your event handler when your UI is no longer around. Forgetting to do so causes a memory leak (the form object cannot be garbage collected), an ObjectDisposedException if you're lucky. You could only skip this requirement if closing the form or window also terminates your app.