Search code examples
wpfmefprism-6

MEF, Prism and new view instance on navigation


The code below worked on shared instance of the view. Now what I'm trying to achieve is each time I navigate to ViewB I want a new instance of the view and its backing view model. I have tried various combinations of the below but they all seem to ultimately end with the RequestNavigate failing silently the second time I try to navigate to ViewB...

I have also tried setting IsNaviagtionTarget to false after the view has been navigated to once.

Bootstrapper:

public void Initialize()
{
    _regionManager.RegisterViewWithRegion(RegionNameConstants.MainRegion, typeof(ViewA));
    _regionManager.RegisterViewWithRegion(RegionNameConstants.MainRegion, typeof(ViewB));
}

ViewB (class):

[RegionMemberLifetime(KeepAlive = false)]
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
internal partial class ViewB
{
    [ImportingConstructor]
    public ViewB(ViewBViewModel viewModel)
    {
        InitializeComponent();
        DataContext = viewModel;
    }
}

ViewBViewModel:

[Export(typeof(ViewBViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
internal class ViewBViewModel : BindableBase, INavigationAware
{
    public void OnNavigatedTo(NavigationContext navigationContext)
    {
    }

    public bool IsNavigationTarget(NavigationContext navigationContext)
    {
        return true;
    }

    public void OnNavigatedFrom(NavigationContext navigationContext)
    {
    }
}

ViewA simply has a button with a command that calls:

ViewA Navigation command:

public override void Execute(object parameter)
{
    _regionManager.RequestNavigate(RegionNameConstants.MainRegion, new Uri(nameof(ViewB), UriKind.Relative));
}

Solution

  • Don't register typeof(ViewB) with the region manager in the bootstrapper:

    public void Initialize()
    {
        _regionManager.RegisterViewWithRegion(RegionNameConstants.MainRegion, typeof(ViewA));
    }
    

    And since you are navigating to the Uri of nameof(ViewB), you should also export the view with a contract name of nameof(ViewB):

    [Export(nameof(ViewB))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    [RegionMemberLifetime(KeepAlive = false)]
    internal partial class ViewB
    {
        [ImportingConstructor]
        public ViewB(ViewBViewModel viewModel)
        {
            InitializeComponent();
            DataContext = viewModel;
        }
    }
    

    Then you should get a new instance of ViewB each time you navigate to it using:

    _regionManager.RequestNavigate(RegionNameConstants.MainRegion, new Uri(nameof(ViewB), UriKind.Relative));