I have a program that attaches a listener to an object every time the window switches, and then calls a delegate when an event occurs on this window.
The problem is that the code assigns a new delegate every time a window is switched to, meaning one window could have multiple delegates called for one event.
To prevent this I would like to be able to un register a delegate from within the delegate function.
For example:
void OnWindowChange(CustomClass newWindow){
newWindow.OnEvent += delegate {
Console.WriteLine("This event happened.");
newWindow.OnEvent -= *this delegate*;
};
}
I was considering not using an anonymous function, but the problem is, there are at least 10 events per window object that all need hooked. So anonymous seems to be the best (DRYist) way.
If there is a better way to go about doing this, I am open to it.
Related
I'm not new to C#, but events is one of the most confusing topics I confront in the language.
one of the questions is: where should I assign the event handler to the event, or the question in other form: why most events are raised in the subscriber constructor? what does it mean?
like this example (taken from the book Mastering Visual C# )
public ReactorMonitor(Reactor myReactor)
{
myReactor.OnMeltdown +=
new Reactor.MeltdownHandler(DisplayMessage);
}
Raise = generate. Events are not raised in the subscriber constructor. The subscriber does not raise events at all. The event source raises/generates events, and subscribers subscribe to, receive, and handle them.
Events in c# are nothing more than function pointers, i.e. a variable that contains a pointer (or list of pointers) to a function that matches a specific signature (typically Action<object,EventArgs>). Or in the words of this MSDN article:
Delegates are like C++ function pointers but are type safe.
When you subscribe to an event, you are essentially saying "Store the address of my function. When X happens, please call it (along with any other function whose address is stored)."
Thus the code
myReactor.OnMeltdown += Meldownhandler;
can be read as
objectThatRaisesEvents.FunctionPointer = MyHandler;
Notice that MyHandler is not followed by parentheses. If it were MyHandler() that means you are invoking the function, the value of the expression MyHandler() is actually the return value of the function; MyHandler by itself doesn't invoke the function or return its value but instead returns the address of the handler itself. So the above line of code takes the address of MyHandler and stores it in a variable named FunctionPointer.
When the object that raises events invokes FunctionPointer() it is telling c# to obtain the address of the function stored in FunctionPointer and invoke it.
So it is really calling MyHandler() indirectly. Thus these two lines do exactly the same thing:
objectThatRaisesEvents.FunctionPointer();
MyHandler();
Also notice the += in your example. In c# that is the equivalent of
objectThatRaisesEvents.FunctionPointer =
objectThatRaisesEvents.FunctionPointer + MyHandler;
We typically use that syntax because there might be several handlers that subscribe to an event. += has the effect of appending our handler to the list. You could use = instead, but it would unsubscribe any existing handlers.
To answer your question-- when should you subscribe to events? That is a very broad question, but typically
In an ASP.NET web page, you'd subscribe during the Init event.
In a Windows Form, you'd subscribe in the InitializeComponent method.
There are many other contexts of course... the bottom line is you should subscribe before you need to receive notifications of occurrences of the event.
The event is one of the standard features of .NET Framework built using delegate model implementing the Observer design pattern.
https://msdn.microsoft.com/en-us/library/edzehd2t(v=vs.110).aspx
https://en.m.wikipedia.org/wiki/Observer_pattern
Where you subscribe to the event depends on the business rules, but most of the time you want to subscribe at the earliest possible moment which is usually the constructor of the class interested in the handling of the event.
When events should be raised on the other hand depends on what you are trying to communicate to the subscribers if it is a notification of the state change then you raise an event as soon as state is changed.
An event is a message sent by an object to signal the occurrence of an
action. The action could be caused by user interaction, such as a
button click, or it could be raised by some other program logic, such
as changing a property’s value.
I have designed a Windows application using C#. The application's form consists of a couple of labels and a button. When the application starts, I instantiate a UdpListener and I start a separate thread with it, so as to achieve responsiveness while the listener waits for incoming packets. When data arrives, the listening thread needs to update the form's controls, and for this I have declared delegate functions and checking for each control if Invoking is required prior to seeing them through these functions.
The application worked fine until now. I now want to implement a timer functionality, such that if a pause of longer than 2 seconds of receiving data has been detected, I would like to turn a label red. I am trying to use the System.Timers.Timer class, and following Microsoft's example (https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx), I have implemented as follows:
private static void SetTimer()
{
// Create a timer with a two second interval.
aTimer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
e.SignalTime);
}
I call SetTimer() from my main form. While the above compiles, when I try to substitute Console.... with my controls, say lblStatus, the compiler is complaining that I am trying to reference non static controls from static context. trying to build similar functions as I did for labels and text boxes and using the Invoke method checks does not work either. If anyone has implemented such functionality I would be extremely interested your opinion on this.
In regards to a possible duplication of an existing question on here, please note that I had assumed that the method and event had to be static (as this code was copied from the example cited above), thus the compiler error; I knew what the error meant, I just was puzzled on how I could refer to the form controls from another thread given the static nature of the event. I was also curious as to how come from that static event, Console is still accessible; I guess it's not considered a control. I hope this makes sense to the forum.
You cannot access member variables without an instance reference from a static function. This is because a static function is not part of an instance and it has no access to this.
You should just declare your SetTimer and OnTimedEvent as normal instance methods and declare the timer the same (non-static). That way all your functions will be part of the instance and will have access to other instance variables (controls).
Based on your question, it doesn't seem that you need any of these to be static.
I would like to confirm something - when I register a method as a subscriber to an event the long way, like so:
_serviceContext.ReadingEntity += new EventHandler<ReadingWritingEntityEventArgs>(_serviceContext_ReadingEntity);
I need to un-register that method from the event's subscription if I don't want it to continue to be called when the event is fired, like this:
_serviceContext.ReadingEntity -= new EventHandler<ReadingWritingEntityEventArgs>(_serviceContext_ReadingEntity);
When I register a delegate as a subscriber to an event, like so:
public guy ThisMethod()
{
_serviceContext.ReadingEntity += delegate(object sender, ReadingWritingEntityEventArgs e)
{
};
}
There is no way to un-register that delegate from the subscriber list from that method. So I am assuming that the scope of this registration is limited to the method in which it's registered - i.e. if the _serviceContext.ReadingEntity event was fired in a method called by ThisMethod, this registration would be already expired and the code inside the delegate would not run. Is this correct?
Thanks!
p.s. I realize that the first "long" way of registering an event handler also has scope limitations, but I'm a bit hazy on that. My main question, however, is whether or not the delegate registration will live on outside of the method above.
Once you subscribed a delegate this way (you can unsubscribe using -= operator if you cache the delegate variable somewhere) you can't remove it from subscribers list and it will be invoked every time event rises until publisher is alive. Moreover this subscription will prevent any subscriber class (class which contains the method you subscribed to event) from garbage collection until publisher is alive (unless you use a static method).
To give some clarity, there is no "anonymous" methods in IL code. All your delegates and lamdbas are translated into static/instance methods and closure classes (depends on whether they use instance members/function parameters).
You can unsubscribe a delegate if you keep a reference to it.
EventHandler<ReadingWritingEntityEventArgs> aDelegate = delegate(object sender, ReadingWritingEntityEventArgs e)
{
};
_serviceContext.ReadingEntity += aDelegate;
_serviceContext.ReadingEntity -= aDelegate;
If you do not do it this way, there is no way to unsubcribe. The scope is not limited to the method in which it was registered. It will be registered for the lifetime of the event.
I know this is really basic stuff but I'm struggling to wrap my mind around it.
Ok so I have a method that I want to run:
public static void DelegateTest(string testStuff)
{
for (int i = 0; i < 4; i++)
{
Console.WriteLine(testStuff);
}
}
Then, outside of the scope of this method (but within the scope of my class) I define my delegate with the same output type and input parameters as my method:
public delegate void myDelegate(string test);
I instantiate my delegate like so:
myDelegate md = new myDelegate(DelegateTest);
I can then kick off my method as many times as I like by BeginInvoking the delegate, and the methods will run side by side in separate threads.
md.BeginInvoke("Hello World", null, null);
md.BeginInvoke("Hello World Again", null, null);
md.BeginInvoke("Hello World A Third Time", null, null);
How do I now define an event and only kick off my method asynchronously when the event happens? Also, what are the limitations on what an event can be? Can more or less anything that happens on my computer be defined as an event or only certain things?
Edit: Say for example, after doing the above, I want to create an event and define this event as 'the space bar has been pressed'. Every time the space bar is pressed, this is the event happening. When the event happens, I want to start my method asynchronously, I don't want to start my method asynchronously if the space bar hasn't been pressed.
How would I go about this?
Just use Invoke rather than BeginInvoke for synchronous calls.
EDIT: as per ThePower's answer, you don't need the Invoke, you can just call your delegate as if it were a function (because it is!).
EDIT2: You are actually trying to register an event handler. For this you don't need to create your own delegate. An example for handling the KeyPress event in WinForms:
public class MyForm : Form
{
public MyForm()
{
KeyPress += OnKeyPressHandler;
}
private void OnKeyPressHandler(object sender, KeyPressEventArgs keyPressEventArgs)
{
//TODO: whatever you need to do...
}
}
If you want to use it as an event, check out the event type. There's a good example here.
Although, if you want to use your delegate...
You have already defined Asynchronous, so for Synchronous use :
md("Hello World", null, null);
md("Hello World Again", null, null);
md("Hello World A Third Time", null, null);
I'm not sure I completely understand your question. In C#, for all practical purposes, an event is a delegate, meaning that any delegate can be used as an event.
Using your example:
public delegate void MyDelegate(string test);
You can now use MyDelegate as an event in a class:
public class MyClass
{
public event MyDelegate MyEvent;
}
You can now register event handlers with MyEvent and then in the event handler you can execute any code you want. From a traditional sense, this is the only way to define events in C#.
Another option to consider is using a publish/subscribe pattern such as an EventAggregator. This pattern doesn't typically rely on delegates and instead relies on an aggregator object to notify all subscribers of a published event. In this scenario, the event can really be any object that contains the information expected by the subscribers.
I recently attended a interview in C# where i was asked a question about Events and delegates in C#
The person asked me when a event say button gets clicked, which gets called first event or delegate?
Does the delegate calls the event or the event calls delegate?
Can we have a event without a delegate in c#?
The person asked me when a event say button gets clicked, which gets called first: the event or the delegate?
When you open a door, which gets opened first: the door or the doorknob?
Huh?
That question doesn't make any sense. You open a door with a doorknob, but you don't open a doorknob.
What does it mean to "call" an event? Events aren't things that you call. Events are things that you raise. Raising an event is identical with calling the delegate.
Does the delegate calls the event or the event calls delegate?
Does the door open the doorknob, or does the doorknob open the door?
Again, the question doesn't make sense. A doorknob is not something that can be "opened", and the doorknob does not open the door -- you open the door, by holding the doorknob.
Does the delegate call the event? No; events are not things that can be "called". Does the event call the delegate? No, the code that is raising the event calls the delegate.
Can we have a event without a delegate in c#?
Yes, in the sense that the delegate reference associated with an event can be a null reference. But every event is associated with a delegate type, and somehow has associated with it a reference to a delegate.
The whole set of questions indicates to me that the questioner does not have a very good understanding of the relationship between events and delegates. A good way to think about it is that an event is just a property that contains a reference to a multicast delegate. Whereas a property has special methods that get and set the value of the property, an event has special methods that add and remove delegates to the multicast delegate.
Events are a concept which utilize delegates as a means to call methods that have subscribed to them.
Events themselves are not called. When a piece of code raises an event, it will call each of the subscribed methods by invoking the delegates.
Events are raised, delegates are called. So when the button is clicked, a buttonClick event is raised, meaning that each delegate subscribed to the event will be called, according to the subscription order.
An event is simply a code construct implemented in .NET as a multi-cast delegate.
When an event is "raised" (which can only be done by code in the same class as the event; event raising must happen within "protected" scope), the delegates are invoked one at a time, in a synchronous fashion but not necessarily in any deterministic order. The event IS the delegate, so when the event is raised for a button being clicked, the delegates are invoked by the runtime, which has received the Windows message that the user clicked on the GUI area for the button.
The statements "the event is raised" and "the delegates are invoked" are equivalent statements; it's like asking "which comes first, the chicken or the gallus domesticus?".
Now, events often cascade, especially when we're talking about UI. There is a MouseUp event, invoked when the mouse button is released, which can fire one or more other events such as MouseClick, MouseDoubleClick, DragDrop, etc. You may not attach a handler to the MouseUp event, but there is built-in logic behind the scenes of MouseUp to raise the MouseClick event which you DO handle. So, in this sense, you could say that the MouseUp event "comes first" and calls the MouseClick handler delegate.
This page bubbled up on top of Google results, so below is something you might find useful if you also land here. Multi-cast delegates ARE called (see MSDN) in deterministic order on one thread, in the order of assignment. This assignment will involve an array of some sort, and it would be illogical for the indices to fill up out of order.
public partial class Form1 : Form
{
ob<Control>ob1;
ob<Control>ob2;
ob<Control>ob3;
public Form1()
{
InitializeComponent();
ob<Control>.setup(button1);
ob1 = new ob<Control>(1, true);
ob2 = new ob<Control>(2, false);
ob3 = new ob<Control>(3, false);
}
public class ob<T> where T : Control
{
int ndx;
Boolean isSentinel;
static Boolean dontdostuff;
static T c;
public static void setup(T c) {ob<T>.c = c;}//an argument less from constructor, useful for many objects (more likely to be menuitems)
public ob(int ndx, Boolean isSentinel)
{
this.ndx = ndx;
this.isSentinel = isSentinel;
c.Click += new EventHandler(click);
}
void click(object sender, EventArgs e)
{
if( isSentinel)
{
if (MessageBox.Show("ob" + ndx + " asks: short circuit subsequent delegate calls?", "", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
{
dontdostuff = true;
return;
}
else
{
dontdostuff = false;
}
}
else
{
if( dontdostuff) return;
}
MessageBox.Show("ob" + ndx + " doing stuff in order of handler addition", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}