Is it possible to execute some code when someone subscribes to an event that i made in my class. a short explenation: i need to configure an external pc to send data to me when someone subscribes to this event, so when that data is received i can throw the event.
public class test
{
public event EventHandler myEvent;
private void Method1()
{
//this needs to be executed when someone subscribes to the event
}
private void Method2()
{
//this needs to be executed when someone unsubscribes to the event
}
}
You can create your add / remove methods
private EventHandler myEvent;
public event EventHandler MyEvent {
add {
myEvent += value;
if(myEvent != null) ExecuteCode();
}
remove {
myEvent -= value;
}
}
be careful if your function should be thread-safe, in which case you need a lock in order to ensure it to be synched.
Related
What would be the equivalent C# code against following VB.Net code:
Public Event EndOfVideo()
Private Sub RaiseEndOfVideo()
RaiseEvent EndOfVideo()
End Sub
EDIT
Here is the equivalent C# code that telerik converter generated for me.
public event EndOfVideoEventHandler EndOfVideo;
public delegate void EndOfVideoEventHandler();
private void RaiseEndOfVideo()
{
if (EndOfVideo != null) {
EndOfVideo();
}
}
Calling RaiseEndOfVideo doesn't trigger/invoke EndOfVideo event, and Null Reference Exception is raised.
Consider you have class VideoPlayer which has event EndOfVideo and you want to raise this event and when someone calls method EndVideo on object of VideoPlayer.
Now, like any other member of a class event also initialized to null and gets the value when some handler is attached to it.
Attaching an handler to an event happens using += operator.
public class VideoPlayer
{
public event EndOfVideoEventHandler EndOfVideo;
// Following delegate indicates that the a method accepting no parameter
// and returning void can be attached as an handler to this event.
public delegate void EndOfVideoEventHandler();
public void EndVideo()
{
RaiseEndOfVideo();
}
private void RaiseEndOfVideo()
{
if (EndOfVideo != null)
{
// Following line of code executes the event handler which is
// attached to the event.
EndOfVideo();
}
}
}
public class WebPage
{
public void VideoStopped()
{
Console.WriteLine("Video Stopped");
}
}
Now in Main method of program.cs
static void Main(string[] args)
{
VideoPlayer player = new VideoPlayer();
WebPage page = new WebPage();
player.EndOfVideo += page.VideoStopped;
// Following method call on player object will call internally
// RaiseEndOfVideo which will Raise event and event will execute
// VideoStopped method of page object which is attached in previous line
// and display "Video Stopped" message in Console.
player.EndVideo();
Console.WriteLine("Completed!!! Press any key to exit");
Console.ReadKey();
}
I hope this would help you start understanding how events and delegates work in C#. For further reading you can go thru https://msdn.microsoft.com/en-us/library/edzehd2t(v=vs.110).aspx
This is the generally accepted way to write an event with no parameters:
public class Foo
{
public event EventHandler EndOfVideo;
protected virtual void OnEndOfVideo()
{
var handler = EndOfVideo;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
Your code is what was needed in the old days: creating a delegate and yada yada.
To state the obvious, though, you need to subscribe to an event with something like:
public class Bar
{
public void DoAllTheThings()
{
var foo = new Foo();
foo.EndOfVideo += foo_EndOfVideo;
}
void foo_EndOfVideo(object sender, EventArgs e)
{
Console.WriteLine("EndOfVideo");
}
}
For the sake of completeness, the EventHandler delegate has a generic counterpart, EventHandler<T>, which you would use when you want an event that does have parameters, where T should be a class inheriting from System.EventArgs which holds the information you want your event to expose.
To do that, you will need to create a custom eventHandler to specify the method signatures of the handlers for your event
I have problem with event. For example let i have event
public event EventHandler<AxisChangedEventArgs> AxisChanged
which fires when Axis pan or zoom or something else. When it's firing i am making Console.WriteLine("Working");. How can i pass CFDBOX parameter into SomeWork anonymous method does not help because it will be imposible to unsubscribe from it. And i cannot override AxisChanged event.
public void AddEvents(CFDBOX CFDBOX) {
CFDBOX.PlotModel.Axes[0].AxisChanged += SomeWork;
}
public void RemoveEvents(CFDBOX CFDBOX) {
CFDBOX.PlotModel.Axes[0].AxisChanged -= SomeWork;
}
public EventHandler<AxisChangedEventArgs> SomeWork =
delegate(object o, AxisChangedEventArgs args) {
Console.WriteLine("Working");
}
;
Take advantage of closure lambda expressions:
private EventHandler<AxisChangedEventArgs> axisChangedEventHandler;
public void AddEvent(CFDBOX CFDBOX) {
// keep a reference of the event handler to remove it later
axisChangedEventHandler = (o, args) => {
// parameter CFDBOX bound to the event handler
Console.WriteLine("Working " + CFDBOX);
};
// register event handler
CFDBOX.PlotModel.Axes[0].AxisChanged += axisChangedEventHandler;
}
public void RemoveEvent() {
// unregister event handler
CFDBOX.PlotModel.Axes[0].AxisChanged -= axisChangedEventHandler;
}
Any parameter which must be passed with an event should be a member of your EventArgs implementation. In your scenario: AxisChangedEventArgs. Hope i get your question.
The sender of the event (in your case o) should always be the instance, which calls the event. So if your event get's fired from different classes (not instances!), you will have to check for the type of o.
I have a set of events that have the same signature . now I wonder if I can create a generic event handler raising method to do this for all of the events ?
is this possible to send an event as <T> ?
If this is all within a single class, you can make a method to raise the event which works with any of them. For example, if your events all were EventHandler<T>, you could use:
private void RaiseEvent<T>(EventHandler<T> eventHandler, T eventArgs)
{
if (eventHandler != null)
{
eventHandler(this, eventArgs);
}
}
You could then call this via:
this.RaiseEvent(this.MyEvent, new MyEventArgs("Foo"));
For a static version of Reed Copsey's reply, I created a static class Event:
public static class Event
{
public static bool Raise<T>(Object source, EventHandler<T> eventHandler, T eventArgs) where T : EventArgs
{
EventHandler<T> handler = eventHandler;
if (handler != null)
{
handler(source, eventArgs);
return true;
}
return false;
}
}
This also assumes your event handlers are of the type EventHandler<T>. The return type was changed from void to bool and returns whether there were any listeners of the event. Rarely used, so feel free to change back to void.
Example usage:
public event EventHandler<FooArgs> FooHappend;
public void Foo()
{
Event.Raise(this, FooHappend, new FooArgs("Hello World!");
}
See this. It describes what you want.
You can create a typed event by using a typed delegate and using that for your event:
public delegate void myDel<T>(T stuff);
public event myDel<int> myEvent;
public doStuff()
{
myDel(1);
}
Is there any way of being notified when something subscribes to an event in my class, or do I need to wrap subscription/unsubsription in methods eg:
public class MyClass : ISomeInterface
{
public event SomeEventHandler SomeEvent; //How do I know when something subscribes?
private void OnSomeEventSubscription(SomeEventHandler handler)
{
//do some work
}
private void OnSomeEventUnsubscription(SomeEventHandler handler)
{
//do some work
}
}
instead of
public class MyClass : ISomeInterface
{
private SomeEventHandler _someEvent;
public void SubscribeToSomeEvent(SomeEventHandler handler)
{
_someEvent += handler;
//do some work
}
public void UnsubscribeFromSomeEvent(SomeEventHandler handler)
{
_someEvent -= handler;
//do some work
}
}
The reason I ask is because the event is already exposed directly on a ISomeInterface but this particular implementation needs to know when stuff subscribes/unsubscribes.
You can write custom accessors for your event:
private SomeEventHandler _someEvent;
public event SomeEventHandler SomeEvent
{
add
{
_someEvent += value;
Console.WriteLine("Someone subscribed to SomeEvent");
}
remove
{
_someEvent -= value;
Console.WriteLine("Someone unsubscribed from SomeEvent");
}
}
Thomas has answered this already but thought I'd also add that you may need to lock any critical section in the add remove sections since event subscription is never thread safe, i.e. you have no idea who is going to connect to you or when. E.g.:
private readonly object _objectLock = new object();
private SomeEventHandler _someEvent;
public event SomeEventHandler SomeEvent
{
add
{
lock(_objectLock)
{
_someEvent += value;
// do critical processing here, e.g. increment count, etc could also use Interlocked class.
} // End if
} // End of class
remove
{
lock(_objectLock)
{
_someEvent -= value;
// do critical processing here, e.g. increment count, etc could also use Interlocked class.
} // End if
} // End if
} // End of event
Below is the program I used for the test.
It prints (as expected):
Raise A
Event from A
Raise B
Event from B
Now, if we change first two lines of the Main to be:
A a = new B();
B b = new B();
the Program will print:
Raise A
Raise B
Event from B
which is also expected, as overriding event hides the private backing field in the base class and therefore events fired by the base class are not visible to clients of the derived class.
Now I am changing the same lines to:
B b = new B();
A a = b;
and the program starts printing:
Raise A
Raise B
Event from A
Event from B
What's going on?
class A
{
public virtual event EventHandler VirtualEvent;
public void RaiseA()
{
Console.WriteLine("Raise A");
if (VirtualEvent != null)
{
VirtualEvent(this, EventArgs.Empty);
}
}
}
class B : A
{
public override event EventHandler VirtualEvent;
public void RaiseB()
{
Console.WriteLine("Raise B");
if (VirtualEvent != null)
{
VirtualEvent(this, EventArgs.Empty);
}
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
a.VirtualEvent += (s, e) => Console.WriteLine("Event from A");
b.VirtualEvent += (s, e) => Console.WriteLine("Event from B");
a.RaiseA();
b.RaiseB();
}
}
We have a single instance (of B) which has the following fields:
A.VirtualEvent: null
B.VirtualEvent: Two event handlers
The call to a.RaiseA() just prints "Raise A" - but nothing more, because the private field in A is null.
The call to b.RaiseB() prints the remaining three lines, because the event has been subscribed to twice (once to print "Event from A" and once to print "Event from B").
Does that help?
EDIT: To make it clearer - think of the virtual event as a pair of virtual methods. It's very much like this:
public class A
{
private EventHandler handlerA;
public virtual void AddEventHandler(EventHandler handler)
{
handlerA += handler;
}
public virtual void RemoveEventHandler(EventHandler handler)
{
handlerA -= handler;
}
// RaiseA stuff
}
public class B : A
{
private EventHandler handlerB;
public override void AddEventHandler(EventHandler handler)
{
handlerB += handler;
}
public override void RemoveEventHandler(EventHandler handler)
{
handlerB -= handler;
}
// RaiseB stuff
}
Now is it clearer? It's not quite like that because as far as I'm aware you can't override just "part" of an event (i.e. one of the methods) but it gives the right general impression.
You hooked up two event handlers to the same event. Since A and B are pointing to the same object, when you call b.RaiseB() both event handlers get fired. So first you're calling RaiseA which is a basecalss method. That prints Raise A. It then doesn't actually fire off the event because it's null. Then, you're raising B but TWO handlers are hooked up to it, therefore it first prints Raise B, and when the event fires, both handlers get called.
Try making your RaiseA function protected + virtual.
A rule of thumb: If derived class overrides event accessors, it must also override the function that invokes the event.