After searching far and wide on the internet, and not finding any real solution, I developed my own custom RegionBehavior
, which turned out to work very nicely.
The behavior listens to the region's view collection for any changes, and when any are removed, it checks for and calls Dispose
on the view and/or view model, only if they implement IDisposable
.
class DisposeClosedViewsBehavior : RegionBehavior
{
protected override void OnAttach()
{
Region.Views.CollectionChanged += Views_CollectionChanged;
}
private void Views_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action != NotifyCollectionChangedAction.Remove) return;
foreach (var removedView in e.OldItems)
{
IDisposable disposableView = removedView as IDisposable;
IDisposable disposableViewModel;
var iviewView = removedView as IView;
if (iviewView != null)
{
disposableViewModel = iviewView.DataContext as IDisposable;
}
else
{
var frameworkElementView = removedView as FrameworkElement;
disposableViewModel = frameworkElementView?.DataContext as IDisposable;
}
disposableView?.Dispose();
disposableViewModel?.Dispose();
}
}
}
The final step is to plug this behavior into prism by overriding the bootstrapper ConfigureDefaultRegionBehaviors
method:
protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors()
{
var factory = base.ConfigureDefaultRegionBehaviors();
factory.AddIfMissing(nameof(DisposeClosedViewsBehavior), typeof(DisposeClosedViewsBehavior));
return factory;
}
Works like a charm!