Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.net default event handler

In my product I need process wide events. For that I used code like this:

public class Global
{
    public static event EventHandler<MyEventArgs> Message;
    public static void ShowMessage();
}

Now let's say I have a WinForms user interface. In form's code I will subscribe to this event and handle it in some default way (eg. by using System.Windows.Forms.MessageBox.Show() method). Now the question is how do I allow user to create derived form and override my default Message event handler implementation?

Just subscribing to the event for the second time with custom implementation doesn't solve the problem (both event handlers would be executed and potentially two message boxes shown). The options I see are either:

//call OnSubscribeToMessageEvent() from either form's constructor or OnLoad event handler
protected virtual void OnSubscribeToMessageEvent()
{
    Global.Message += new EventHandler<MyEventArgs>(Global_Message);
}
private void Global_Message(object sender, MyEventArgs e)
{
    //my default implementation
}

or

//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
    //my default implementation
}

Which version is better and why? Or maybe there are any other options?

like image 943
Tomasz Grobelny Avatar asked Apr 25 '11 22:04

Tomasz Grobelny


People also ask

Which is default event of button in C#?

For example, default event for the button control is the Click event.

What are C# event handlers?

An event handler, in C#, is a method that contains the code that gets executed in response to a specific event that occurs in an application. Event handlers are used in graphical user interface (GUI) applications to handle events such as button clicks and menu selections, raised by controls in the user interface.

How are events handled in a .NET environment?

Event handling is familiar to any developer who has programmed graphical user interfaces (GUI). When a user interacts with a GUI control (e.g., clicking a button on a form), one or more methods are executed in response to the above event. Events can also be generated without user interactions.

How do you call an event handler in C#?

Invoke(this, e); handler(this, e) will call every registered event listener. Event listeners subscribe with help of the += operator and unsubscribe with -= operator to that event. this is there to give the event listener to know who raised the ThresholdReached event.


2 Answers

I still have some doubts as I have never seen such a design pattern in any .NET library

Yes, you're right to worry about this. These kind of event subscriptions are very fickle, the event source always outlives the subscriber. There's only one class in the framework I know that does this, SystemEvents. The problem is that every subscriber has to very carefully unsubscribe itself when its lifetime ends or the object will stay referenced forever. A memory leak that's very hard to diagnose.

A better pattern here is to use an interface. Let's declare one:

public class MyEventArgs { /* etc.. */ }

public interface IGlobalNotification {
    event EventHandler Disposed;
    void OnMessage(MyEventArgs arg);
}

Now you can have a form implement the interface:

public partial class Form1 : Form, IGlobalNotification {
    public Form1() {
        InitializeComponent();
        GlobalMessages.Register(this);
    }

    void IGlobalNotification.OnMessage(MyEventArgs arg) {
        // do something
    }
}

The Register method registers the form with the GlobalMessages class, the Dispose event ensures that the class can detect that the form is dying:

public static class GlobalMessages {
    public static void Register(IGlobalNotification listener) {
        listener.Disposed += delegate { listeners.Remove(listener); };
        listeners.Add(listener);
    }
    public static void Notify(MyEventArgs arg) {
        foreach (var listener in listeners) listener.OnMessage(arg);
    }

    private static List<IGlobalNotification> listeners = new List<IGlobalNotification>();
}

Call GlobalMessages.Notify() to get the OnMessage() method to run in all live form instances. The major advantage of this approach is that a client programmer can never screw up.

like image 169
Hans Passant Avatar answered Oct 04 '22 12:10

Hans Passant


I would let the derived class override the Global_Message. The subscription to the event is generic and why would you want to implement it in every child again? It also gives you the option to call base.Global_Message(sender, e) in case your child class just wants to add some decoration to it and use the default behaviour otherwise.

like image 29
ChrisWue Avatar answered Oct 04 '22 12:10

ChrisWue