8 Replies - 8848 Views - Last Post: 25 January 2012 - 12:30 PM

#1 jens  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 67
  • View blog
  • Posts: 430
  • Joined: 09-May 08

Why events, and what are they?

Posted 22 January 2012 - 02:07 PM

I'm having a hard time understanding the difference between delegates and events, could someone please explain? Referring to the code below I have a few questions.

Why is the button click using an event...
Why doesn't it just invoke a delegate instead...

As we can see from #3 a delegate is instantiated when we are using an event. As seen in #4 this delegate instance is then "added" to an event. At line #5 we see how the event is fired; looking again at #3 and #4 I think that the event invokes the delegate which calls the onstartEvent method.

Looking again at #3 and #4 and then at #6 after running this code we see that we get get the exact same behaviour from invoking the delegate instance as from fireing the event.

1) Why are there events?

2) Furthermore looking at #0 things start to look a bit strange. An event is some type that is actually a delegate type. What ARE events, RELLY?

3) Why can't we just settle for delegates (Invoking delegates instead of firing events)
and be done with the events?

4) At #2 the delegate (?) EventHandler is added to an event. Where IS the event (where is it declared and instansiated)?

5) How is the event above called/invoked/fired

Regards
/Jens


using System;
using System.Windows.Forms;

namespace WindowsFormsApplication3
{
    public partial class Form1 : Form
    {
        // custom delegate
        public delegate void StartDelegate();

        // custom event
        public event StartDelegate StartEvent;		//#0

        public Form1()
        {
            // Creating a button from code, otherwise the EventHandler delegate
            // assignment is done automatically for us in the Form1.Designer.cs
            Button clickMe = new Button();
            clickMe.Text = "Click Me";
            clickMe.Parent = this;

            // An EventHandler delegate is assigned
            // to the button's Click event
            //clickMe.Click += new EventHandler(onclickMeClicked);
            //
            // We can just as well do it this way in order
            // to make the similarities between events and delegates
            // more obvious.
            EventHandler eHandler = onclickMeClicked;   //#1
            clickMe.Click += eHandler;                  //#2

            // our custom "StartDelegate" delegate is assigned
            // to our custom "StartEvent" event.
            //StartEvent += new StartDelegate(onstartEvent);
            //
            // We can just as well do it this way in order
            // to make the similarities between events and delegates
            // more obvious.
            StartDelegate sDelegate = onstartEvent;     //#3
            StartEvent += sDelegate;                    //#4

            // fire our custom event
            StartEvent();                               //#5

            // Invokation of the delegate.
            sDelegate();                                //#6

            // Replacing the method in the delegate.
            sDelegate = AMethod;

            // Invokation of the delegate.
            sDelegate();
        }

        // this method is called when the "clickMe" button is pressed
        public void onclickMeClicked(object sender, EventArgs ea)
        {
            MessageBox.Show("You Clicked.");
        }

        // this method is called when the "StartEvent" Event is fired
        public void onstartEvent()
        {
            MessageBox.Show("Started event.");
        }

        // This method called when the "sDelegate" sd is invoked the second time.
        public void AMethod()
        {
            MessageBox.Show("Delegate invokation.");
        }
    }
}


This post has been edited by jens: 22 January 2012 - 02:08 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Why events, and what are they?

#2 RexGrammer  Icon User is offline

  • Coding Dynamo
  • member icon

Reputation: 182
  • View blog
  • Posts: 783
  • Joined: 27-October 11

Re: Why events, and what are they?

Posted 22 January 2012 - 03:02 PM

Quote

An event is a message sent by an object to signal the occurrence of an action. The action could be caused by user interaction, such as a mouse click, or it could be triggered by some other program logic. The object that raises the event is called the event sender. The object that captures the event and responds to it is called the event receiver.


This tells it pretty correctly: an event is a message to signal when something has been done.

Now the next part:

Quote

In event communication, the event sender class does not know which object or method will receive (handle) the events it raises. What is needed is an intermediary (or pointer-like mechanism) between the source and the receiver. The .NET Framework defines a special type (Delegate) that provides the functionality of a function pointer.


Because the event doesn't know to who is it being sent, it needs a mediator: a delegate that is basically just a pointer to a method.

Quote

A delegate is a class that can hold a reference to a method. Unlike other classes, a delegate class has a signature, and it can hold references only to methods that match its signature. A delegate is thus equivalent to a type-safe function pointer or a callback. While delegates have other uses, the discussion here focuses on the event handling functionality of delegates. A delegate declaration is sufficient to define a delegate class. The declaration supplies the signature of the delegate, and the common language runtime provides the implementation. The following example shows an event delegate declaration.


A delegate is a class that points to a method, it has a signature and can only point to methods that have the same signature as himself. In other words it's a type-safe function pointer.

This was all quoted from: Events and Delegates (MSDN). I chewed it up a bit for you ;).

Now for your specific questions:

1) So that you can react to some important action in the application.
2) You have an explanation what is an event earlier in my post. It's a message that signals that something has been done.
3) There's an explanation both of the delegate and the event earlier in my post.
4) It's declared on line 12
5) You can't instantiate an event. You can only subscribe to it, an example of this is on line 40

Basically if you're dealing with WPF or WinForms you're dealing with event driven programming models. You see it's a pretty big thing. It's almost everywhere!

If you're wondering where aren't you using event driven programming models: in XNA games.

I've also had a hard time understanding this, but in time I realized what events actually are.

The best way to learn these concepts is to experiment and to gain experience, it's also a plus when you're working with experienced people.

Hope this helps!
Cheers!

This post has been edited by RexGrammer: 22 January 2012 - 03:12 PM

Was This Post Helpful? 3
  • +
  • -

#3 Ryano121  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1363
  • View blog
  • Posts: 3,002
  • Joined: 30-January 11

Re: Why events, and what are they?

Posted 22 January 2012 - 03:05 PM

We also have a good tutorial on this subject - Delegates, Lambdas and Events
Was This Post Helpful? 0
  • +
  • -

#4 CodingSup3rnatur@l-360  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 992
  • View blog
  • Posts: 972
  • Joined: 30-September 10

Re: Why events, and what are they?

Posted 22 January 2012 - 04:40 PM

*
POPULAR

Hi,

What are events?

It is not technically correct to say events are delegates. Events are not delegates. Events are an application of delegates. They are more than just simple delegates.


Why do we not simply use delegates and scrap events?

You are absolutely right that you can get functionally exactly the same results if you use a delegate, instead of an event. However, there is one crucial difference between the two. That main difference is one of accessibility.

Example

Say we have defined a delegate type, as so:

public delegate void StartDelegate();




We could do something like this using a plain field of the delegate type, to create, and subscribe to, the event:

public class Test
{
    public StartDelegate myEvent;

    protected virtual void OnMyEvent()
    {
        StartDelegate temp = this.myEvent;
        if (temp != null)
        {
            temp(); //raise the event
        }
    }
}



We can then subscribe to the event in the main method, as so:

public class Program
{
     private static Test test;
 
     public static void main(String[] args)
     {
          test.myEvent += new StartDelegate(test_myEvent);
     }

     public static void test_myEvent()
     {
         
     }
} 



However, we can also raise the event from the Program class:

public static void main(String[] args)
{
    test.myEvent += new StartDelegate(test_myEvent);
    test.myEvent(); //raise the event from another class
}



main() is now reaching into the Test object, and raising its event! This is bad. It breaks encapsulation. It is the Test object's event, so only it should be able to raise it. Imagine the chaos that would cause...

We subscribe to the event as we want to be notified when the specific event/change of state has occurred. However, that whole idea is destroyed if anyone can raise the event, as any object can raise the event of any other object. So, any object can raise the event that you are listening to, at any time they wish, which will likely not be at the time that the event should in reality be raised.

Events fix this problem


By changing this line:

public StartDelegate myEvent;


to

public event StartDelegate myEvent;


this line in the main method:

test.myEvent();


will no longer compile. We will get an error that reads something similar to this:

Quote

The event 'Test.myEvent' can only appear on the left hand side of += or -= (except when used from within the type 'Test')


As the error message suggests, we can still subscribe to the event as usual, without a problem. So, the event keyword makes it so users of the the object that has the event can subscribe to, and subscribe from, the event without a problem. However, they cannot raise the event; only Test objects can do that.

This is because when the compiler sees the event, it generates extra code:

This:

public event StartDelegate myEvent;


gets translated to something like this:

private StartDelegate _myEvent;

public StartDelegate myEvent
{
    add
    {
        lock(this)
        {
            _myEvent += value; //actually calls Delegate.Combine() to add the 'value' to the delegates invocation list, which is equivalent to the += version
        }
    }
    remove
    {
        lock(this)
        {
           _myEvent -= value; //actually calls Delegate.Remove() to remove the 'value' from the delegates invocation list, which is equivalent to the -= version
        }
    }
}




The delegate type field is made private so external classes cannot access it directly (and therefore cannot invoke it directly). All access to the delegate field is controlled through this special sort of property that adds and removes delegates from the delegate field.

When we do test.myEvent += new StartDelegate(test_myEvent);

the add part (which is compile as a method , as with normal properties that we see all the time) of the property like structure is called, and the delegate is added to the private field's invocation list.


That is the difference between a plain delegate type field, and a delegate type field with the event keyword. The version with the event keyword causes the compiler to take special measures to add some encapsulation (stopping external objects from being able to raise events of other objects, by only allowing adding and removing from the delegates invocation list), some basic thread synchronization etc.

In that code, 'event' is roughly the term used to describe all of that code (the special 'property' (although, not really a property in the traditional sense) which is just a pair of ad/remove methods, the delegate field, the thread synchronization code etc), the term 'delegate' is simply referring to the private delegate field in that event setup. Hence, the difference between a delegate, and an event.

An event is backed by a delegate, basically.




Why does it matter if other objects can raise the events of all other objects, and thus why do we need the event keyword?


Picture this simple scenario... You have written an application that monitors the fluctuations in stock exchange values (via a web service). Every time different values come in to your DataRetreiver class (a class you have written that grabs, and collates the data), it raises an event that contains the data in its event arguments, of which various other classes listen out for, so that they can grab the newly retrieved data, and process it, present it, when the event is raised to say that new data has arrived.

Now imagine that this application allows third parties to write plug ins for it, and the third parties a given access to the DataRetreiver object, so that they have access to functionality required to get the data. However, as we aren't using the event keyword on the delegate in the DataRetreiver class, they can also raise the event, and fill the event's arguments with data. So, third party plug in writers can raise the event at any time they wish, and they can raise it with bogus data. As all the other classes in the application listen for this event, and rely on it to get up to date data, all those classes will be continually getting incorrect data, due to this third party raising the event of the DataRetreiver continually, and with wrong data.

So, basically, third parties can totally break your application simply by raising this event.

Add the event keyword to the delegate field in the DataRetreiver, now third party plug in writers can only subscribe to, and unsubscribe from, the event in the DataRetreiver class. They can no longer raise the event manually (and raise it with their own supplied bogus data), and thus they no longer have the means to destroy our application.

That is just one, slightly dramatic example, but it is clearly very important (both logically, and functionally) that if an object has an event that is raised under certain circumstances, and is raised with certain data, that only that object is allowed to raise the event, thus ensuring that the event is always raised at the correct time, and with the correct data. NO other object should be able to raise the event directly.

It is basic encapsulation. We should restrict access to the inner workings, and fields of classes as much as is possible.

You should always use the event keyword, for your events :)


How is the Click event of the Button object raised?

Presumably, the operating system detects the click on button window, sends a message to the application, and the event is raised in response to that message, as events are normally raised in .NET.


Is EventHandler a delegate type?

Yes, EventHandler is a delegate type defined by the framework that is used to define events. It is standard for events to have two arguments (Object sender, EventArgs e), and a void return type. This delegate encapsulates methods that have this number of parameters, and a void return type, hence it is commonly used to define events.

This line:

clickMe.Click += eHandler;


you can think roughly as calling the add part of this code:

Spoiler


Thus, we are adding delegate instance to the private _Click delegate field of the button class, via the special property. And, I shall repeat what I said earlier:

Quote

In that code, 'event' is roughly the term used to describe all of that code (the special 'property', the delegate field, the thread synchronization code etc), the term 'delegate' is simply the private delegate field. Hence, the difference between a delegate, and an event.


My tutorial here covers most of what you have asked here :)

Any questions, just ask.

This post has been edited by CodingSup3rnatur@l-360: 22 January 2012 - 05:06 PM
Reason for edit:: Added clarification on the add/remove bit

Was This Post Helpful? 14
  • +
  • -

#5 jens  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 67
  • View blog
  • Posts: 430
  • Joined: 09-May 08

Re: Why events, and what are they?

Posted 24 January 2012 - 11:31 AM

Thank you so much for an excellent answer with pedagogical explanations!

Answers as yours, that explain why things are the way they are and not only how to use a feature, gives me so much understanding.

The only thing I didn't catch was the part on how the event from e.g. button click is raised. In my own code I do this:

    // fire our custom event
    StartEvent();                               //#5



But where would I find the clickMe.Click(); that fires that event?

Thanks
Jens

This post has been edited by jens: 24 January 2012 - 11:34 AM

Was This Post Helpful? 0
  • +
  • -

#6 lordofduct  Icon User is offline

  • I'm a cheeseburger
  • member icon


Reputation: 2538
  • View blog
  • Posts: 4,641
  • Joined: 24-September 10

Re: Why events, and what are they?

Posted 24 January 2012 - 02:26 PM

You don't actually receive direct access to fire an event defined in a class you don't have direct access to.

Of course child classes may want to fire events defined in the super class it may inherit from. The super class in this case will usually uncover a protected method to call for doing so. The 'standard' name of it will be:

On*EventName*

Such as the protected method of a Control which is:

Control.onclick
http://msdn.microsof...ol.onclick.aspx

You can now fire the Click event from a child class of Control (or Button as Button's are Controls). It is kept 'protected' so as not to break encapsulation... the whole point of events in the first place. If it were public, well than a 'delegate' would have sufficed in the first place.




NOTE! - the 'On*EventName*' methods by standard tend to be virtual to allow a child class to easily override and perform actions with out actually attaching a delegate to the event. This is just extra functionality added to it, and is merely tangential to the origin of the method in the first place.

This post has been edited by lordofduct: 24 January 2012 - 02:29 PM

Was This Post Helpful? 1
  • +
  • -

#7 CodingSup3rnatur@l-360  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 992
  • View blog
  • Posts: 972
  • Joined: 30-September 10

Re: Why events, and what are they?

Posted 24 January 2012 - 04:51 PM

*
POPULAR

I gave you the simple, stripped down way to think about the button click event in my above post. However, with Winform controls, the reality is slightly more complicated due to the large number of events that each control has. Extra code is in place to account for this.

However, the short answer to your question is that the code that the Click event will be found in the Control class, of which Button is a sub class. It is the Control class that ultimately invokes/raises the event, and that is where you will find code similar to that that you posted in your last post.


The longer answer...

The Button class ultimately inherits from the Control class, and it is the Control class that actually defines the Click event.

Now, you'll note from my first post that the event field (public event StartDelegate myEvent;) is automatically expanded for us into the add/remove property like structure by the compiler. However, we can write that add/remove code ourselves, if we want. So, instead of this:

public event StartDelegate myEvent;


(which would give the compiler the cue to generate the private StartDelegate delegate backing field, the add/remove pair of methods etc) we can do this in our code directly:

public event StartDelegate myEvent
{
    add
    {
        //we can add our own custom code here
    }

    remove
    {
       //we can add our own custom code here
    }
}



The Control class uses the second approach of defining an event, and adds its own code to the add/remove methods, rather than letting the compiler generate the private delegate fields, and the code in the add/remove methods (we'll get to possible reasons for this later). This means that the Control class has to be manage the delegate for each event itself also, as the compiler will no longer generate the delegate backing field automatically.

So, in the Control class, there is the event definition:

public event EventHandler Click
{
    add
    {
        base.Events.AddHandler(EventClick, value);
    }
    remove
    {
        base.Events.RemoveHandler(EventClick, value);
    }
}




That is the Click event, in all its glory.

So, in your code, when this line:

clickMe.Click += new EventHandler(eHandler); 


is executed, this line from the Control class is executed:

base.Events.AddHandler(EventClick, value);



So, what is that line doing?

Well, the Control class inherits from the Component class, and the Component class defines a field that looks like this:

private EventHandlerList events;



which is accessed through this property in the Component class:

protected EventHandlerList Events
{
        get
        {
            if (this.events == null)
            {
                this.events = new EventHandlerList(this);
            }
            return this.events;
        }
}




It is that property is being accessed in the custom add/remove parts in the Control class (shown further up the page).



What is this EventHandlerList?

The EventHandlerList class is, very simply, a singularly linked list of delegates. It is the delegates in this list that back the events of the WinForm controls (click, enter, enabled etc), and hold the list of methods to call when each event is fired. So, instead of letting the compiler generate delegate fields automatically as I described in my first post, the Component class chooses create, and manage the delegates for each event itself, in a list.

This is what AddHandler() looks like, in the EventHandlerList class:

public void AddHandler(object key, Delegate value)
{
    ListEntry entry = this.Find(key);
    if (entry != null)
    {
        entry.handler = Delegate.Combine(entry.handler, value);
    }
    else
    {
        this.head = new ListEntry(key, value, this.head);
    }
}



Remember, when we subscribe to the Click event, the add part of the event is called in the Control class, and that then calls AddHandler(), passing in key that can be used to uniquely identify the Click event's delegate in the list. This key will allow the delegate to be found and retrieved from the linked list, once it has been added. We also pass in the new EventHandler delegate, from this line:
clickMe.Click += new EventHandler(eHandler);
.

As you can see, AddHandler() first tries to find a delegate with the Click event key. If it finds one, it calls Delegate.Combine() (which, remember, is equivalent to the += operator) to add the new delegate to the invocation list of the click event delegate found in the linked list. If it doesn't find one, it adds the new delegate to the list.


The net result of all that is that you end up with a list of delegates. Each WinForm control event can have a single delegate entry in the list, and when we use +=, we are adding the new delegate on the right hand side of += to the invocation list of the relevant delegate in the linked list, if it exists. If it doesn't exist, we add the delegate on the right hand side of += to the list.



How/where is the click event actually raised then?

Well, there is a method in the Button class is called onclick() that is used to raise the Click event. That method calls the onclick method in the Control class. That method in the Control class looks like this:

protected virtual void onclick(EventArgs e)
{
    EventHandler handler = (EventHandler) base.Events[EventClick];
    if (handler != null)
    {
        handler(this, e);
    }
}



As you can see, handler(this, e) is the line that actually raises the Click event. This bit:

(EventHandler) base.Events[EventClick];


is going to the EventHandlerList (via an indexer) in the Component class, and picking out the delegate that has the EventClick key (the unique object that identifies the Click event delegate in the list).


Apart from the way that the delegate is retrieved, that is a bog standard implementation of a method to raise an event :)

The Click event is defined in the Control class, and is ultimately raised just like any other event.



How does the Control class know when to raise the Click event?

The operating system sends a WM_LBUTTONUP message to to a window when the left mouse button is released whilst the cursor is on a window (a window is any control; button, form etc). That message will be picked up by the window procedure of the control. When the Control class sees this message in its message queue, it takes various actions, and ends up calling onclick(), which raises the Click event. I think that is the message that is used to identify the button clicks.



Why use EventHandlerList, and write custom boilerplate code to manage the events?

So, the question is, why go to all this trouble, when they could have just defined the events individually with simple delegate fields, and let the compiler generate the required boiler plate code, and delegate fields?

Well, I would guess it has to do with the sheer number of events (there are 55+) that are associated with each WinForm control. There are many different events, and holding the backing delegates in a list helps manage this mass of events in an efficient and maintainable way, and adds flexibility by giving Microsoft the freedom to manage the backing delegates as they wish, without relying on the compiler to generate the code for them. When you have that many events floating around a class, I suppose it is good to be able to have tight control over how they are managed.

On key point when trying to understand why Microsoft implemented the WinForm controls event system like this is that the backing delegate for an event is created and added to the list, only when you subscribe to said event. If you do not subscribe to an event, no delegates are ever created, no delegate fields are needed in the classes, and no EventHandlerList object is created. Contrast this to defining the events individually, and letting the compiler generate the boiler plate code. In that case, the compiler would generate a backing delegate field for every event, whether you wanted/needed them or not! Therefore, dynamically creating the delegates as and when they are needed, and using a list to store them, could help minimize the memory footprint of controls, particularly when you think about the number of controls that a typical application uses, and the number of events each of those controls have.

You'll also notice that there is no thread synchronization code in the Click event definition in the Control class (lock() statements). As all UI controls should be accessed from a single thread, the thread synchronization code that the compiler would add would have added necessary overhead. By managing the events themselves (by implementing the add/remove method themselves), Microsoft can avoid this.


That may be a lot to take in, and I haven't had much time tonight so I may not have explained myself very well in places. Once again, feel free to ask for clarification on anything :)
Was This Post Helpful? 5
  • +
  • -

#8 RexGrammer  Icon User is offline

  • Coding Dynamo
  • member icon

Reputation: 182
  • View blog
  • Posts: 783
  • Joined: 27-October 11

Re: Why events, and what are they?

Posted 25 January 2012 - 04:13 AM

Wow, you really have a lot of free time... :D
But man kudos to you, you could be a professor.

This post has been edited by RexGrammer: 25 January 2012 - 04:13 AM

Was This Post Helpful? 0
  • +
  • -

#9 CodingSup3rnatur@l-360  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 992
  • View blog
  • Posts: 972
  • Joined: 30-September 10

Re: Why events, and what are they?

Posted 25 January 2012 - 12:30 PM

View PostRexGrammer, on 25 January 2012 - 11:13 AM, said:

Wow, you really have a lot of free time... :D


Oh, how I wish that was true ;)

Quote

you could be a professor.


I don't know about that, but thanks! :)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1