C# - Removing event handlers - FormClosing event or Dispose() method - c#

Suppose I have a form opened via the .ShowDialog() method.
At some point I attach some event handlers to some controls on the form.
e.g.
// Attach radio button event handlers.
this.rbLevel1.Click += new EventHandler(this.RadioButton_CheckedChanged);
this.rbLevel2.Click += new EventHandler(this.RadioButton_CheckedChanged);
this.rbLevel3.Click += new EventHandler(this.RadioButton_CheckedChanged);
When the form closes, I need to remove these handlers, right?
At present, I am doing this when the FormClosing event is fired.
e.g.
private void Foo_FormClosing(object sender, FormClosingEventArgs e)
{
// Detach radio button event handlers.
this.rbLevel1.Click -= new EventHandler(this.RadioButton_CheckedChanged);
this.rbLevel2.Click -= new EventHandler(this.RadioButton_CheckedChanged);
this.rbLevel3.Click -= new EventHandler(this.RadioButton_CheckedChanged);
}
However, I have seen some examples where handlers are removed in the Dispose() method.
Is there a 'best-practice' way of doing this?
(Using C#, Winforms, .NET 2.0)
Thanks.

You don't need to remove the handlers in this case because neither the form nor its buttons are referenced by code external to the form, and the entire object graph will therefore be garbage collected.

No, you don't need to remove the event handlers from controls on the form that is closing. They will all be disposed together.
You're probably thinking of web pages where removing event handlers is needed to avoid memory leaks in the browser.

Related

Unregistering all events to release memory

I have a program which allows the editing of product information. I noticed that it was not releasing memory after closing the editing forms. After some research I stumbled upon this question which mentions that the problem may be that it is hanging on to event subscriptions.
That made sense to me because this form has about 100+ controls on it, many of which are custom with custom events which are subscribed to by their parent controls. This creates a pretty large hierarchy of event subscriptions. So I looked for a way to release these and found this which allows you to unsubscribe from that event.
The problem is, I have a ton of subscriptions. Do I really have to manually unsubscribe from each event one by one on form close, or is there at least a way to release them in one fell swoop, or loop through them?
Remember this: The object on the LEFT of the += keeps alive the object containing the method on the RIGHT of the +=. That is, the object that raises the event keeps alive the object that handles the event, even if the object (such as a form) that handles the event is disposed.
So the thing you need to ensure is that all the event-raisers have gone away.
However, if all the event-raisers happen to be controls in the same Form class that subscribes to those events, you will not need to manually unhook all the event handlers when the form is closed.
This is because the controls that raise the events to which to form has subscribed have the same lifetime as the form itself.
You only need to worry if you subscribe to events raised by an object that has a longer lifetime than the object that is subscribing. Then the subscribing object (the form) would need to unsubscribe when it (the form) is disposed.
It depends on how long your form and its events will be living.
However, you can loop through your controls within the form, releasing the events.
If you remove a nonexisting event accidentally - don't worry, it won't throw an exception.
For example, this is how to get rid of all your TextBox.KeyDown-Events:
private void frm_FormClosed(object sender, FormClosedEventArgs e)
{
foreach (Control tb in this.Controls)
{
if (tb is TextBox)
{
TextBox tb1 = (TextBox)tb;
tb1.KeyDown -= TextBox_KeyDown;
}
}

C#: Multiple Event Raises

My question is related to events:
I have Class with a TaskAComplete Event that is raised when TaskA is complete.
When a button is pressed I subscribe the TaskACompleteEvent
MyObject.TaskAComplete += new EventHandler(MethodToCall);
But in other Event I want to Unsubscribe from the TaskAComplete Event when the Event occurs the first time.
with:
MyObject.TaskAComplete -= MethodToCall;
And then when the Button is pressed the next time to Subscribe the TaskAComplete Event again.
Now when i start the Application and click on the Button the first time it raises the Event correctly.But when i click on the Button the second time the Event is raises two times in a row. (Third time click ->Event is raised three times in a row and so on..)
When i Subscribe the Event in the Contructor of the Form it only raises one time at every click.
Why the Event comes several times?
When you subscribe to an event, you are subscribing by providing a delegate to a method. A delegate is effectively a strongly-typed, object-oriented approach to a C/C++ function pointer.
This delegate then goes into the list of calls for the event.
When you do new EventHandler(MethodToCall) you are explicitly creating that delegate. However, when you do -= MethodToCall, you are removing an "automatic" delegate. It is as if you wrote -= new EventHandler(MethodToCall). Obviously, this new delegate is not the one in the invocation list.
To do what you want, on add, you need to save the new delegate in a variable, which you can later remove. For example:
var handler = new EventHandler(MethodToCall);
MyObject.TaskAComplete += handler;
// later on
MyObject.TaskAComplete -= handler;
You only need to subscribe to the event once. If you subscribe multiple times with the same handler, that handler will be invoked multiple times just like you are seeing.
Why do you want to unsubscribe from the TaskAComplete event in the first place? If your other code is correct, you will get it exactly once for each task.

Event handler for a UserControl doesn't fire

My UserControl contains various controls. I made an event handler for its click event. I want the event handler to fire / be called when the user clicks anywhere on my user control.
This is the method I use to add my UserControl to my WinForms application.
private void addContact(some parameters here)
{
//This is my usercontrol
contactsListItem.contactsListItem contact = new contactsListItem.contactsListItem();
//
//some codes here
//
//Adding an event handler for the click event
contact.Click += new EventHandler(contact_Click);
//Adding the UserControl to my application
flowLayoutPanel_contactsList.Controls.Add(contact);
}
The contact_Click(...) event handler should change the background of my UserControl. I have tried stepping into the code to see if the event handler fires and I found out that it doesn't fire no matter where I click on my UserControl.
I have searched through the internet. I encountered terms like delegate, subscribers and publishers.
What should I do to make the event handler for my UserControl's click event to fire?
What is the structure of your user control? Click events are not bubbled in WindForms, hence if you are clicking on a control WITHIN your user control, the latter won't fire any Click event.
EDIT:
The simplest solution is to manually bubble the event from each child by attaching a handler in your user control:
child1.Click += new EventHandler(child_Click);
child2.Click += new EventHandler(child_Click);
child3.Click += new EventHandler(child_Click);
and inside child_Click fire off your Click event:
this.OnClick(e);
You seem to be on the right track however it is not clear what your contact here is. Typically you use delegates (essentially pointers to functions) for methods that have arguments to be passed:
if (bDeleteRdClick)
DeleteRD.Click -= delegate { DeleteRDClick(this.Object); };
DeleteRD.Click += delegate { DeleteRDClick(this.Object); };
where you are sure to remove pre-existing delegates, otherwise they will 'stack-up', firing multiple methods when not required.
For the method above, using an EventHandler seems to me to be the right approach, but as I state above, a check on whether contact is of the correct type would not go unmissed:
if (this.contact.GetType() == typeof(RibbonButton))
{
RibbonButton Rb = (RibbonButton)contact;
Rb.Click += new EventHandler(contact_Click);
}
I hope this is of some help.

What does it means in C# : using -= operator by events?

When must we use this operator by events? What is its usage?
Just as += subscribes you a handler to the event, -= unsubscribes it.
Use it when you no longer want a particular handler to be called when the event is raised. You often only need to use it the component raising the event is logically longer lived than the handler of the event - if you don't unsubscribe, the "event raiser" effectively has a reference to the handler, so can keep it alive longer than you want.
As noted in comments:
-= will only remove a single handler; if there are multiple handlers subscribed (even using the exact same delegate) it will still only reduce the handler count by 1. The last instance of the specified handler is the one removed. (So if you previously had handlers A, B, A, C subscribed in that order, and removed A, you'd end up with A, B, C.)
-= doesn't cause an error if the specified handler is not subscribed to the delegate already; it just ignores the request. This is true even if the event has no handlers subscribed to it at the moment.
Just as you can add event handlers via +=, you can remove them via -=.
For instance:
mybutton.Click += new EventHandler(myhandler);
You can later remove it like this:
mybutton.Click -= new EventHandler(myhandler);
...because event handlers for the same method and instance are equivalent (so you don't need to retain a reference to the handler you used with += and use that one with -=).
The += and -= operators can be used in C# to add/remove event handlers to/from one of an object's events:
// adds myMethod as an event handler to the myButton.Click event
myButton.Click += myMethod;
After the above code runs, the myMethod method will be called every time myButton is clicked.
// removes the handler
myButton.Click -= myMethod;
After the above code runs, clicking on myButton will no longer cause myMethod to be called.
You remove the Eventhandler Function.
C# Tutorial, Events and Delegates
I suspect that the background logic of the += is to add the handler to a list/array of event handlers for the given event. When -= is used, it compares your right hand argument to the list of event handlers it is holding for this event and deletes it from the list. If you do multiple += for a given event, each handler will get called.
Stated differently:
+= means add a method to the list of methods to call when the event occurs.
-= means remove the specified method from the list of methods to call.
If all are removed, the event will have no handlers and the event will be ignored.

Throwing events through objects

I'm developing a Windows Mobile 5.0 or above application with .Net Compact Framework 2.0 SP2 and C#.
I have a Winform (Form1) with a control (Control1) that contains another control (Control2). For example, a winform with a panel and inside this panel there is a button, but in my case Control1 and Control2 are custom controls.
Control2 has an event, Click, that is thrown when the user does click over it. This click event must be handled by Form1. To do it, first I handle the event on Control1 that throws a new event that is handled on Form1. This my code:
On Control1:
public event EventHandler Control2Click;
private void control2_Click(object sender, EventArgs e)
{
if (Control2Click != null)
{
Control2Click(sender, e);
}
}
On Form1:
private void control1_Control2Click(object sender, EventArgs e)
{
// Do something interesting.
}
Is there a better way to handle Control2_Click directly in Form1? I don't know if my way has a bad performance and this kind of events can be handled better.
Thank you!
No, you are doing it right. It is the correct way the bubble an event out of a nested control that isn't directly accessible from a container control. You'd normally use the PerformClick() method to fire the Click event but this doesn't appear to be available in CF.
Perf is not an issue, calling a delegate target is very fast, a dozen nanoseconds or so on a desktop machine. Click is a "human-time" event, anything less than 20 milliseconds is perceived as "instant".
What's stopping you from hooking up the Control2 Click event directly from Form1? Does Control1 expose Control2 via a property? Or perhaps expose an event on Control1 which actually hooks up to the Control2 Click event? For example:
// In Control1
// Assuming Control2 is some sort of Save button, for example
public EventHandler SaveClicked
{
add { control2.Click += value; }
remove { control2.Click -= value; }
}
Note that:
If you change the value of control2 within Control1, the event handlers won't be "transferred" which would be be unfortunate
The sender parameter in the event handler will refer to Control2, not Control1
To be honest I wouldn't expect this to be a performance problem however you handle it - it's just a delegate invocation or two.

Categories