Message, WeakReference & Garbage Collection

Dec 15, 2009 at 3:52 PM

I'm having some problems using the Messenger. I have a View and ViewModel. When the View is created it registers for Message A. When the View Model receives a particular command a notification of Message A is sent by the View Model, and the View creates a new dialog.

The problem comes when the View is reopened (after being closed down). When the View is reopened it once again registers for Message A. But now when the View Model receives a particular command and a notification is sent by the View model, there are two actions. The new action is fine and is the desired one, but the old action (from the first time the View was created) is a problem because its target, the original View, is awaiting garbage collection and so invoking the action causes unwanted results.

The check in Messenger to ascertain whether the action's target is dead does not help in this situation because the target is awaiting garbage collection, but has yet to be garbage collected.

Is there a way to overcome this issue short of (a) implementing Unregister on Messenger, or (b) limiting message-action mapping to one action with a given signature for each message?

Dec 17, 2009 at 9:01 AM

The solution I have used to this problem is to modify Messenger to include an optional guard function alongside the action. During notification the action is then only called if the guard check passes.

This solves the problem in the case of an expired View, because the guard can check whether the View is active and if the View is inactive the action is not invoked. This allows for an expired View to be garbage collected naturally.

Oct 14, 2010 at 6:31 PM

Can you explain exactly what you did?  How do you know if the view is active? or inactive?  What is the guard you created?

 

Apr 26, 2011 at 8:07 AM

I modified Messenger.WeakAction to include a guardMethod, guardTargetRef and guardDelegateType and then created overloads of Messenger.Register to register a Func<bool> (i.e. the guard) alongside the callback. When NotifyColleagues is called the action is only invoked if the guard succeeds (or if the guard is null).

The guard I use to find out whether a View is active is simply the IsVisible property.