When do I detach event handlers in a control? - c#

so I have a control whose panel attaches these events inside the panel's initialized event:
gvvm = DataContext as GraphViewerViewModel;
gvvm.ZoomToFitEvent += new EventHandler(_GraphViewerViewModel_ZoomToFitEvent);
gvvm.ZoomInEvent += new EventHandler(_GraphViewerViewModel_ZoomInEvent);
gvvm.ZoomOutEvent += new EventHandler(_GraphViewerViewModel_ZoomOutEvent);
gvvm.CloseVCDEvent += new EventHandler(gvvm_CloseVCDEvent);
gvvm.LoadVCDEvent += new EventHandler(gvvm_LoadVCDEvent);
gvvm.ScrollToTimeEvent += new EventHandler<GraphViewerViewModel.ScrollToTimeEventArgs>(gvvm_ScrollToTimeEvent);
Question 1. When should I detach the events? Is is appropriate to do so in panel.unloaded?
question 2. Is it appropriate to use events to communicate from your view model to your view? it seemed more reasonable than creating a property bool and doing actions in the panel based on the propertychanged event, though that has the advantage of not requiring me to subscribe/unsubscribe events. But the downside is I have to think of reasonable names for a property event toggle.

Answer to question #1 is yeaaahhh, kinda, Unloaded event should serve for releasing resources.
However if the event handler is living only inside the control and you know that the control is not gonna be added or removed from VisualTree constantly during runtime then you could let the garbage collector do the job for you. Means once nobody holds the instance to your control the garbage collector will collect all of it anyways.
Answer to question #2: Read what Bernard said. The communication between View and ViewModel should not exist. However the ViewModel may communicate with the View which is the case everytime you set a Binding or you use INotifyPropertyChanged interface.

Related

MvvmCross: Best way to raise event in ViewModel?

I currently have a View (Android Fragment) and a coresponding ViewModel. I now want to raise an event in the ViewModel which the View can subscribe to.
What's the best way to archive this? I heard a regular C# event (delegate) can lead to memory leaks? Is this the reason for the WeakSubscribe function? How to bind it to an event?
To prevent memory leaks in your views, every event you subscribed to needs to be unsubscribed from, either way using WeakSubscribe or subscribing to events as usual.
A common scenario would be subscribing on:
Android OnResume()
iOS ViewWillAppear()
then dispose the subscription on:
Android OnPause()
iOS ViewWillDisappear()
WeakSubscribe
If you want to "listen" for ViewModel property changes, WeakSubscribe comes in handy:
private IDisposable _selectedItemToken;
_selectedItemToken = ViewModel.WeakSubscribe(() =>
ViewModel.SelectedItem, (sender, eventArgs) => {
// do something
});
Just notice that WeakSubscribe() returns an MvxWeakEventSubscription that is also IDisposable. You need to save a reference to that subscription in your view and dispose it when thew view is no longer needed.
There are two reasons to keep that reference:
You can dispose it later
If you don´t keep it, your lambda event handler may not always work
Later on...
_selectedItemToken?.Dispose();
Normal event subscription
If you just need to subscribe to another kind of event (not property changes) in your ViewModel, you don´t actually need WeakSubscribe. You can just add an event listener to the ViewModel, as you would do with any object.
ViewModel.AnEvent += YourDelegate;
Later on...
ViewModel.AnEvent -= YourDelegate;
Don´t forget the last step. That will prevent memory leaks. As I said, Android OnPause() and iOS ViewWillDisappear() are good places to do it.
That way your ViewModel won´t be stuck in memory when the view is disposed thus your view can be garbage collected correctly.
You can create a leak if you subscribe to an event in a temporary object and don't unsubscribe before releasing the temporary object. Little chance for that in your case as the view model most likely will be created only once.
Since you are using mvvm, an alternative to events are Messengers which you can find implemented in popular mvvm-frameworks like MvvmLight or MvvmCross. This gives you truly decoupled events as you only need to know the format of the message and don't need to know anything about the sender (which in your case is the ViewModel). With messenger you only subscribe to a message-type and the sender can be anywhere in the app.

How to subscribe to an event without preventing garbage collection?

Let's say AppConfiguration.Instance is a singleton.
Now let's say my UI dynamically adds a button that should change it's text if the configuration is changed, so my app could do:
AppConfiguration.Instance.Changed += Changed_Handler;
On the button's code, but I don't wanna do that because that will prevent garbage collecion of the button after the user navigates to another screen and the button gets removed from the form
My question is: Is there a design pattern for listening to an event without preventing garbage collection asides from manually unsubscribing to the event with AppConfiguration.Instance.Changed -= Changed_Handler;?
After writing the and question and doing my last search-before-posting on weak bindings I came across the weak event pattern that does exactly what I want

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# 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.

Removing DataContextChanged/Loaded Event Handlers on XAML User Control

In efforts to reduce memory leaks, I am attempting to figure out whether, after adding a handler to the "DataContextChanged" event or the "Loaded" event on a XAML User Control, i.e. (UserControl.xaml.cs):
public MyUserControl()
{
InitializeComponent();
DataContextChanged += new DependencyPropertyChangedEventHandler(MyUserControl_DataContextChanged);
Loaded += new RoutedEventHandler(MyUserControl_Loaded);
}
If I need to remove it. Does WPF handle this, or do I need to remove them manually?
Short answer -- no.
You only need to remove handlers when they would keep an object rooted, meaning prevent its garbage collection. This will not happen if you create a child object and have one of its event handlers point into a parent object, because there are no dangling references to the child object.
It will happen if you create a child object and the parent object points one of its event handlers into the child object, because now the parent object has a reference to the child object that will keep it alive (rooted).
In the case you specify above, it's totally internal -- you are adding a reference to your own class, inside the class. When the user control is destroyed, it won't have references sitting around in another class' event handler. So you do not need to remove the event handler.

Categories