Click here to Skip to main content
16,018,394 members
Articles / Programming Languages / C#
Article

How to route events in a Windows Forms application

Rate me:
Please Sign up or sign in to vote.
4.61/5 (17 votes)
17 Jul 2005CPOL2 min read 113.4K   2K   67   16
An article about routing events in a Windows Forms application.

Sample Image

Introduction

To receive a button click notification, you simply hook up an event handler to your button's Click event, providing you have a reference to the button. This is very straightforward if the button is directly embedded in the form where the Click notification needs to be handled. But how do you add an event handler to a button that is embedded in another control, say a UserControl. Adding a notification handler to that control's Click event will notify your event handler only if that control was clicked. There is little need to be notified when the mouse is clicked over a UserControl or Form.

Event handlers are normally assigned across one level of the control hierarchy, from the Form directly to a button or from a UserControl directly to a button. To assign an event handler from a Form to a button that is embedded in another control is not a straightforward affair. One way to accomplish it would be to expose the button from the UserControl to the Form. But this a rather awkward thing to do if the button was nested many layers deep. A much better way is to override the Click event in the embedding control and redirect the captured Click event up the food chain. This article describes such a technique. I am using the Button and its Click event as a model to demonstrate how to route an event to its final target.

Overriding a Control's event

Let us construct a demo application where two buttons are placed into a user control and the the user control is placed into a form. The button's Click events are ultimately processed by the form's event handlers. So, the routing needs to be built into the user control. Take a look at the following code snippet:

C#
// code snippet for UserControl

// normal event registration with the button
this.button1.Click += new System.EventHandler(this.button1_Click);

// the wrong implementation of the UserControl's event handler
private void button_Click(object sender, System.EventArgs e)
{
    /*
        this will publis the click event further up the chain but 
        the subscribers will learn that the sender is this UserControl
        which is definitely not what we want
    */ 
    base.OnClick(e);
} 

// the correct implementation if the UserControl's event handler
private void button_Click(object sender, System.EventArgs e)
{
    /*
        Implementation of EventHandlerDelegate to explained
    */
    if(this.EventHandlerDelegate != null)
        this.EventHandlerDelegate(sender, e);
}

The EventHandlerDelegate represents the overridden Click event of the Button. The code that overrides it looks like this:

C#
public class UserControl1 : System.Windows.Forms.UserControl
{     
        // define an event handler delegate which basically re-uses an existing
        // signature
        public delegate void EventHandler(object sender, System.EventArgs e);
        // decalre an event handler delegate
        EventHandler EventHandlerDelegate;
        // re-define the Click event
        new public event EventHandler Click
        { 
            // this is the equivalent of Click += new EventHandler(...)
            add 
            {   
                this.EventHandlerDelegate += value;
            }
            // this is the equivalent of Click -= new EventHandler(...)
            remove
            {
               this.EventHandlerDelegate -= value;
            }
        }
        
        // the rest of the code not shown
}

Instrumenting the UserControl in this way permits the Form to assign its event handlers like so:

C#
this.userControl1.Click += new 
  EventRouting.UserControl1.EventHandler(this.userControl1_Click);

Event routing also requires some participation by the event consumers to indicate the handling of the event. One other UserControl implementation demonstrates an event dispatcher that stops dispatching the events as soon as one consumer indicates that the events were handled.

C#
// redefine the EventArgs class
public class EventArgs : System.EventArgs 
{
    bool handled;
    // the event consumer should set it to 'true'
    // to indicate that the event was handled
    public bool Handled 
    {
        get { return this.handled; }
        set { this.handled = value; }
    }
}

private void button2_Click(object sender, System.EventArgs e)
{
    if(this.EventHandlerDelegate != null)
    {
        // prepare the arguments for dynamic invokation
        EventArgs e2 = new EventArgs();
        // pass along this new EventArgs object

        object[] args = new object[] { sender, e2 };
        
        // get every event handler and invoke it dynamically
        foreach(Delegate handler in 
            this.EventHandlerDelegate.GetInvocationList())
        {
            handler.DynamicInvoke(args);
            if(e2.Handled)
                break;
        }
    }
}

This whole concept is very simple. Just download the code, compile it and observe the show. You can apply this technique for any kind of events including the ones defined by you.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
I am a consultant, trainer, software archtect/engineer, since the early 1980s, working in the greater area of Boston, MA, USA.

My work comprises the entire spectrum of software, shrink-wrapped applications, IT client-server, systems and protocol related work, compilers and operating systems, and more ....

I am currently focused on platform development for distributed computing in service oriented data centers.

Comments and Discussions

 
Questionthanks, helped me Pin
Paul Bauer5-Dec-14 1:14
Paul Bauer5-Dec-14 1:14 
QuestionThanks dude Pin
BiffaBacon26-Sep-12 12:44
BiffaBacon26-Sep-12 12:44 
GeneralThanks very much. Pin
egoer13-May-10 0:59
egoer13-May-10 0:59 
Questionwhat about Pin
Zap-Man24-May-08 10:32
Zap-Man24-May-08 10:32 
QuestionHow can one contact Wytek Szymanski, the author of this arcticle? Pin
YossiMimon2-May-08 0:04
YossiMimon2-May-08 0:04 
GeneralThanks Pin
bilmuhalper12-Mar-07 5:45
bilmuhalper12-Mar-07 5:45 
GeneralUse a Controller Class Pin
Frank W. Wu26-Jul-05 4:57
Frank W. Wu26-Jul-05 4:57 
GeneralHmmm Pin
Maximilian Hänel25-Jul-05 21:57
Maximilian Hänel25-Jul-05 21:57 
GeneralUse the new keyword with care Pin
jmservera25-Jul-05 20:31
jmservera25-Jul-05 20:31 
GeneralSure, but... Pin
Girb18-Jul-05 0:20
Girb18-Jul-05 0:20 
GeneralRe: Sure, but... Pin
Wytek Szymanski18-Jul-05 15:52
Wytek Szymanski18-Jul-05 15:52 
GeneralRe: Sure, but... Pin
Girb18-Jul-05 19:40
Girb18-Jul-05 19:40 
GeneralRe: Sure, but... Pin
Khorne24-Apr-06 0:04
Khorne24-Apr-06 0:04 
GeneralRe: Sure, but... Pin
Sebrell18-Aug-06 10:03
Sebrell18-Aug-06 10:03 

You could also implement it as follows:
<span style="color:green;">// in UserControl1.cs</span>
<span style="color:blue;">public event</span> EventHandler Button1Click {
<span style="color:blue;">    add</span> {
<span style="color:blue;">        this</span>.button1.Click += <span style="color:blue;">value</span>; 
    }
<span style="color:blue;">    remove</span> { 
<span style="color:blue;">        this</span>.button1.Click -= <span style="color:blue;">value</span>; 
    }
}

Note that in this scenario the value of the "sender" argument resolves to the button, not the user-control. But it eliminates the need to re-write inherited events, and allows you to propagate the event-bubble upwards through the control hierarchy indefinitely.

QuestionThanks man !Multiple events? Pin
Trance Junkie17-Jul-05 22:06
Trance Junkie17-Jul-05 22:06 
GeneralThanks man ! but.... Pin
Trance Junkie17-Jul-05 22:05
Trance Junkie17-Jul-05 22:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.