Normal event handlers are defined using the +=
operator and the source keeps a reference to its listeners. If this reference is not removed, it prevents the listener from receiving garbage data. This is one of the most common causes of memory leaks, which are now much easier to avoid.
WPF 4.5 WeakEventManager
provides us with a central event dispatching capability that allows the listeners to be de-allocated from memory, while the event is still alive.
While this is not a strictly new behavior, WPF 4.5 brings us enhanced support to set up a weak reference to an event. Prior to this version of WPF, we had to create a weak event manager for every event. This is not the case anymore. Now we can use a generic WeakEventManager
for this; let's see how it works.
Here we will implement some events with the WeakEventManager
class.
WPFWeakEvents
.MainWindow.xaml
view and add a Button Click event, name it btnRaiseEvent
, and put Raise an event…
in the content.MainWindow.xaml.cs
code and change the MainWindow
class code to this:public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // The leaking way // this.btnRaiseEvent.Click += btnRaiseEvent_Click; SetupWeakEventManager(); } void btnRaiseEvent_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Hey, use the WeakEventManager or I might leak..."); } private void SetupWeakEventManager() { WeakEventManager<Button, RoutedEventArgs>.AddHandler(this.btnRaiseEvent, "Click", btnRaiseEvent_Click); } }
WeakEventManager
class to handle the Button Click event in a proper way that will provide a safer event handling, which will not provoke memory leaks.We used the WeakEventManager
class, which provides us with a way to add and remove a handler through static methods, so we now have a much easier way to add weak event handlers.
Take a look at the WeakEventManager
generic class, pictured in the following screenshot:
To use the WeakEventManager
class, we only need to provide the type that raises the event and the type with the event's data. Next, we invoke the AddHandler
method, which requires the specific object that we are subscribing to, the event name, and the associated event handler.
We should also use the RemoveHandler
method to remove the event handler, which is a polite behavior for our code, wherever possible.
Before this WPF version, we had to implement the IWeakEventListener
interface on the event listeners, which is no longer required. However, it can still be useful in some scenarios—bear in mind that this is driven by reflection and thus has a performance penalty. This could be interesting for implementing a custom control or a library, avoiding performance penalties. Also doing so could be interesting for testing purposes.