Ive implemented an event in a object like this:
public class BaseObject
{
public delegate void NavigateHandler(object sender, EventArgs e);
public virtual event NavigateHandler Navigate;
A child og that base tries to invoke it:
public class ChildObject : BaseObject
{
private void DoNavigate()
{
Navigate(null, null);
This part above is broken, VS2012 tells me that I cant use Navigate in that manner.
However, it works fine to "hook" on that event if I instansiate a object of ChildObject:
ChildObject obj = new ChildObject();
obj.Navigate += foo_Navigate;
Where did I go wrong? I want to trigger that navigate event in the DoNavigate method.
You are only allow to invoke events from within the class that defines it.
If you want to allow sub-classes to fire the event then create a protected method (by convention it would be called OnNavigate) that fires the event and that can be accessed from implementing classes.
Related
I'm working on a project where I'm actually using inherited controls with some automated behaviour so I don't need to re-do all the job. The controls are being inherited from DevExpress controls and I've got access to the inherited controls.
I reached a point where an event was being raised and subscribing to my own method was showing no results because the inherited control executed its own code.
Inherited control:
private void BinaryGridView_InvalidRowException(object sender, InvalidRowExceptionEventArgs e)
{
e.ExceptionMode = DevExpress.XtraEditors.Controls.ExceptionMode.NoAction;
DevExpress.XtraEditors.XtraMessageBox.Show(e.ErrorText, "Atención", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Own method in my form:
grwWhatever.InvalidRowException += (s, e) => { e.ExceptionMode = ExceptionMode.NoAction; };
According to the documentation, I was trying to hide any message box and of course, as my inherited control source says, it was showing that message box.
So, reaching that point I guess had two options:
1.- Inheriting from that inherited control, changing the private to protected virtual and overriding that behaviour. This wasn't a choice since, for reasons I couldn't explain here I must use uniquely those inherited controls.
2.- Changing the private to public, so I could unsubscribe and subscribe again, afterwards:
grwWhatever.InvalidRowException -= grwWhatever.BinaryGridView_InvalidRowException;
grwWhatever.InvalidRowException += (s, e) => { e.ExceptionMode = ExceptionMode.NoAction; };
This 2nd option is actually working fine but... let's guess none of them are doable. Changing the content of the inherited control's event is not a possibility. Leaving a part the inherited control's usage design... Which would be the best way to proceed? Could it be done using Reflection?
The right solution should be changing the code in the base class. But since you have mentioned you don't have access to change the code of base class, and a solution using reflection is also acceptable, here I will share an example using reflection, for learning purpose.
Remove private event handler subscription from base class
I assume I have a base class called MyBaseForm and you have handled Load event using MyBaseForm_Load private method in the base class.
In this example, in a derived class MyDerivedForm which is derived from base class, I use some reflection code to remove the MyBaseForm_Load event subscription and instead, I handle the event using a new handler in the derived class MyDerivedForm_Load.
The expected behavior:
Before removing the event handler, you will see two message boxes
After removing the event handler using eventInfo.RemoveEventHandler, you will see just a single message box, from the derived class event handler.
Here is the code:
public class MyBaseForm : Form
{
public MyBaseForm()
{
this.Load += MyBaseForm_Load;
}
private void MyBaseForm_Load(object sender, EventArgs e)
{
MessageBox.Show("MyBaseForm_Load");
}
}
public class MyDerivedForm : MyBaseForm
{
public MyDerivedForm()
{
var eventInfo = this.GetType().GetEvent("Load",
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Instance);
var delegateType = eventInfo.EventHandlerType;
eventInfo.RemoveEventHandler(this,
Delegate.CreateDelegate(delegateType, this, "MyBaseForm_Load", false, true));
this.Load += MyDerivedForm_Load;
}
private void MyDerivedForm_Load(object sender, EventArgs e)
{
MessageBox.Show("MyDerivedForm_Load");
}
}
I am trying to understand for which purpose the events pattern decided that the method that fires the event should be declared virtual.
From C#6 in a Nutshell, from Joseph and Ben Albahari, O'Reilley:
Finally, the pattern requires that you write a protected virtual method that fires the
event. The name must match the name of the event, prefixed with the word On, and
then accept a single EventArgs argument:
Below a snippet I created to try to investigate.
I had the impression that the idea was to allow inheriting classes to completely overwrite how the event is handled, out of the box (original class). But the snippet below shows this is not possible, because deriving classes will never be able to invoke the event objects themselves (by the one one of the goals of the constraints imposed by the keyword event on delegates). The event can be invoked only in the containing class.
Now, since the pattern also asks that the method that fires the event simply check if the the event is not null and then call the delegate, with whatever every subscriber asked to do, what is left to be achieved by having the method that fires the event as virtual ? Inheriting classes are obliged to invoke the event the way it is in the broadcaster class, so all that is left for them is to add functionality. But this is exactly what they can achieve by subscribing to the event, in other words, by adding a call to an external function the time the event is fired.
I hope my wording is clear enough.
namespace eventsPatternVirtualEventFirerer
{
internal class Program
{
private static void Main(string[] args)
{
var obj = new X();
obj.ev += Obj_ev;
obj.Start();
}
private static void Obj_ev(object sender, EventArgs e)
{
Console.WriteLine("subscriber code...");
}
}
public class X
{
public event EventHandler<EventArgs> ev;
protected virtual void OnEvent(EventArgs e)
{
Console.WriteLine("original implementation...");
ev?.Invoke(this, e);
}
public void Start()
{
OnEvent(EventArgs.Empty);
}
}
public class X2 : X
{
public X2()
{
}
protected override void OnEvent(EventArgs e)
{
Console.WriteLine("inheriting class implementation overwrite...");
//compilation error - "the event 'X.ev' can only appear on the left hand side of += or -= (except when used from within the type 'X')"
ev?.Invoke(this, e);
}
}
}
I think the purpose is to allow derived classes to do something before/after the event is fired
public class X2 : X
{
public X2()
{
}
protected override void OnEvent(EventArgs e)
{
// Do something before the event
base.OnEvent(e);
// Do something after the event
}
}
There are a few things you can add/change in a derived class
Add a OnBeforeEvent / OnAfterEvent addition.
Choose not to broadcast the event (by conditionally not calling base.OnEvent(e)).
Vary the event args in some way.
Additionally, If you think about the way something like a page model works, it typically fires a Load event to notify when the page is loaded. Without a protected OnLoad method, derived classes would have to subscribe to it's own Load event to perform some action on load
public class MyPage : Page
{
protected override void OnLoad(EventArgs e)
{
// do something when the page is loaded
base.OnLoad(e);
}
}
versus:
public class MyPage : Page
{
public MyPage() : base()
{
this.Load += (sender,e) => {
// bleugh - subscribing to my own events
}
}
}
A good example might be the Paint event in Windows Forms.
// in MyButton : BaseButton : Control
void override OnPaint(object s, PaintEveargs e)
{
base.OnPaint(s, e); // Control: Draw background, BaseButton: draw border
// draw my own stuff
}
A button has several layers of base class, each drawing on top of each other.
I saw some tutorials and I couldn't understand why would they suggest to raise an event from Virtual Protected method, instead of directly, what is the difference?
public delegate void SomethingEventHandler(string s);
public event SomethingEventHandler Something;
public void Main() {
// Raising an event
OnSomething(); // Via method
Something("something"); // Directly
}
protected virtual void OnSomething()
{
Something("something");
}
See "Design Guidelines for Developing Class Libraries", Event Design:
Do use a protected virtual method to raise each event. This is applicable only to non-static events on unsealed classes, not to structures, sealed classes, or static events.
Complying with this guideline allows derived classes to handle a base class event by overriding the protected method. The name of the protected virtual (Overridable in Visual Basic) method should be the same as the event name prefixed with On. For example, the protected virtual method for an event named "TimeChanged" is named "OnTimeChanged".
⚠ Important
Derived classes that override the protected virtual method are not required to call the base class implementation. The base class must continue to work correctly even if its implementation is not called.
I guess that is mainly because of a basic principe called 'Don't Repeat Yourself' (DRY).
For example: you have to raise the NotifyPropertyChanged event when a property's value has changed. You want to do that from 10 properties in your code. You can repeat raising that event from ten methods, or call a method that does that for you. If you have to change something to the event raising, you only have to do that once.
Also, making it protected virtual gives you the opportunity to override that functionality in a derived class.
Also note that for thread-safety, your raising should look like this:
protected virtual void OnSomething()
{
EventHandler d = Something;
if (d != null)
{
d("something");
}
}
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?
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.
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.
I would prefer your second example, as that way, classes that extend your base class only have to override one method and do not have to remove the handler added by the base class from the event.
The key is adding the virtual keyword, so that a derived type can overide the method and the method they created will be called instead.
//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
Now that you've added virtual to both, I'd go with the first and override the one that subscribes to the event, if they didn't want the event subscribed to.
Though 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 potentially an inherited class could do somewhere: (note the -=)
{
Global.Message -= GlobalMessageEvent;
}
I had once a situation where I had to override the event handler in some derived class of mine. I could not unfortunately just "override" it since the implementation logic was bound strictly to that particular method implementation in the base class.
My natural idea was to first "unbind" the original event handler from the event and then to bind my own brand-new method. So I tried to use the "-=" operator like:
myObject.SomeEvent -= new EventHandler (BaseClass.SomeEventHandler)
at which point the compiler complainer that it had no access to the private method SomeEventHandler. Since the base class was a part of the library I did not really want to modify its implementation (though simply as it seems by just turning "private" into "protected");
It's so simple to attach an event handler to an event. Why is it so difficult to get rid of one?
Why I wanted it? Because the base implementation was casing some problems (just did not handle our particular case) so I wanted to redefine it. But even after I attached my event handler the base implementation was getting executed anyway. Since it was doing some kind of Redirect, my own implementation was never going to run since the request processing was being broken at server after redirect.
Is there anyway to get rid of an event handler in a base class from a library without modifying its implementation?
It would be just as easy to get rid of the handler if your code can officially see the handler. If absolutely necessary, it is possible to unsubscribe using reflection to get hold of the delegate, but this is messy. It would be a lot cleaner and safer to either a: avoid the requirement, or b: change the code to make the handler protected.
Reflection approach (use at own risk); uncomment the block in the Bar.ctor() to see the change.
using System;
class Foo
{
public event EventHandler SomeEvent;
public Foo()
{
SomeEvent += SecretHandler; // a bad idea, anyway
//(self-subscribed events....)
}
protected virtual void OnSomeEvent()
{
EventHandler handler = SomeEvent;
if (handler != null) handler(this, EventArgs.Empty);
}
private void SecretHandler(object sender, EventArgs args)
{
Console.WriteLine("suscribed");
}
}
class Bar : Foo
{
public Bar()
{
/*
MethodInfo method = typeof(Foo).GetMethod("SecretHandler",
BindingFlags.NonPublic | BindingFlags.Instance);
EventHandler handler = (EventHandler)Delegate.CreateDelegate(
typeof(EventHandler), this, method);
SomeEvent -= handler;
*/
}
public void Test()
{
OnSomeEvent();
}
}
static class Program
{
static void Main()
{
Bar bar = new Bar();
bar.Test();
}
}