In my application, I am often creating new Views and ViewModels, but persisting the same Models. For example, I might show a simple view of a list of items in my main window, and have another window with further details of any particular item. The detail window can be opened and closed at any time, or multiple windows can be opened simultaneously for different items on the list.
Therefore, there can be more than one ViewModel for a given model object, and they need to be updated with changes from other places. (I'm using INotifyPropertyChanged
on my models.) I want to get rid of ViewModels when I am done with them, i.e., as the detail window is closed.
public DetailViewModel(MyDetailModel detailModel)
{
// Retain the Detail Model
this.model = detailModel;
// Handle changes to the Model not coming from this ViewModel
this.model.PropertyChanged += model_PropertyChanged; // Potential leak?
}
It is my understanding that the event handler will cause the Model to retain a reference to the ViewModel, and keep it from getting garbage collected.
1) Is this correct? How can I tell if these references are still present?
2) How should I determine the ViewModel is no longer needed and unsubscribe from the events?
I'm following on the answer of IAbstract, the WPF got this implemented directly via
PropertyChangedEventManager
, more can be found there.The final code might look like:
I'm a big fan of using
IDisposable
for this kind of thing. In fact, you can get excellent results using aCompositeDisposable
to handle all of your clean-up needs.Here's what I do:
What this lets you do is stick all sorts of clean-up code into a collection that automatically gets run once and only once when
IDisposable.Dispose()
gets called on your class.This is particularly nice for event handlers as it allows you to place add handler code next to remove handler code in your source and this makes refactoring much simpler. It's very easy to see if you are actually removing handlers if the code is next to the add handler.
To make this happen you need to add two classes to your code.
The first is
CompositeDisposable
:And the second - which is used in
CompositeDisposable
- isAnonymousDisposable
.The class
AnonymousDisposable
is used to turn anAction
into anIDisposable
so that the action is run when theAnonymousDisposable
is disposed.A further option that you can now use easily is the use of anonymous event handlers rather than needing to define private methods to handle the events.
You could use this in the constructor instead:
You can use method-level variables in lamdbas, so this option can help keep your module getting all cluttered.
Now, you could stop at this, but you might have noticed another
Add
overload in theCompositeDisposable
class that helps adding event subscriptions, like so:This does the entire work of subscribing and unsubscribing from the handler.
You can even go one step further and do it all in one line, like this:
Sweet, huh?
I hope this helps.
At first I thought this would be the way to go:
But then I found this beautiful nugget. So, there are at least two possible solutions: (a) sample implementing
IDisposable
, and (b) arguments againstIDisposable
. I'll leave the debate to you. ;)You may also consider the WeakEvent Pattern among others ...
You may want to consider using a Weak Event Pattern. I believe that Microsoft introduced
WeakEventManager
andIWeakEventListener
to solve this exact garbage collection issue.