meds
meds

Reputation: 22956

UserControl is not being destroyed when an event is attached to it

I have the following line of code in a usercontrol:

Application.Current.RootVisual.MouseLeftButtonDown += RootClicked;

When it's defined the parent usercontrol is no longer collected by the GC or destroyed, the RootClicked event keeps firing even after it should no longer be active.

if I add:

Application.Current.RootVisual.MouseLeftButtonDown -= RootClicked;

The issue is no longer present.

Any ideas why this is? Is there a function I should explicitly remove the event?

Upvotes: 1

Views: 321

Answers (3)

Claudiu Mihaila
Claudiu Mihaila

Reputation: 1332

What happens: Application.Current.RootVisual.MouseLeftButtonDown event keeps reference to the control in its invocation list so the control is not eligible for collection (since it is referenced by the delegate).

Solution:

Subscribe to Unloaded event after you subscribe to the MouseLeftButtonDown event and unsubscribe form the MouseLeftButtonDown event in the Unloaded event handler:

 ...
 Application.Current.RootVisual.MouseLeftButtonDown += RootVisual_MouseLeftButtonDown;
 this.Unloaded += Control_Unloaded;
 ...

 void Control_Unloaded(object sender, RoutedEventArgs e)
 {
    Application.Current.RootVisual.MouseLeftButtonDown -= RootVisual_MouseLeftButtonDown;
 }

OR more concise:

Application.Current.RootVisual.MouseLeftButtonDown += RootVisual_MouseLeftButtonDown;
this.Unloaded += (s, e) => Application.Current.RootVisual.MouseLeftButtonDown -= RootVisual_MouseLeftButtonDown;

Upvotes: 2

Dave C
Dave C

Reputation: 441

This is a known behavior, but most developers are not aware of it. You should look into the Weak Event Pattern for information on how to get around this limitation in a more graceful (if more coding-intensive) fashion than having to manually remove event handlers.

Upvotes: 1

Salvatore Previti
Salvatore Previti

Reputation: 9070

This is a normal behaviour and a common source of memory leaks in .NET.

When you attach an instance method of object A to an event of object B, you are adding in the list of event receivers the instance of A, so the garbage collector cannot free up the object A until you remove the handler or you release every reference to both object A and B. This is an expected and normal behaviour.

There are two common ways to solve the problem:

1) You unsubscribe object A from the event when you don't need the object A anymore.

2) You use weak events, like WPF does. Weak events are usually implemented with the class WeakReference, you can find more informations on the web.

Upvotes: 3

Related Questions