The Weak Event Pattern

Microsoft made a good move with .NET 4.0 when they introduced the concept of a weak event pattern as a technique meant to address a glaring WPF memory leak issue that had the tendency of arising under certain conditions. You can read all about it here, but that aside, it helps to actually understand the problem that merited the creation of these techniques.

Memory leaks arising from lingering event subscriptions is an often misunderstood issue. Remember, in a CLR environment, memory is managed by the CLR’s own automatic garbage collector. In this context, a memory leak refers to a nonoccurrence of the collection of one or more objects which otherwise should have been collected according to standard expectations. Thus, assuming that the CLR garbage collector is “perfect” (it is quite good), the notion of a memory leak occurring should be a foreign one. But it can happen, and one of the preconditions for that scenario has to do with event subscriptions.

It’s not as simple as the presence of lingering event subscriptions, however. Let’s go over some incredibly rudimentary terminology:

  • One object exposes events that other objects can subscribe to. This object is the publisher of the event.
  • The objects which attach handlers to the publisher are subscribers of the event.

Why It’s Needed

From the subscriber’s point of view, I should always be sure to detach all handlers previously attached to the publisher as soon as it is practical. In fact, this requirement makes me a good candidate for a purely-managed focused implementation of the IDisposable interface. However, if I, as the subscriber, shirk these responsibilities, we aren’t necessarily guaranteed a memory leak. It is only when the lifetime of the publisher exceeds that of the subscribers will we have ourselves a memory leak. This is more of a matter-of-fact observation than a deep deduction; because subscribers have handlers attached to the publisher, the publisher will maintain a reference to those subscribers, and thus those subscribers cannot be collected.

This becomes a problem, especially when the subscribers need to die. An example that can occur is when you have some type of collection view or view model that contains children views or view models. This collection publishes an event that its children subscribe to. Whenever a child gets removed from the collection, we would very much want that child to be collected, especially if it is something significant such as a graphical view. Unless that child’s handler is detached, however, this collection won’t occur.

Many times the objects involved will lack the level of intimacy with each other required for one to know that that it needs to tell the other that it needs to clean up its event handlers. One of the constructs Microsoft developed in order to account for situations where associated objects lacked understanding of the internal behavior and structure of each other was the IDisposable interface. Unfortunately, WPF makes little to no use of this approach, which I believe is both odd and a major cause of all of these problems. Therefore, implementation of this interface will do nothing for you and your WPF-specific objects.

How to Use the Pattern

Making use of the weak event pattern is a rather simple affair:

  1. Create a new manager class derived from WeakEventManager
  2. Create a new implementation of IWeakEventListener
  3. Wire up the IWeakEventListener appropriately

Although it is a simple few steps one must complete, it is a bit burdensome to have to create new classes for each event or group of events coming from a specific source which we want to listen to weakly. There is a heavy use of static methods involved with this pattern as well, further restricting our options in regards to inheritable functionality.

Why does the pattern require specific types defined for specific events? The answer has to do with performance. It is possible to create a generic WeakEventManager, but your performance will suffer. Indeed, with .NET 4.5, we will see a generic WeakEventManager introduced by Microsoft. However, with it comes the warning I just provided: use of the generic variant of WeakEventManager will result in decreased performance. The performance trade-off most likely has to do with reflection cost as well as expectations by internal WPF components and processes which may have been optimized around an expectation of discrete manager types.

A Generic IWeakEventListener

With IWeakEventListener implementations, however, the story is different. Here we can easily devise a generic variant which we can easily use without worry of performance implications.

Here is an example of a generic IWeakEventListener implementation:

WeakEventListener.cs 
/// <summary>
/// Provides a generic weak event listener which can be used to listen to events without a strong reference
/// being made to the subscriber.
/// </summary>
/// <typeparam name="TEventArgs">
/// The type of <see cref="EventArgs"/> accepted by the event handler.
/// </typeparam>
public class WeakEventListener<TEventArgs> : IWeakEventListener
    where TEventArgs : EventArgs
{
    private readonly EventHandler<TEventArgs> _handler;

    /// <summary>
    /// Initializes a new instance of the <see cref="WeakEventListener{TEventArgs}"/> class.
    /// </summary>
    /// <param name="handler">The handler for the event.</param>
    public WeakEventListener([NotNull]EventHandler<TEventArgs> handler)
    {
        _handler = handler;
    }

    bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
    {
        TEventArgs eventArgs = e as TEventArgs;

        if (null == eventArgs)
            return false;

        _handler(sender, eventArgs);

        return true;
    }
}

Using this generic variant is quite simple: add it as a member to a subscriber class, and make a call to an appropriate WeakEventManager.AddListener method in order to register the weak event listener from the subscriber during its initialization.

Matt Weber

I'm the the Senior Software Architect at Emergingsoft where I lead the software development team. I am also the owner of this website. I enjoy well-designed code, independent thought, and the application of rationality in general. You can reach me at matt@badecho.com.

  2 Responses to “A Generic IWeakEventListener Implementation”

  1. Thanks. Hard to wrap your head around at first.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 
   
© 2012-2013 Matt Weber. All Rights Reserved. Terms of Use.