When to remove event handlers from an object? - c#

So I am registering some event handlers in an object's loaded event.
tv.PreviewMouseDown += new MouseButtonEventHandler(SignalScrollViewer_PreviewMouseDown);
but I had two questions.
If loaded occurs twice and it tries to add the event handler again will there be problems?
How should I handle unregistering the event? Will it automatically handle unregistering on destruction or do I need to handle it in some event like unloaded or something?

Yes that will cause another subscription which causes the handler to execute twice. You can remove the loaded handler inside the loaded handler.
MSDN:
Loaded and Unloaded might both be raised on controls as a result of user-initiated system theme changes. A theme change causes an invalidation of the control template and the contained visual tree, which in turn causes the entire control to unload and reload. Therefore Loaded cannot be assumed to occur only when a page is first loaded through navigation to the page.
If the object is gone it cannot raise any events, so no need to do anything about that. And the handler will not keep the object alive (it's the other way around).

If loaded occurs twice and it tries to add the event handler again will there be problems?
The event will get subscribed multiple times. You may want to handle this scenario.
How should I handle unregistering the event? Will it automatically handle unregistering on destruction or do I need to handle it in some event like unloaded or something?
You can unregister it in Unloaded or similar. In general, you only need to do this if object on which the event you're subscribing will live beyond your lifetime. If it's an object within yourself (ie: subscribing to an event on a button within a user control, from the user control), unsubscription isn't required.

One normally subscribes to events from inside the constructor, i.e. immediately after the tv object gets created. If you keep those together, it's not possible to subscribe multiple times to the same tv object.

One would want to register event handlers in Loaded and remove them in Unloaded, so any objects which handle the event would have a defined lifetime. So, one would wish that every Loaded event occurs only once when the control is shown, and is followed by an Unloaded event when the control is removed from sight.
However, Loaded might be raised several times, depending on your layout: Expander causes Loaded to be raised twice, but Unloaded only once on controls inside the Expander, and TabControl might reuse the same controls for different TabItems (different data) without raising Loaded or Unloaded in between.
I found two ways to get around this: Either use DataTemplates (this helps at least in the TabControl case), or use the DataContextChanged event to register / unregister the events, which is a good way to ensure that the object which receives the events is always the current DataContext (i.e. ViewModel).
You might also want to check out the following link for more information on attaching and removing event handlers and other behaviours: http://wpfglue.wordpress.com/2009/12/11/the-sticky-component-framework/

Related

What is the difference between Form.Move and Form.LocationChanged?

If you create a standard C# WinForms application, you fill find that a form has two events: Move and LocationChanged.
Move is raised when the form moves and LocationChanged is raised when the form location property changes.
Surely if the form moves, the location property will change, too?
What is the difference between the two events? In which case will one fire and not the other?
The Move and LocationChanged events are declared on the Control class, which is then inherited by ScrollableControl, ContainerControl and finally Form.
According to the source code, OnLocationChanged calls OnMove before it invokes the LocationChanged event handler. So, the OnMove event will be raised first and then LocationChanged. You could in theory handle both events knowing that Move will be occur first.
If you look through the source you'll see that LocationChanged is raised when the bounds change (or similar events). You'll also notice that the only thing which actually invokes OnMove is in fact OnLocationChanged.
According to MSDN, the LocationChanged event:
Occurs when the Location property value has changed.... This event is
raised if the Location property is changed by either a programmatic
modification or through interaction.
It makes no such distinction for OnMove, where it merely states:
Occurs when the control is moved.
Which is curious since the two events are tied to each other.
This is however how one specific class handles these events. I did a bit of searching through the reference source and I couldn't find anything (inheriting from Control) which explicitly called OnMove other than the instance I've already cited. That doesn't mean they don't exist or that one couldn't invoke it separately in their own subclass of Control.
Both Move and LocationChanged events are interconnected. I believe there is no situation when one if fired and the other is not. The difference is that they belong to different categories of events.
The Move event has [SRCategoryAttribute("CatLayout")] attribute.
The LocationChanged event has [SRCategoryAttribute("CatPropertyChanged")] attribute.

What's the benefit of manually adding / removing event handlers, instead of assigning them through the UI?

At work, my old boss would insist we programmatically assign and remove event handlers from our controls in the code behind, rather than simply double clicking a button (for example).
We'd have an AttachEvents() and DetachEvents() method on every single form. I don't remember his explanation as to why this is allegedly better than assigning it from the Design View, and he's since been transferred to a different project. My new manager doesn't know.
I thought he said it had something to do with events not properly being removed from memory, but I really don't know.
So: What is the benefit of doing it this way?
Performance-wise they are the same.
But doing it in the code behind is a much neater way since you control when to AttachEvents() or DetachEvents()
But you have to be careful in terms of avoiding any duplicate event wire ups. These in turn might lead up eating memory, but prominently they would cause performance issues since the event handler would be called as many times as it was wired up.
Some event handlers such as timers need to be removed before leaving a form otherwise they would still fire, for example
timer.Elapsed += ...
and
timer.Elapse -= ...
Probably a good and clear way to remember to do it in this way.
Other than the implications of your own architecture, there's no difference whatsoever.
The designer will place the event subscriptions on the InitializeComponent method and you should not do any changes to that method because the designer might override them or crash if it's something it can't handle.
Usually, the event subscriptions are events the form subscribes from its children. When the from is closed/disposed, all the children are disposed and each child will dispose event subscriptions.
Problems arise when the form subscribes to outside components. Then the form becomes "attached" to those components and, if not unsubscribed, becomes a resource leak.
There's also the possibility of events being fired when the form is not ready to handle them.
I've used a mixed approach where events from child controls were subscribed in the designer (or carefully manually coded in the InitializeComponent method) and used the AttachEvents/DetachEvents approach for components outside the UI (or the scope of the form/control).

WPF Window eventhandler

So we know that if you attach an event handler, we should remove it at some point if the object is not being used anymore. How does this work for Window objects?
Take for example, the Window's Loaded event, or Closing event. If we register the EventHandlers to handle these events in the Initialize method, why don't we ever unregister them?
Because it is not a big deal. Usually you subscribe to the event in the derived class itself, so you will not cause the instance to linger in memory because of a stray event handler subscription. Also you will need the Closing event handler until the very end of the Window's lifetime, there is no point in unsubscribing from it.

When to wire up event handlers asp.net

Let's say we have a pretty standard form with a textbox and a button (for simplicity). You want to handle a Click event and do some stuff based on user's input.
I was wondering, does it matter, when exactly you wire up an event handler for the Click event in a code-behind? If it does, where is the best place to put it? Page load? Page init? I've tried both places, but didn't notice any difference. Or it's just a personal preference of the programmer? I've already searched the internet couple of times, but haven't found any satisfactory answer.
I know when the actual method execute, just not sure about the wiring-up part.
As you know, there are several Page_xxx event handlers, like Init, Load, Prerender... This events exist in Controls, and Pages as well as User controls (in fact they're derived form Control, which holds all these events).
This events are related to the ASP.NET Page Life Cycle
If you read the page pointed to by this link carefully you will understand when the events are triggered. So, if you bind your event handler in any page lifecycle event that happens before the events are triggered, it's guaranteed that your event handlers will be bound in time to be triggered.
These are the main lifecycle steps:
PreInit -> Init -> InitComplete -> PreLoad -> Load -> [Control events] ->
LoadComplete -> PreRender -> SaveStateComplete -> Render -> Unload
Not all of them have associated events, but, if it's necessary you can override the corresponding OnXxx() function, like OnPreInit(). (This is usually only done on custom server controls).
You can bind events in Page_Init or Page_Load, because the control events are triggerd after the loading of all the controls has finished. The Load step happens in top-bottom way, first in the Page, and then recursively in all the children controls.
After Load finishes, the first events which are triggered are the Change Events, like TextChanged or SelectionChanged. Then are triggered all the other events, like Click.
If you bound the events in PreRender or Unload, they wouldn't be triggered. If you did in Init or Load, they would.
So it could look like it's safe to bind in Init or Load, but that's not true:
It could look like there's no special reason to bind them on Init or Load, because they'll be triggered later in the page life cycle. But, as the binding defined in the .aspx happens during Init, a programmer will expect that all events are already bound in the Load event. What would happen if this programmer raised an event of a child control in code behind? The Load event happens first in the root of the control tree, and them on all of the children, recursively. So, by the time the programmer is trying to raise the event of the child control, it won't be already bound. So this won't work as expected. This is more than enough to consider unsafe to bind events in Load event. That's why you should always bind events in Init.
Look at this diagram to see the order of execution of Page & children events:
ASP.NET Page Life Cycle Diagram
I have been wiring mine up in the control tag. If I do it this way it is clear that an event handler is present.
<asp:Button ID="btnRefresh" runat="server" Text="Refresh" OnClick="btnRefresh_Click" />
If I had to wire up an event handler in the codebehind, I would put it in Page_Load as a private function call.

C# Should I manually remove the event handler I declared?

Okay, make an example here:
I have UserControl A, UserControl B, UserControl C and one Windows Form.
This Windows Form is only started with UserControl A.
UserControl C has [Next] and [Back] buttons.
Say, UserControl A is declared with an event handler. One of function in UserControl A will actually raise the event call to execute one function at UserControl C.
So, at UserControl C, I have to add with
"UserControlA.OneFunction += this.UserControlC_Function;"
If I click Next button at UserControl C, it will dispose the UserControl A and add new UserControl B to the Windows Form. But I never remove this event handler manually.
One of the function in UserControl A is the caller (where event is declared).
One of the function in UserControl C is the listener.
So, these are my questions:
Should I manually remove the handler before UserControl A disposed?
Will this User Control A dispose automatically remove the handler that declared previously?
Should I add this somewhere?
"UserControlA.OneFunction -= this.UserControlC_Function;"
By convention, we don't. And since no event should be invoked after disposal, there is no need to do so unless the control in question is behaving weirdly.
No. At least there isn't such code as seen from reflector.
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.
The answer to this post does a really good job explaining when you need to manually remove an event handler and when it is not necessary.
Do I need to remove event subscriptions from objects before they are orphaned?
If the form is released (assuming no other objects has a reference to the objects in question) there's little risk of not removing the event handler, however it's a good idea always to remove the event handler before the object listening can no longer be reach (ie all variables referencing the object i sout of scope) not doing so can create a memory leak.
This is not the case in your situation (if I get what you are describing, code would make it more clear)
The problem would be if you attach a delegate referencing object C to an event on object A and then looses access to C (e.g. assigning a new value to the variable). C would then hang around until A is garbage collected
If the memory lifetime of an event publisher is not limited relative to the useful lifetime of an event subscriber, failure to unsubscribe an event will likely cause a memory leak. Were it not for the unfortunate hassle of doing so, there wouldn't be any reason for an event subscriber that was being disposed not to unsubscribe from all events, and for an event publisher that was being disposed not to nullify all event subscriptions. Since neither C# nor VB provides any convenient means of doing those things, however, one has to balance the hassle of proper subscription handling with the fact that in many situations one can get away skimping on it.

Categories