carlAlex
8/10/2016 - 7:37 AM

C# event - stackoverflow.com

C# event - stackoverflow.com

To understand event handlers, you need to understand delegates. In C#, you can think of a delegate as a pointer (or a reference) to a method. This is useful because the pointer can be passed around as a value.

The central concept of a delegate is its signature, or shape. That is (1) the return type and (2) the input arguments. For example, if we create a delegate void MyDelegate(object sender, EventArgs e), it can only point to methods which return void, and take an object and EventArgs. Kind of like a square hole and a square peg. So we say these methods have the same signature, or shape, as the delegate.

So knowing how to create a reference to a method, let's think about the purpose of events: we want to cause some code to be executed when something happens elsewhere in the system - or "handle the event". To do this, we create specific methods for the code we want to be executed. The glue between the event and the methods to be executed are the delegates. The event must internally store a "list" of pointers to the methods to call when the event is raised.* Of course, to be able to call a method, we need to know what arguments to pass to it! We use the delegate as the "contract" between the event and all the specific methods that will be called.

So the default EventHandler (and many like it) represents a specific shape of method (again, void/object-EventArgs). When you declare an event, you are saying which shape of method (EventHandler) that event will invoke, by specifying a delegate:

***Below example***
(*This is the key to events in .NET and peels away the "magic" - an event is really, under the covers, just a list of methods of the same "shape". The list is stored where the event lives. When the event is "raised", it's really just "go through this list of methods and call each one, using these values as the parameters". Assigning an event handler is just a prettier, easier way of adding your method to this list of methods to be called).
using System;

class Observable
{
    public event EventHandler SomethingHappened;

    public void DoSomething()
    {
        EventHandler handler = SomethingHappened;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

class Observer
{
    public void HandleEvent(object sender, EventArgs args)
    {
        Console.WriteLine("Something happened to " + sender);
    }
}

class Test
{
    static void Main()
    {
        Observable observable = new Observable();
        Observer observer = new Observer();
        observable.SomethingHappened += observer.HandleEvent;

        observable.DoSomething();
    }
}
public class Mother
{
 //Child object reference
 Baby _billy;
 
 public Mother()
 {
  //Child object
  _billy = new Baby();
 
  //Registering for a call back or listening for the baby to cry
  _billy.Cry += Billy_CryHandler;
 
  //Put the baby to sleep, the baby will wake up eventually
  _billy.Sleep();
 }
 
 //When the baby is awoken, you need to ask the baby 
 //why it woke up and put it back to sleep
 private void Billy_CryHandler(object sender, CryEventArgs e)
 {
  //The reason was passed over using our custom event argument object
  Console.WriteLine("Why are you awake Billy? - " + e.Reason + "n");
  
  Console.WriteLine("Billy, go back to sleep!n");
 
  //Put the baby back to bed
  _billy.Sleep();
 }
}
 
public class Baby
{
 //The model method that will be called when the event is raised "Call me back at"
 public delegate void CryHandler(object sender, CryEventArgs e);
 
 //The way that you can register for a call back
 public event CryHandler Cry;
 
 Random _r;
 
 public Baby()
 {
  _r = new Random();
 }
 
 public void Sleep()
 {
  //Get a value between 0 and 10 - which is indeterminate enough for this example
  int sleep = _r.Next(10);
 
  //Announce that the baby will be put back to bed
  Console.WriteLine("Baby will be sleeping for " + sleep + " seconds.n");
 
  //Long running process
  System.Threading.Thread.Sleep(sleep * 1000);
 
  //Callback when the baby wakes up
  RaiseCryEvent(new CryEventArgs() { Reason = "I pissed myself again..." });
 }
 
 private void RaiseCryEvent(CryEventArgs e)
 {
  //This is syntactic sugar - a one liner that replaces 
  //the if statement in the prior example
  Cry?.Invoke(this, e);
 }
}

//This delegate can be used to point to methods
//which return void and take a string.
//***PUBLISHER***
public delegate void MyEventHandler(string foo);

//This event can cause any method which conforms
//to MyEventHandler to be called.
///***PUBLISHER***
public event MyEventHandler SomethingHappened;

//Here is some code I want to be executed
//when SomethingHappened fires.
//***SUBSCRIBERS "RESPONSE"***
void HandleSomethingHappened(string foo)
{
    //Do some stuff
}

//I am creating a delegate (pointer) to HandleSomethingHappened
//and adding it to SomethingHappened's list of "Event Handlers".
//***SUBSCRIBER "SUBSCRIBING" TO THE EVENT***
myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened);
public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click = delegate {}; // add empty delegate!

//Let you do this:
public void DoSomething() {
    Click(this, "foo");
}

//Instead of this:
public void DoSomething() {
    if (Click != null) // Unnecessary!
        Click(this, "foo");
}