default .net event handler

In my product I need process events. For this, I used the following code:

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

Now let's say that I have a WinForms user interface. In the form code, I will subscribe to this event and process it by default (for example, using the System.Windows.Forms.MessageBox.Show () method). Now the question is, how can I allow the user to create a derived form and override the default implementation of the Message event handler?

Only subscribing to an event for the second time with a custom implementation does not solve the problem (both event handlers will be executed and, possibly, two message windows will be displayed). Possible options:

 //call OnSubscribeToMessageEvent() from either form 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 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 other options?

+4
source share
5 answers

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

Yes, you are right to worry about it. These types of event subscriptions are very inconsistent, the event source always allocates a subscriber. There is only one class within the framework that I know does this, SystemEvents. The problem is that each subscriber must very carefully unsubscribe when his life ends, or the object will constantly refer to him. A memory leak that is very difficult to diagnose.

It is best to use an interface. Let one declare:

 public class MyEventArgs { /* etc.. */ } public interface IGlobalNotification { event EventHandler Disposed; void OnMessage(MyEventArgs arg); } 

Now you have the opportunity to implement the interface 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 run the OnMessage () method on all instances of the live form. The main advantage of this approach is that the client programmer can never mess up.

+3
source

I would let the derived class override Global_Message . Subscribing to the event is general and why do you want to implement it again in every child? It also gives you the ability to call base.Global_Message(sender, e) if your child class just wants to add some decoration to it and use the default behavior otherwise.

+2
source

I would prefer your second example, since classes extending your base class should only override one method and should not remove the handler added by the base class from the event.

0
source

The key adds the virtual keyword , so that the derived type can override the method, and instead the method that they created will be called.

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

Now that you have added a virtual one for both, I would go with the first one and redefine the one that subscribes to this event if they do not want to subscribe to the event.

Although there is another option, call it # 3.

 protected EventHandler GlobalMessageEvent = new EventHandler<MyEventArgs>(Global_Message); protected virtual void OnSubscribeToMessageEvent() { // this could be done in the Form_Load() or constructor instead. Global.Message += GlobalMessageEvent; } 

Then a potentially inherited class could do somewhere: (note the - = )

 { Global.Message -= GlobalMessageEvent; } 
0
source

All Articles