C# events are actually accessors

By admin - Last updated: Wednesday, October 15, 2008 - Save & Share - Leave a Comment

An interesting feature of C# I discovered recently is that events are actually accessors into Multicast Delegates, much like properties are accessors into other fields.

private string myData;
public string MyData // A property
{
  get { return myData; } // called when the property is read
  set { myData = value; } // called when the property is written to
}
 
private EventHandler myDataChanged;
public event EventHandler MyDataChanged // An event
{
  add { myDataChanged = (EventHandler)Delegate.Combine( myDataChanged, value ); } // called when a handler is attached
  remove { myDataChanged = (EventHandler)Delegate.Remove( myDataChanged, value ); } // called when a handler is detached
}

A vanilla event declaration, without the accessors, does this internally. It also acquires a lock every time it accesses the EventHandler to be thread safe, which we’re not doing here, and you should, if you need the safety.

A great application of this is to simulate “bubble” events in WinForms like in ASP.NET. Take for example a form with a user control with a button in it. If I wanted to receive the button’s click event on the form, I would have to either expose the button, or handle its event in the control, and raise a different one on the control:

public class MyControl : UserControl
{
  public event EventHandler MyButtonClick;
  Button btn;
 
  public MyControl()
  {
    btn = new Button();
    btn.Click += new EventHandler( btn_Click );
  }
 
  private void myBtn_Click( object sender, EventArgs e )
  {
    if ( MyButtonClick != null )
      MyButtonClick( sender, e );
  }
}
 
public class MyForm : Form
{
  MyControl ctl;
 
  public Form()
  {
    ctl = new MyControl();
    ctl.MyButtonClick += new EventHandler( ctl_MyButtonClick );
  }
 
  private void ctl_MyButtonClick( object sender, EventArgs e )
  {
    // Button clicked on the control!
  }
}

This can get rather bothersome and ugly if you have many buttons. Using an event accessor you can take the handler and attach it to anything you like, so you can just pass-through the handler directly to the button(s).

public class MyControl : UserControl
{
  Button btn;
 
  public MyControl()
  {
    btn = new Button();
  }
 
  public event EventHandler MyButtonClick
  {
    add { btn.Click += value; }
    remove { btn.Click -= value; }
  }
}

There’s one caveat to this technique, and that’s when you handle the event somewhere upstream, the “sender” would be the button, not the MyControl. This might break encapsulation, and if that’s important to you, the handle/re-raise method is the way to go.

Posted in C# • Tags: , , Top Of Page

Write a comment

Currently you have JavaScript disabled. In order to post comments, please make sure JavaScript and Cookies are enabled, and reload the page. Click here for instructions on how to enable JavaScript in your browser.