I assumed that Prism Regions would automatically detect and call Dispose
any views or view models that implemented the IDisposable
interface. Turns out I was wrong.
I then considered implementing IActiveAware
so I could dispose my views/viewmodels on my own, but that seems rather hackish. I'd rather have it done automatically.
How can I configure Prism Regions to automatically dispose my views and view models that implement IDisposable
?
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!
Modification of Nathan A
's answer for Prism 6 (IView
was removed) and uses a handy built in helper method to call Dispose an View and ViewModel.
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 || e.Action == NotifyCollectionChangedAction.Replace))
return;
foreach (var removedView in e.OldItems)
MvvmHelpers.ViewAndViewModelAction<IDisposable>(removedView, d => d.Dispose());
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With