How to create a new view every time navigation occurs in PRISM?
Asked Answered
S

3

6

I'm using WPF4 and PRISM4 for my new project.

There is a single module with several views in it. The DI is done with unity. When I navigate from ViewA to ViewB for the first time, the ViewB is created and its constructor is called. But when I try to navigate to ViewB for the second, third time, the ViewB is not created, but existing instance is reused.

I'm using IRegionManager.RequestNavigate for my navigation purposes.

I've tried to pass TransientLifeTimeManager to RegisterType Unity methods, but to no avail.

Is there a way to configure prism and/or unity to create a new view every time I navigate to it?

Thanks.

Sherronsherry answered 25/2, 2011 at 9:17 Comment(0)
G
18

The way to do it is to implement IRegionMemberLifetime on your either your view or viewModel, and return false in the boolean property KeepAlive as follows:

public class EmployeeDetailsViewModel : IRegionMemberLifetime
{
    public bool KeepAlive
    {
        get { return false; }
    }
}
Gidgetgie answered 25/2, 2011 at 15:28 Comment(2)
This is not quite correct, because it has the side effect that if the user switches active views through the UI then your EmployeeDetailsView will be removed from the region instead of simply being deactivated.Garbo
I am indeed assuming that he wants to remove the view when it's navigated from, and if I'm mistaken then he would have corrected me. We are interpreting his request differently - I really don't see why this would make you vote -1, as if my answer is incorrect.Gidgetgie
G
20

The correct way to do this is by implementing INavigationAware either in your View or your ViewModel (Prism will check first the view, and if it doesn't implement INavigationAware it will also check the ViewModel).

You are interested specifically in the IsNavigationTarget method, which tells Prism if the current instance of the View should be reused, or if another instance should be created to satisfy the navigation request. So, to always create a new View you would do:

public class MyViewModel : INavigationAware {
    bool INavigationAware.IsNavigationTarget(NavigationContext navigationContext)
    {
        return false;
    }

    void INavigationAware.OnNavigatedFrom(NavigationContext navigationContext)
    {
    }

    void INavigationAware.OnNavigatedTo(NavigationContext navigationContext)
    {
    }
}

All of this is explained in greater detail in Chapter 8 of the Prism 4 documentation; they also have an illustration of how it works, which is very nice because it also lets you know exactly where you can hook in and how.

Garbo answered 4/3, 2011 at 12:50 Comment(2)
A small addendum, if using MEF for dependency injection you should ensure that your view has the attribute [PartCreationPolicy(CreationPolicy.NonShared). Otherwise, the ServiceLocator will return the same instance regardless of the IsNavigateTarget logic. The navigation service sees that the region already contains the instance and activates it. I was puzzled for a long time.Cyst
This actually fixed my opposite problem. My condition was incorrect thus returning false all the time.Laroy
G
18

The way to do it is to implement IRegionMemberLifetime on your either your view or viewModel, and return false in the boolean property KeepAlive as follows:

public class EmployeeDetailsViewModel : IRegionMemberLifetime
{
    public bool KeepAlive
    {
        get { return false; }
    }
}
Gidgetgie answered 25/2, 2011 at 15:28 Comment(2)
This is not quite correct, because it has the side effect that if the user switches active views through the UI then your EmployeeDetailsView will be removed from the region instead of simply being deactivated.Garbo
I am indeed assuming that he wants to remove the view when it's navigated from, and if I'm mistaken then he would have corrected me. We are interpreting his request differently - I really don't see why this would make you vote -1, as if my answer is incorrect.Gidgetgie
F
1

It internally looks for a View in ActiveViews property of a region. If it does not exist in there, it creates a new one and adds it to ActiveViews for future use.

To accomplish what you want to do, you will need to remove or clear ActiveView collection before navigating to any View.

Example:

public static class RegionManagerExtensions
{
    public static void RequestNavigateEx(this IRegionManager regionManager, String regionName, Uri source)
    {
        if (regionManager != null)
        {
            IRegion region = regionManager.Regions[regionName];

            if (region != null)
            {
                foreach (Object view in region.ActiveViews)
                {
                    region.Remove(view);
                }

                regionManager.RequestNavigate(regionName, source);
            }
        }
    }
}
Fob answered 25/2, 2011 at 9:50 Comment(2)
Hey, I tried to do this and end up with a blank view. is there something i'm missing?Poetess
The view doesn't have to exist in the Active View property; the view also won't be recreated if it exists in the Views property.Vituperate

© 2022 - 2024 — McMap. All rights reserved.