Subscribing to change notifications without memory leaks

You know this feeling? You are doing the best you can to prevent memory leaks by correctly unsubscribing from all events, and then you hit that object from which you cannot determine the lifetime. Well, you have a few options:

  1. Don’t talk about it, maybe your app won’t be used that much so maybe nobody notices.
  2. Try to implement IDisposable, but when to call that, you don’t know the end of life of the object?
  3. Fix the issue, but how?!

Note that this solution works on .NET, Silverlight, Windows Phone and WinRT. It doesn’t matter whether you use ASP.NET MVC, MVVM in WPF of your own custom pattern.

How do I create a memory leak?

Creating a memory leak is very easy. Simply subscribing to change notifications of objects mostly results in large statements such as the one below:

var itemAsPropertyChanged = obj as INotifyPropertyChanged;
if (itemAsPropertyChanged != null)
{
    itemAsPropertyChanged.PropertyChanged += OnPropertyChanged;
}

What is the solution to prevent memory leaks?

You can either use the WeakEventListener in Catel or use the brand new ChangeNotificationWrapper that is now available in the latest prerelease version of Catel on NuGet. The ChangeNotificationWrapper allows the subscription of both the INotifyPropertyChanged and INotifyCollectionChanged interfaces using weak events, thus preventing memory leaks.

Subscribing to events of an observable object

Using the code below, one can subscribe to the PropertyChanged event of an object:

var wrapper = new ChangeNotificationWrapper(obj);
wrapper.PropertyChanged += OnPropertyChanged;

Note that it is not required to check whether the object implements INotifyPropertyChanged, the wrapper does it automatically

Subscribing to events of an observable collection

Using the code below, one can subscribe to the CollectionChanged event of an object:

var wrapper = new ChangeNotificationWrapper(observableCollection);
wrapper.CollectionChanged += OnCollectionChanged;

Note that it is not required to check whether the object implements INotifyCollectionChanged, the wrapper does it automatically

Advanced scenario with observable collections

Sometimes it is required to watch both changes inside a collection, but also the items inside a collection. For example, there is a list of customers and you are also interested in changes of customers inside a collection. This is fully supported by the ChangeNotificationWrapper using the code below:

var wrapper = new ChangeNotificationWrapper(observableCustomerCollection);
wrapper.CollectionChanged += OnCollectionChanged;
wrapper.CollectionItemPropertyChanged += OnCollectionItemPropertyChanged;

All subscriptions are automatically managed by the ChangeNotificationWrapper when items are added or removed from the collection.

Unsubscribing from events

When you are no longer interested in events from the source object, there are two options:

  1. Just leave them coming, as soon as the objects are no longer used, they will be garbage collected
  2. Unsubscribe using the following code:
wrapper.UnsubscribeFromAllEvents();

Grabbing the bits

As always, Catel is open-source thus you can either check out the source or grab the latest bits via NuGet.