in

Redwerb

Tools, tips, and techniques for software developers.

Redwerb

Tools, tips, and techniques for software developers.

April 2008 - Posts

  • How Things Work: Events in .Net

    Ever take the time to learn how events work in .Net? They are pretty basic, but unless you have taken the time to discover how they work, they may seem to be a bit like magic.

    Events are a very powerful way to reduce coupling in your application. Events in .Net are based on the Observer pattern identified in the classic Gang-of-Four book, Design Patterns: Elements of Reusable Object-Oriented Software.

    The first part of this article discusses how VB.Net hides some of the complexity of dealing with events. The second part explains how events work in .Net in general.

    What VB.Net Hides From You

    Compared to C#, event handling in VB.Net requires fewer lines of code to both publish and subscribe to events. However, this is because the VB.Net compiler hides the actual implementation from the developer. If you were to look at the code that the compiler generates, you would see that events in VB.Net work pretty very much the same as C#.

    Let's create a couple of simple classes to use as an example. One is called MyPublisher and it defines an event called MyEvent. The other is called MySubscriber which creates an instance of MyPublisher and listens for MyEvent. You can download the example code here (in the download section of this website).

       1:  Public Class MyPublisher
       2:   
       3:      Public Sub ForceMyEvent()
       4:          OnMyEvent(EventArgs.Empty)
       5:      End Sub
       6:   
       7:      Public Event MyEvent(ByVal sender As Object, ByVal e As EventArgs)
       8:      Protected Overridable Sub OnMyEvent(ByVal e As EventArgs)
       9:          RaiseEvent MyEvent(Me, e)
      10:      End Sub
      11:   
      12:  End Class
      13:   
      14:  Public Class MySubscriber
      15:   
      16:      Public Sub New(ByVal publisher As MyPublisher)
      17:          mPublisher = publisher
      18:      End Sub
      19:   
      20:      Private WithEvents mPublisher As MyPublisher
      21:      Public ReadOnly Property Publisher() As MyPublisher
      22:          Get
      23:              Return mPublisher
      24:          End Get
      25:      End Property
      26:   
      27:      Private Sub mPublisher_MyEvent(ByVal sender As Object, ByVal e As EventArgs) Handles mPublisher.MyEvent
      28:          Console.WriteLine("Hello World!")
      29:      End Sub
      30:   
      31:  End Class 

    Pretty basic code, easy to understand, and one of the reasons why I like VB.Net. However, if you really want to understand what's going on, you should open this code up in Reflector. What you see is that the VB.Net compiler hides a lot of the complexity for you. What seems like a simple line of code actually get's broken down into many lines of code.

    NOTE: Reflector shows some code that is automatically generated that doesn't have anything to do with events so I removed it from the examples, as well as it doesn't always generate the code correctly (for example, Reflector starts line 12 in the publisher with RaiseEvent which is incorrect).

       1:  Public Class MyPublisher
       2:   
       3:      Public Sub ForceMyEvent()
       4:          Me.OnMyEvent(EventArgs.Empty)
       5:      End Sub
       6:   
       7:      Public Delegate Sub MyEventEventHandler(ByVal sender As Object, ByVal e As EventArgs)
       8:      Public Event MyEvent As MyEventEventHandler
       9:      Protected Overridable Sub OnMyEvent(ByVal e As EventArgs)
      10:          If MyEventEvent IsNot Nothing Then
      11:              MyEventEvent(Me, e)
      12:          End If
      13:      End Sub
      14:   
      15:  End Class 

    If you are familiar with the way C# handles events, you will notice that VB.Net is compiled into something very similar. IMHO, VB.Net is more elegant in that you can declare the event and the delegate in a single line and you can raise the event in a single line.

    The subscriber is a bit more interesting.

       1:  Public Class MySubscriber
       2:   
       3:      Public Sub New(ByVal publisher As MyPublisher)
       4:          Me.mPublisher = publisher
       5:      End Sub
       6:   
       7:      <AccessedThroughProperty("mPublisher")> _
       8:      Private _mPublisher As MyPublisher
       9:      Private Property mPublisher() As MyPublisher
      10:          Get
      11:              Return Me._mPublisher
      12:          End Get
      13:          Set(ByVal WithEventsValue As MyPublisher)
      14:              Dim handler As MyEventEventHandler = New MyEventEventHandler(AddressOf Me.mPublisher_MyEvent)
      15:              If (Not Me._mPublisher Is Nothing) Then
      16:                  RemoveHandler Me._mPublisher.MyEvent, handler
      17:              End If
      18:              Me._mPublisher = WithEventsValue
      19:              If (Not Me._mPublisher Is Nothing) Then
      20:                  AddHandler Me._mPublisher.MyEvent, handler
      21:              End If
      22:          End Set
      23:      End Property
      24:   
      25:      Public ReadOnly Property Publisher() As MyPublisher
      26:          Get
      27:              Return Me.mPublisher
      28:          End Get
      29:      End Property
      30:   
      31:      Private Sub mPublisher_MyEvent(ByVal sender As Object, ByVal e As EventArgs)
      32:          Console.WriteLine("Hello World!")
      33:      End Sub
      34:   
      35:  End Class 

    In the original code, we declare mPublisher using the WithEvents keyword. What this keyword does is change the field that we defined into a property and creates a new field by prefixing the original name of the field with an underscore. By doing this, when we set mPublisher in our code, what we are really doing is setting the property. This causes the AddHandler/RemoveHandler code to be invoked (if you develop in C#, this is a very useful pattern to follow).

    How Events Work

    In the Publisher class in the above example, MyEventEvent (line 11) is being called as if it were a method, but it is actually what is called a multi-cast delegate. A delegate is basically a reference to a method (in the case of events, this would be the event handler). A multi-cast delegate is essentially a list of delegates that can be called in the same way as a single delegate. Refer to the Code Project article, A Beginner's Guide to Delegates, for a good description of delegates and multi-cast delegates.

    So basically when we raise an event, we are simply iterating through the list of event handlers and calling them one at a time (synchronously). All of the event handlers get called unless one of them throws an exception.

    If you want more control over how events are raised, for example, you want to stop calling additional event handlers when one of them has handled or canceled the event, you can explicitly call each event handler in the list. Let's take our example from above and tweak it so that we are manually calling the methods.

       1:  Protected Overridable Sub OnMyEvent(ByVal e As CancelEventArgs)
       2:      If MyEventEvent IsNot Nothing Then
       3:          For Each handler As MyEventEventHandler In MyEventEvent.GetInvocationList()
       4:              handler(Me, e)
       5:              'If e.Cancel Then Exit For
       6:          Next
       7:      End If
       8:  End Sub 

    In this example we are iterating through the list of delegates (the references to the event handlers) and calling each method in turn. If the event arguments were CancelEventArgs, we could check e.Cancel after calling the delegate and if it was true, we could exit the for loop. You can also use this to add asynchronous event handling to your project (if you do, make sure you document it well!).

  • My Worst Fear

    My worst fear is getting some form of dementia. I think I can handle losing limbs or other serious injuries, but losing my ability to solve problems or communicate would be terrible. The reason I became a software developer was because I enjoy solving problems and my ability to do so is a major way that I define myself.

    The professor of the usability class that I recently started was diagnosed with Parkinson's disease. Parkinson's disease primarily affects the motor skills of an individual. However there are also symptoms that effect the brain, including dementia and short-term memory loss. There is currently no cure for Parkinson's disease. Michael J. Fox suffers from Parkinson's disease.

    Although I am sure the professor is brilliant, he was unable to communicate very effectively due to this disease. One of the symptoms is hypophonia or soft speech. The room was deathly silent for 4 hours during the lecture, any noise (such as changing position in a chair) was a distraction.

    Another symptom that I noticed was short term memory loss.  The professor frequently paused during the lecture, often times in the middle of a sentence, trying to remember what he was talking about. He also went off subject often. Normally this wouldn't bother me, but I was having a hard time paying attention already and I didn't really know what the course was about, so I was often confused about what he was talking about and whether it was part of the course, or something else.

    For a class called Visual Media in Technical Communication, I found it a bit ironic that there was no visual presentation for the class. Perhaps before the professor contracted Parkinson's disease he wrote on the white board or something, however, he sat while he did the lecture (I've never had a professor sit while they did a lecture). Of course, symptoms involving motor skills are the most common symptoms of Parkinson's disease and is probably the reason he sat through it.

    As you can probably imagine, I dropped the class. I feel guilty about dropping the class. It's not the professors fault that he wasn't able to perform his job very well and I'm sure he isn't ready to leave a job that he's been doing for many years. Considering that this is my greatest fear, I am certainly sympathetic to his condition.

    If you are interested in learning more about Parkinson's disease, there are a number of organizations out there. The following list is from the Wikipedia article...

Copyright Brian Brewder, 2007. All rights reserved.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems