I am using Prism for WPF, and I am having an issue disposing view models in a TabControl when the tab is closed. This is leading to a memory leak. I have IDisposable in my view and view models (VM) to perform necessary cleanup. The issue is that where I feel the need to call Dispose on the VM that the DataContext is null on the view.
The VM are auto wired in XAML:
prism:ViewModelLocator.AutoWireViewModel="True"
My custom RegionBehavior is below. My expectation is that Prism automatically sets the DataContext on the view. The view is populated with data from the VM so I'm not sure how the DataContext is null in Views_CollectionChanged. Note that when calling Dispose on the view that the DataContext is null in that method too.
Is this normal behavior? How should I call Dispose() on the VM that is being removed from the region in order to cleanup data & unsubscribe from events?
using Prism.Regions;
using System;
using System.Collections.Specialized;
using System.Windows;
namespace WpfProject.ModuleShared
{
/// <summary>
/// Code is pulled from PluralSight course download Mastering TabControl.
///
/// When a view is injected into a region the view goes into the Region Adapter first. The region adapter adapts the view to the region.
/// Such as a TabItem is created to create a new tab item and add the view to the tab item for display in the tab control region.
///
/// Region Behaviors can apply to all regions and not be limited to a single region adapter.
/// </summary>
public class RegionManagerAwareBehavior : RegionBehavior
{
public const String BehaviorKey = "RegionManagerAwareBehavior";
protected override void OnAttach()
{
Region.Views.CollectionChanged += Views_CollectionChanged;
}
/// <summary>
/// Associate the scoped RegionManager to the injected View.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">Contains new Views to be added to the region.</param>
void Views_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
. . .
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems)
{
InvokeOnRegionManagerAwareElement(item, x => x.RegionManager = null);
var view = item as FrameworkElement;
// view.DataContext is always null
var vm = view.DataContext;
// dispose the view model
var disposableVM = vm as IDisposable;
if (disposableVM != null)
disposableVM.Dispose();
// dispose the view
var disposableView = view as IDisposable;
if (disposableView != null)
disposableView.Dispose();
}
}
}
. . .
}
}
asoperator without checking the result for null.var view = item as FrameworkElement;is null when item is not a FrameworkElement, and the next code line would throw a NullReferenceException.e.OldItemsand each item in the collection's DataContext property is null. I believe there is something I do not understand about Prism and cleanup after removing a view from a region.