Apologies in advance for the long post. I'm having a hard time understanding if/how/when views and view models are cleaned up and GC'd/disposed.
Some background on my app: it's WPF and Prism 4.1, and I'm using Castle Windsor as my IoC. The app consists of a "main" window containing a region into which I load a "results" view. The "results" view contains a number of regions
of its own - these always show the same view, so they are loaded using the "regionManager.RegisterViewWithRegion" notation during application startup. These child regions do not participate in navigation at runtime.
All views and view-models are registered with Castle as "transient". View-models are decorated with the "[RegionMemberLifetime(KeepAlive = false)]" attribute, and the views include the "ClearChildViewsRegionBehavior.ClearChildViews="True""
attached property. View-models are injected into their corresponding view's constructor (I believe this is "view first"?).
Despite all this, if I navigate away from the "results" view (using
regionManager.RequestNavigate), it seems that neither this view/VM, or any of its child views/VMs are being GC'd/disposed. I've tried implementing IDisposable on all the views and VMs, but Dispose() never gets called.
My main concern is to avoid memory leaks - my "results" view, and its child views, render a huge amount of information (based on records in a db), and if the user continually navigates in and out of this view, viewing these records, it's going to
eat up memory. Also, I've implemented an "events service" (similar to Prism's event aggregator) where the VMs register as event publishers and/or subscribers. I'm finding that even after navigating away from the "results" view, its VM and
the child VMs, are still responding to events - further evidence that things aren't being cleared up.
I guess I need some way for the child VMs to cleanup, including unsubscribing from these events, when the parent "results" view is navigated away from, but how/where? IDisposable.Dispose() seemed like the ideal place, but it's not being called - whether
that's down to Castle or Prism, I don't know.
One other option might be to change my approach and register all the views and VMs as "singletons", avoiding such memory concerns. However I still might want to perform some cleanup on the child VMs, so how/where could I do that?
Thanks in advance
Based on my understanding, the RegionMemberLifetime
attribute is only in charge of telling if the VM has to be removed from the Region or not, which does not force the destruction of the VM. Therefore, the root of your problem is more likely
to be related to the "events service" you implemented, since the subscription to these events are
to your VMs which causes them to be kept alive and responding to events.
In order to be able to resolve this, you can choose between the following 2 options:
- Make your VMs implement IActiveAware which provides the
IsActive property. Then, in the setter of the property you verify if
its value and RegionMemberLifetime are false so you can do the cleanup.
- On the other hand, you can make your VMs implement INavigationAware and the just check if
RegionMemberLifetime is false in the OnNavigatedFrom method (provided by INavigationAware) and do the cleanup there.
Hope this helps,