Static Events for Decoupling Communication Between Classes/Forms/Controls in C#
So I’m new to C#, but I have to admit that the ‘simple’ examples out there really aren’t simple and they really don’t cover what I would consider to be the most common use for events: Communication between forms and controls without having to resort to directly linking one class to another. I’ve been using Cairngorn Events/Delegates for awhile now in Flex/ActionScript3, so I’m not coming at it from a complete novice standpoint. But it seems every example I could find only showed how to raise and use events within the creator of the event. None of them showed how to use events to decouple, or reduce the linkage and increase the usability of your code.
So here goes: Imagine if you will, that you have several forms on your application and you want to allow the user to exit from any of them, while still doing that last minute clean up like saving any data or config, etc. ( I realize there is a way to do this using the Application event handler, but this technique applies all over the place, and this example is easy to understand.)
So first you want to create your event class. I put mine in a handy folder called Events in my C# project.
using System;
namespace Demo.Events
{
// Declare a delegate for an event.
public delegate void ExitAppHandler(object sender);
// Declare an event class.
class AppExitEvent
{
public static event ExitAppHandler evtExitApp;
// This is called to fire the event.
public static void OnExitEvent()
{
// ok so this calls the handlers we have +='d to listen the event
if (evtExitApp != null)
evtExitApp(null);
}
}
}OK, so this sets up a separate event class that has a static handler variable and a static method. This is the glue between our classes. Now we can reuse a form that calls this event, without having to worry about any other code.
Now we want to listen to this in our forms that want to do something when this event is triggered.
namespace Demo {
public partial class Demo : Form
{
public Demo()
{
Events.AppExitEvent.evtExitApp += new Events.ExitAppHandler(this.ExitEventHandler);
InitializeComponent();
}
// An event handler.
private void ExitEventHandler(object sender)
{
// TODO: Do cleanup/save/etc
this.Close();
}
}
}This could be your main application form for instance, with a lot of other stuff going on in this class, like adding controls, etc. Multiple forms that need to respond to the exit event would simply do the same thing: Add Events.AppExitEvent.evtExitApp += new Events.ExitAppHandler(this.ExitEventHandler); to their class/form, along with an ExitEventHandler method.
Now all we need to do is show another form/control/class calling this as well. In my case, this is a custom toolbar, or a sub form’s right click menu:
namespace Demo
{
public partial class Caller : UserControl
{
public Caller()
{
// If you wanted to have this form respond to the exit event as well, you could simply uncomment this
// Events.AppExitEvent.evtExitApp += new Events.ExitAppHandler(this.ExitEventHandler);
InitializeComponent();
}
// this is in response to a button click NOT SHOWN
private void pbExit_Click(object sender, EventArgs e)
{
Events.AppExitEvent.OnExitEvent();
}
}
}
And finally, we show how to call this static event:
Events.AppExitEvent.OnExitEvent();
This is called in response to a button click, that button not shown in this example, but you should hopefully get the idea. I’ve also shown commented out, that this other form could also be a consumer of the same exit event if you wanted.
That does it! I needed another similar event to occur when I minimized the app, and when I wanted to open a popup form from a number of different locations, so this technique is very useful.
Obviously, the above example doesn’t really show how to pass additional info with the event, like mouse coordinates or other data.
To do that you would need to create a class derived from EventArgs (CustomEventArgs let’s say) that held your custom data, and change the declarations to add in your custom event args. The existing examples out there show this aspect pretty well.