Public event of base class in derived class - c#

I have a base-class (let it be SomeBaseClass) containing a public event (SomeEvent) and I have a derived-class in which I want to raise this event but I can't(!!) VS 2010 says me (in derived-class in line: base.SomeEvent != null) "The event 'SomeBaseClass.SomeEvent' can only appear on the left hand side of += or -=". If I replace base on this It is make no sense.

No, it's absolutely right - the event is only an event (with subscription and unsubscription) as far as a derived class is concerned. If your base class wants to let derived classes raise the event, it should include a protected method to do so (typically a virtual OnFoo(EventHandler) for an event called Foo with the EventHandler type, for example). Note that if you write a field-like event in C# like this:
public event EventHandler Foo;
That's actually declaring a private field called Foo (which that class and any nested classes have access to) and a public event (which consists only of subscribe/unsubscribe). You could declare your own "custom" event like this:
protected EventHandler foo;
// Note: not thread-safe. Only present for demonstration purposes.
public event EventHandler Foo
{
add { foo += value; }
remove { foo -= value; }
}
and then derived classes would have access to the field... but I wouldn't recommend that. (I rarely declare non-private fields, other than for constants.)

You need to do it the right way (i.e., the idiomatic way in C#)
public class Base {
public event EventHandler<EventArgs> SomeEvent;
protected virtual void OnSomeEvent(EventArgs e) {
EventHandler<EventArgs> handler = SomeEvent;
if (handler != null) {
handler(this, e);
}
}
}
public class Derived {
protected virtual void OnSomeEvent(EventArgs e) {
// derived event handling here
// then invoke the base handler
base.OnSomeEvent(e);
}
}
The reason that you do it like this is because events can only be invoked from within the defining class.

Related

Implementing an event inherited from an interface

In my project, I need to implement an event that fires when a popup or something similar is pulled up so that I can close anything that needs to hide behind it for whatever reason.
For context, I have 3 files in play here, MainShell which fires the event, IShell which is an interface that MainShell implements and defines the event, and Reports which listens for the event. I could have put the event in MainShell and made everything simpler, however the project references would become circular if I did that. That's just what I have to work with. I can, however, refer to the IShell interface that defines the functions MainShell uses. Unfortunately, it seems attempting to use an event from a derived class/interface causes the implementation to become very complicated and picky for some reason.
In my interface file:
public class ModuleShownEventArgs : EventArgs { }
public delegate void ModuleShownEventHandler(object sender, ModuleShownEventArgs e);
public interface IShell {
event ModuleShownEventHandler ModuleShown;
... }
In my listening class:
public Reports() {
...
Container.Shell.ModuleShown += Shell_ModuleShown;
... }
private void Shell_ModuleShown(object sender, ModuleShownEventArgs e) {}
In my event firing class:
event ModuleShownEventHandler IShell.ModuleShown
{
add
{
((IShell)this).ModuleShown += value;
}
remove
{
((IShell)this).ModuleShown -= value;
}
}
public void OnModuleShown()
{
ModuleShownEventHandler handler = ((IShell)this).ModuleShown;
if (handler != null)
handler(this, new ModuleShownEventArgs());
}
I've managed to stop most of the compiler's complaints, but I'm down to one problem: there's an error where I assign handler = ModuleShown,
the event 'IShell.ModuleShown' can only appear on the left hand side
of += or -=
This prevents me from easily comparing my event to null for checking, and prevents me from firing my event at all.
Questions
How can I get this to work? Why can't I fire my event? Why does defining events change so drastically when they come from a base class/interface? Keep in mind that this project is quite large and I've only started working on it recently, so I can't make sweeping structural changes to it.
I am using Visual Studio 2013, and my project's .NET Framework version is 4.0.
The issue is that you are using explicit interface implementation. You should be using implicit instead.
public class Shell : IShell
{
public event ModuleShownEventHandler ModuleShown;
public void OnModuleShown()
{
ModuleShownEventHandler handler = ModuleShown;
if (handler != null)
{
handler(this, new ModuleShownEventArgs());
}
}
}
https://msdn.microsoft.com/en-us/library/ms173157.aspx
Ideally you will be passing around the instance that implements IShell as the interface if your concern was to hide the event from the Shell implementation. Typically, you use explicit interface implementations when you do not want your class to publicly expose an interface specific member.
I hope this helps.
It should look something like this instead.
public void OnModuleShown()
{
if (((IShell)this).ModuleShown != null);
(((IShell)this).ModuleShown)(this, new ModuleShownEventArgs());
}

How to notify a "higher" class that something in a "lower" class has changed? Or: publish/subscribe the other way round

Suppose you have two classes:
public class A
{
int x = 0;
public void Increase()
{
x++;
}
}
public class B
{
A a;
private void DoSomething();
}
Is there a way for B to be "messaged" and execute DoSomething() when anything has changed in a (i.e. x has increased)? I know how I could make a subscribe to B, such that if B does RaiseSomeEvent(..), a reacts, but not the other way round.
Background: I'm trying to create a custom control
public class BattleshipCanvas : Canvas
{
public BSGrid BattleshipGrid {...}
...
}
that should redraw once anything inside the BattleshipGrid (BSGrid is a class encapsulating a two-dimensional array) changes, where BattleshipGrid will be bound to a certain BSGrid in the ViewModel. I thought about adding an event to BSGrid that is raised whenever I modify its data, but I don't know how to notify the BattleshipCanvas of that event.
I hope I could make it a little clear (it's hard for me to express what I want exactly here) and understandable, but if there arise any questions, feel free to comment and I'll try to answer them. Thanks!
You may be looking for events in c#. In your specific case you may like to make use of the INotifyPropertyChanged Interface. You can use it to inform other classes by events if a property inside the implementing class has changed.
This is also the base to use binding in your project later on.
public class A: INotifyPropertyChanged
{
//Event used to announce a change inside a property of your class
public event PropertyChangedEventHandler PropertyChanged;
int _x = 0;
public int X
{
get { return _x; }
set
{
if (_x != value)
{
_x = value;
OnPropertyChanged("X"); //invokes the event.
}
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) //make sure somebody subscribed to the event
handler.Invoke(this, new PropertyChangedEventArgs(propertyName)); //this calls all eventhandler methods which subscribed to your classes PropertyChanged event.
}
public void Increase()
{
X++; //use the property to invoke a property changed event.
}
}
public class B
{
A a;
public B()
{
a = new A();
a.PropertyChanged += new PropertyChangedEventHandler(a_PropertyChanged); //subscribe up to the event. (use -= to unsubscribe)
a.Increase()
}
//Catch the event
void a_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//execute what you would like to do.
//you can use e.PropertyName to lookup which property has actually changed.
DoSomething();
}
private void DoSomething(){}
}
Events are probably the way to go. You can make any class in your project react to any event being raised in your program, no matter where the event is created/handled.
In your instance, it looks like you don't even need to send over any custom EventArgs.
The most simple example I could find of this is here:
http://timok.tumblr.com/post/57441520214/simplistic-event-example-in-c

Why virtual event does not not call overridden handler

Consider the following scenario, may be this scenario is very hypothetical
public delegate void MyDel();
public class T1
{
public T1()
{
}
public virtual event MyDel MyEvent;
public virtual void RaiseEvent()
{
MyEvent();
}
protected virtual void HandleEvent()
{
MessageBox.Show("base event");
}
}
public class T2:T1
{
public override event MyDel MyEvent;
public T2()
{
MyEvent += new MyDel(HandleEvent);
}
protected override void HandleEvent()
{
MessageBox.Show("overridden event");
}
}
and main client code
baseT = new T2();
baseT.MyEvent += new MyDel(() => MessageBox.Show("From client"));
baseT.RaiseEvent();
Why does it throw an exception, why virtual events do not behave like virtual/overridden methods?
The interface of an event is really just a pair of methods, add and remove. A private backing delegate is generated for auto-implemented events that is accessible only inside the declaring class through the event's name.
The virtual keyword for an event only applies to the add/remove method pair. Accessing and invocation of the backing delegate is not virtual for an auto-implemented event. When the subscribe occurs on an instance of the derived class (T2), it is using the overridden add/remove methods which use its own backing delegate. The base class's backing delegate is still null and is still being invoked in RaiseEvent. This causes a NullReferenceException when RaiseEvent is called.
Virtual events are kind of rare. I would probably make the event itself non-virtual and use protected virtual methods to allow the derived class to modify the event's behavior.

Defining an event for a windows forms custom control

I'm working on an form custom control.the control is a MonthCalendar like Visual studio(C#) MonthCalendar control and I want to define an event for my control.
How can define a new event for this form custom control?
If your event should not provide any additional info (Foo is name of your event):
public event EventHandler Foo;
And raise it this way:
protected virtual void OnFoo()
{
if (Foo != null)
Foo(this, EventArgs.Empty);
}
If you need to pass some additional info to event handlers, then create custom arguments class by inheriting from EvenArgs class
public class FooEventArgs : EventArgs
{
public string Message { get; private set; }
public FooEventArgs(string message)
{
Message = message;
}
}
Declare event this way:
public event EventHandler<FooEventArgs> Foo;
And raise it this way:
protected virtual void OnFoo(string message)
{
if (Foo != null)
Foo(this, new FooEventArgs(message));
}
Its good practice to create protected methods for raising events by descendants of class where event is declared. Also good practice to use event naming convention:
add suffix -ing to event name for events which raised before
something happened (often you could cancel such events) (e.g. Validating)
add suffix -ed to event name for events which raised after something happened (e.g. Clicked)
As Thorsten stated, good practice to create virtual methods for raising events. Its not only allows to raise events from descendants, but also disable event raising, or adding some behavior prior/after event raising.
public event EventHandler<EventArgs> YourEvent;

Why events can't be used in the same way in derived classes as in the base class in C#?

In following code, I want to extend the behaviour of a class by deriving/subclassing it, and make use of an event of the base class:
public class A
{
public event EventHandler SomeEvent;
public void someMethod()
{
if(SomeEvent != null) SomeEvent(this, someArgs);
}
}
public class B : A
{
public void someOtherMethod()
{
if(SomeEvent != null) SomeEvent(this, someArgs); // << why is this not possible?
//Error: The event 'SomeEvent' can only appear on the left hand side of += or -=
//(except when used from within the type 'A')
}
}
Why isn't it possible?
And what is the common solution for this kind of situation?
Others have explained how to get round the issue, but not why it's coming up.
When you declare a public field-like event, the compiler creates a public event, and a private field. Within the same class (or nested classes) you can get at the field directly, e.g. to invoke all the handlers. From other classes, you only see the event, which only allows subscription and unsubscription.
The standard practice here is to have a protected virtual method OnSomeEvent on your base class, then call that method in derived classes. Also, for threading reasons you will want to keep a reference to the handler before checking null and calling it.
For an explanation of the why read Jon Skeet's answer or the C# specification which describes how the compiler automatically creates a private field.
Here is one possible work around.
public class A
{
public event EventHandler SomeEvent;
public void someMethod()
{
OnSomeEvent();
}
protected void OnSomeEvent()
{
EventHandler handler = SomeEvent;
if(handler != null)
handler(this, someArgs);
}
}
public class B : A
{
public void someOtherMethod()
{
OnSomeEvent();
}
}
Edit: Updated code based upon Framework Design Guidelines section 5.4 and reminders by others.
Todd's answer is correct. Often you will see this implemented throughout the .NET framework as OnXXX(EventArgs) methods:
public class Foo
{
public event EventHandler Click;
protected virtual void OnClick(EventArgs e)
{
var click = Click;
if (click != null)
click(this, e);
}
}
I strongly encourage you to consider the EventArgs<T>/EventHandler<T> pattern before you find yourself making all manner of CustomEventArgs/CustomEventHandler for raising events.
The reason the original code doesn't work is because you need to have access to the event's delegate in order to raise it, and C# keeps this delegate private.
Events in C# are represented publicly by a pair of methods, add_SomeEvent and remove_SomeEvent, which is why you can subscribe to an event from outside the class, but not raise it.
My answer would be that you shouldn't have to do this.
C# nicely enforces Only the type declaring/publishing the event should fire/raise it.
If the base class trusted derivations to have the capability to raise its events, the creator would expose protected methods to do that. If they don't exist, its a good hint that you probably shouldn't do this.
My contrived example as to how different the world would be if derived types were allowed to raise events in their ancestors. Note: this is not valid C# code.. (yet..)
public class GoodVigilante
{
public event EventHandler LaunchMissiles;
public void Evaluate()
{
Action a = DetermineCourseOfAction(); // method that evaluates every possible
// non-violent solution before resorting to 'Unleashing the fury'
if (null != a)
{ a.Do(); }
else
{ if (null != LaunchMissiles) LaunchMissiles(this, EventArgs.Empty); }
}
virtual protected string WhatsTheTime()
{ return DateTime.Now.ToString(); }
....
}
public class TriggerHappy : GoodVigilante
{
protected override string WhatsTheTime()
{
if (null != LaunchMissiles) LaunchMissiles(this, EventArgs.Empty);
}
}
// client code
GoodVigilante a = new GoodVigilante();
a.LaunchMissiles += new EventHandler(FireAway);
GoodVigilante b = new TriggerHappy(); // rogue/imposter
b.LaunchMissiles += new EventHandler(FireAway);
private void FireAway(object sender, EventArgs e)
{
// nuke 'em
}
Wrap it with a protected virtual On... method:
public class BaseClass
{
public event EventHandler<MyArgs> SomeEvent;
protected virtual void OnSomeEvent()
{
if(SomeEvent!= null)
SomeEvent(this, new MyArgs(...) );
}
}
Then override this in a derived class
public class DerivedClass : BaseClass
{
protected override void OnSomeEvent()
{
//do something
base.OnSomeEvent();
}
}
You'll set this pattern all over .Net - all form and web controls follow it.
Do not use the prefix Raise... - this is not consistent with MS's standards and can cause confusion elsewhere.

Categories

Resources