Unity & Prism Navigation

Topics: Prism v4 - WPF 4
Jun 22, 2014 at 12:42 PM
Hello.

I am at the point of pulling out my hair - I register 2 views with a regionManager and at start up the correct view is loaded into the region.

I am trying to exchange / replace / deactivate / navigate the initial view with / to the second.
//Bootstrapper.cs
protected override void ConfigureContainer()
{ 
    base.ConfigureContainer();
    Container.RegisterType<object, StartupControl>(typeof(StartupControl).FullName);
    Container.RegisterType<object, MusicGeneration>(typeof(MusicGeneration).FullName);
}

//StartupViewModel.cs
//First attempt at navigation - StartupControl gets deactivated (and removed as it should)
//However <ContentControl regions:RegionManager.RegionName="mainContentRegion"/> //never swaps out the view to MusicGeneration

var region = regionManager.Regions["mainContentRegion"];
region.Deactivate(region.Views.ToArray()[0]);
region.Activate(region.Views.ToArray()[1]);

//I have done this as well, where view is the actual view
regionManager.Regions["mainContentRegion"].RequestNavigate(view.ToString());
///For reference - here is StartUpControl.cs

public partial class StartupControl : IConfirmNavigationRequest, IRegionMemberLifetime
    {
        public StartupControl(IUnityContainer container)
        {
            InitializeComponent();
            DataContext = container.Resolve<StartupViewModel>();
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            
        }

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

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            
        }

        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
        {
            continuationCallback(true);
        }

        public bool KeepAlive { get { return false; } }
    }
Please assist
Jun 25, 2014 at 9:47 AM
Just a question

What don't you use the Messenger approach in order to communicate between your views ?
Jun 26, 2014 at 5:52 PM
Hi,

There are a some issues with the approaches you are using to switch between views.
In the first approach, you are trying to access the views in the region using their positions in the collection.
var region = regionManager.Regions["mainContentRegion"];
region.Deactivate(region.Views.ToArray()[0]);
region.Activate(region.Views.ToArray()[1]);
When the first view is deactivated it is being removed from the region automatically (because you are returning false in the getter of the KeepAlive property) and therefore, the collection will no longer have two views. This means that accessing the element at index 1 in the next line will throw an exception, return a different view (if there were other views in the region besides the two you mention above) or have other undefined behavior.
However, even if the view were not removed from the collection, it is not a recommended practice to access the views through their position in the collection.

In the second approach you are trying to use the RequestNavigate method.
regionManager.Regions["mainContentRegion"].RequestNavigate(view.ToString());
However, take into account that the string you obtain from typeof(MusicGeneration).FullName might be different from the one obtained from view.ToString() (supposing that view is an instance of a MusicGeneration view.) To perform a navigation request the string passed as the view name should be the same as the one used when the view was registered with the RegisterType method.
Also, if the view is already in the region and its IsNavigationTarget method is returning false then the navigation request will disregard the existing view and create a new instance of it.

Based on the code you provided I think that the easier way to switch from the StartupControl to the MusicGeneration view is invoking the RequestNavigate view like this:
regionManager.Regions["mainContentRegion"].RequestNavigate(typeof(MusicGeneration).FullName);
With this, any other view in the region should be deactivated (as the region is used in a ContentControl) and removed (if their KeepAlive property returns false) and the second view should be shown in its place (the existing view (if any) if its IsNavigationTarget returns true or a new instance otherwise.)

Thanks,
Ezequiel Jadib
http://blogs.southworks.net
Jun 27, 2014 at 9:59 AM
Hello Ezequiel - thank you for responding

I must have forgotten to mention this - but at the time of doing this

var region = regionManager.Regions["mainContentRegion"];
region.Deactivate(region.Views.ToArray()[0]);
region.Activate(region.Views.ToArray()[1]);

I didn't have this

public bool KeepAlive { get { return false; } }

the view stayed in memory and was accessible through the debugger / immediate window. But still visible regardless

I have tried

regionManager.Regions["mainContentRegion"].RequestNavigate(typeof(MusicGeneration).FullName);

as well before but to no avail.

The views are being activated and deactived as expected, however, the first view i.e. StartupControl is never deactivated / removed, and thus always visible