what role event delegates play? [duplicate] - c#

This question already has answers here:
Understanding events and event handlers in C#
(13 answers)
Closed 2 years ago.
i have a question,
regarding event delegates. I had a a look, but i am not sure i still quite get it.
For example i have seen event delegates in constructor and it was the only place where the method was called..
Player.Finished+= new FinishedEventHandler(Finished);
and when i have called the method there directly it had completely different impact as just calling Player.Finished+= new FinishedEventHandler(Finished); seemed to be doing nothing. Maybe you can point me to some website where i can find this explained in better way?

This can help you to understand events and delegates:
Events in .NET are based on the delegate model. The delegate model follows the observer design pattern, which enables a subscriber to register with and receive notifications from a provider. An event sender pushes a notification that an event has happened, and an event receiver receives that notification and defines a response to it. This article describes the major components of the delegate model, how to consume events in applications, and how to implement events in your code.
An event is a message sent by an object to signal the occurrence of an action. The action can be caused by user interaction, such as a button click, or it can result from some other program logic, such as changing a property’s value. The object that raises the event is called the event sender. The event sender doesn't know which object or method will receive (handle) the events it raises. The event is typically a member of the event sender; for example, the Click event is a member of the Button class, and the PropertyChanged event is a member of the class that implements the INotifyPropertyChanged interface.
To define an event, you use the C# event or the Visual Basic Event keyword in the signature of your event class, and specify the type of delegate for the event. Delegates are described in the next section.
Typically, to raise an event, you add a method that is marked as protected and virtual (in C#) or Protected and Overridable (in Visual Basic). Name this method OnEventName; for example, OnDataReceived. The method should take one parameter that specifies an event data object, which is an object of type EventArgs or a derived type. You provide this method to enable derived classes to override the logic for raising the event. A derived class should always call the OnEventName method of the base class to ensure that registered delegates receive the event.
A simple example is the Button control: when you click on it, the event OnClick is raised and the control call all delegates that have suscribed to it using:
Click += SomeMethod;
Or (it is the same):
Click += new EventHandler(SomeMethod);
If fact, it adds a reference to the method in the event handler list.
An event is just a list of methods to call in case of the event is raised, like with the button click.
A delegate is just a signature of a method without a body implementation, also called a prototype, to be used as a type, to have strong typing when adding events to an event handler like the button click. So when you assign a method implemented, by its name, it must match the delegate signature (return type and parameters, the name of the delegate itself is not pertinent except for humans).
We also can use lambda:
myButton1.Click += (sender, e) => Close();
myButton2.Click += (sender, e) => { MessageBox.Show("Closing"); Close() };
Handling and raising events (MS Docs)
C# - Events(TutorialsPoint)
C# - Events (TutorialsTeacher)
What are C# Events? (YouTube)
C# Tutorial: Events/Event Handlers (YouTube)

Related

How to check for valid Event Handlers from a unit test (or even from the same unit)

I have found several times that for some reason (for instance, Copy&Paste in the form designer), the Event Handlers assigned to some of the components of a form get lost, i.e., the events are not connected to the correct function in the code of the form.
I would like to check this from either the form code, or from some unit test: ensure that they are not empty at least, or check that they are connected to the correct event handler.
I have seen the questions regarding this, but I can't pass the error The event 'SomeEvent' can only appear on the left hand side of += or -=. This happens when trying to compare it to null, or even as some other answers suggest, get the list of delegates and then check those.
I'm not trying to mess with the events. On the contrary, I want to ensure that they are correctly set from my unit tests.
Manually subscribing the event handlers to the events of the components in the constructor, for instance, seems like a bad idea to me. They should already be subscribed in the InitializeComponent() code... and checking if they are or not to subscribe them is exactly the problem I want to solve.
The event handlers I want to check are NOT defined in the Form itself, i.e., they are not my event handlers, but event handlers for the Form, or some of the components. For example, I have a KeyDown event handler for the Form, to check for some shortcuts. Trying to get the InvocationList for such even handler results in the error above.
I try to never relay on designer to bound events to code, i prefer to write it in my constructor, calling a "WireEvents()" method if i want to group them togheter
Anyway, if i've understood your question, you could just iterate over the eventhandler attached delegates
any EventHandler / EventHandler<> has a method GetInvocationList() that return the list of attached event delegates so you can use that to do your checks
you can iterate doing something like
if(YourEvent!=null){
foreach (var #delegate in YourEvent.GetInvocationList()){
//do your job
}
}
update:
here the link to another answer that address your problem of not being able to call GetInvocationList: https://stackoverflow.com/a/12476529/1716620

Call event associated with a method parameter

A method has an input parameter that is a forms control object (say a ComboBox). I want to determine if the control has a particular event registered and, if so, trigger the event. I tried to enter the following code but the compiler rejects it because the selected event (in the example SelectedIndexChanged) can only appear to the left of the += or -= operators.
private void DoSearch(ComboBox cb) {
// Once the search is complete, I want to call the event
// Does this control have a SelectedIndexChanged event registered?
if (cb.SelectedIndexChanged != null) {
// call the event
cb.SelectedIndexChanged(cb, EventArgs.Empty);
}
}
You can't do what you're asking. Only the class in which the event is defined can raise the event.
Not even subclasses can call a parent class's events. You might see, in a subclass, methods called On* (i.e. OnSelectedIndexChanged). These are used to allow the subclass to call into the base class where the event is defined to raise the event. These methods are usually marked as protected so that only child classes can call them.
Otherwise, the way to get SelectedIndexChanged to be raised is to set the SelectedIndex property.

Is there a way to find the HTMLDocument from the IHTMLEventObj passed from an onload event in IE?

I am working on a Browser Helper Object in C# (yes I know performance will not be great).
I am attaching a handler to the HTMLWindowEvents2_Event.onload event of my window. The event is being raised correctly (for example when a refresh happens). I see my handler being called, and the type is correctly shows as a 'load' event.
The event handler has a parameter that supports the IHTMLEventObj. I cannot work out how to get from this object to the window or document that threw the onload event. Is this even possible from this interface? The object passed into appears to have a null srcElement property (presumably as it is an event raised by the window, not some element in the document).
Do I need to cast this into another class or interface to get at the document?
I would be happy for any help in C# or C++.
There is no source information for the event.
The assumption is that since you attached the event to the connection point of the Window object, you knew which window would be the event source. When you hook the event you need to save the reference to the window in case you need the event source.
Class HTMLWindowEvents2Sink
{
public HTMLWindowEvents2Sink(IHTMLWindow2 eventSource)
{
this.eventSource=eventSource;
}
IHTMLWindow2 eventSource;
void AdviseEvent()
{
eventSource.load += this.HTMLWindow_onload;
}
....
}
You also have a performance hit and potential bug farm here, by using the delegate event handling model.

What is this line of code?

Often in code I see a line of code, I have an idea it do something about event but not clearly know what it does.
Is it possible that I can attach form A's load event in Form B with this, or what is its benefit?
this.CGForm .Load +=new EventHandler(CGForm_Load);
Yes, it clearly has to do with events.
.Load in this case the the Form.Load event. The += operator adds one event handler to the event. An event can have many event handlers at the same time. Event handlers are just regular method that can be anywhere in your code base. When the event fires all subscribed methods will be called, one after the other.
I see no particular good reason to have FormA listen to the Load event of FormB, but other events might be more interesting, like the Form.Closed event. This is a way to have FormA react to changes in FormB.
Edit
Note that this causes FormA to hold a reference to FormB and FormB won't be garbage collected until FormA releases the reference to FormB (with
this.CGForm .Load -=new EventHandler(CGForm_Load);, note the -=) this is a common cause for memory leaks in .NET.
Subscribing to events from other forms is a "code smell" that can be a potential structure problem with your code. In some cases it is required, but if you have it all over the place your code will be hard to understand and maintain.
What this line means is that you subscribe the method CGForm_Load() to the this.CGForm.Load event. The method CGForm_Load() is the event handler or the callback.
After you run this line, every time the event is raised (in this case - every time the form is loaded), CGForm_Load() will be called automatically.
In order to unsubscribe a callback, use -= like this:
this.CGForm.Load -= new EventHandler(CGForm_Load)
Once an event callback is unsubscribed, the next time the event is raised (if the form is loaded again) the callback will no longer be called.
I find the following metaphor helpful: An event is like a power outlet, and callbacks are like power plugs. Subscribing is like connecting the plug to the outlet, and unsubscribing is like pulling it out. While there is a connection, all invocations of the event trigger the callback.
It simply adds the GCForm_Load method to the Load event on the CGForm. Under the hood when the CGForm is loaded code like the following will execute. Whenever this happens all event subscribers (in this case the method being subscribed here as CGForm_Load) will be invoked.
<pseudocode>
class CGForm
{
public EventHandler<FormLoadedEventArgs> Load;
private void SomeMethodThatLoadsTheForm()
{
LoadForm();
var loadHandlers = Load;
if (loadHandlers != null)
{
loadHandlers(new FormLoadedEventArgs(...));
}
}
}
</pseudocode>
this.CGForm .Load +=new EventHandler(CGForm_Load); subscribes the event handler delegate CGForm_Load to the Load event of the CGForm object.
Documentation about subscribing to events can be found at http://msdn.microsoft.com/en-us/library/ms366768(v=vs.80).aspx .
And index of information about how events work in .NET can be found at http://msdn.microsoft.com/en-US/library/awbftdfh(v=VS.80).aspx

C# Events without arguments. How do I handle them?

I'm currently working on a menu system for a game and I have the standard hierarchy for screens and screen elements. (Screens contain some collection of screen elements). I'd like screen elements to send an event to the screen class to declare that it's been selected. However, I don't need any event arguments in this case. I'm not sure what the syntax is to create the event without any arguments. I found a solution that passes the player index as an event argument. (My game is strictly single-player, so this is not necessary.)
public event EventHandler<PlayerIndexEventArgs> Selected;
^-- How this event is declared where PlayerIndexEventArgs inherits from EventArgs. Can I omit PlayerIndexEventArgs, or is there a default type to use here to send no arguments? (Maybe just the EventArgs base class?)
You can use Action delegates. This is much more elegantly then using data you will never need (I mean EventArgs).
Here you define events:
public event Action EventWithoutParams;
public event Action<int> EventWithIntParam;
And here you fire events:
EventWithoutParams();
EventWithIntParam(123);
You can find all the information you need at Action or Action<T>.
Either of these events can be initialised with a no-op delegate ... = delegate { }; so that you don't need to check for null before firing the event.
Try:
public event EventHandler Selected;
then to call..
Selected(null, EventArgs.Empty);
This way it's the default event definition and you don't need to pass any information if you don't want to.
You can just write:
public event EventHandler Selected;
(Maybe just the EventArgs base class?)
You should do exactly that.
From the MSDN Docs on EventArgs:
This class contains no event data; it is used by events that do not pass state information to an event handler when an event is raised.
Going by the PlayerIndexEventArgs type you mentioned, I am assuming you are using XNA, right? If so, take a look at the Game State Management sample. If not the code might help you understand how to do it anyway.

Categories

Resources