SL5 Navigation in Prism: Content for the URI cannot be loaded

Topics: Prism v4 - WPF 4
Nov 7, 2012 at 6:52 PM
Edited Nov 7, 2012 at 7:07 PM

Hi,

I'm implemeting a wizard like window using SL navigation in a Prism application and encounter error "Content for the URI cannot be loaded". I looked at this link; http://compositewpf.codeplex.com/discussions/268440

and added RegisterType code but no success.

I created a bare minimum solution to show this (

https://skydrive.live.com/redir?resid=4F0CE6C357477187!121&authkey=!jAqYuAXpZr0%24

).

 The "Open Wizard" button suppose to open wizard widow using MainView.xaml but it errors out.

Can you help me with the problem? Thank you!

 

Developer
Nov 8, 2012 at 5:26 PM
Edited Nov 8, 2012 at 5:28 PM

Hi,

Based on my understanding, the cause of your problem is that the Silverlight navigation framework does not directly support the use of dependency injection containers, which you may need if you want to use views defined in different loosely coupled modules. As far as I know, the default Frame's ContentLoader only loads pages from the main application package (.xap file). Hence, you may not be able to directly target your views using the MappedUri property (e.g like in your MainView.xaml), unless the project where your views reside is being referenced by the main project, or this will cause the error you mentioned.

In order to avoid this problem without referencing your module projects, you will not only have to register your views in the container as you mentioned, but also you may have to extend the Silverlight default navigation system by setting the Frame's ContentLoader property to a custom INavigationContentLoader implementation, which is used by the frame to load the content associated with a specific URI, allowing to perform arbitrary URI resolution. For example this implementation could resolve the views from the dependency injection container based on the Uri passed. An example on how to implement a custom content loader that also integrates Silverlight Frame Navigation with Prism region navigation can be found in Karl Shifflett's blogs suggested by Guido Maliandi in the aforementioned related thread:

In my opinion these could be an useful starting point to achieve this kind of functionality.

As a side note if there is no specific requirement for using Frame navigation for your wizard, I believe you could also try using the Prism region navigation API instead, which by default support navigation to views in loosely coupled modules.

I hope you find this handy,

Agustin Adami
http://blogs.southworks.net/aadami

Nov 9, 2012 at 1:58 PM

In my case, the wizard is inside a module, so maybe using Prism navigation makes more sense?

The wizard is in a child window, when I resolve the region manager using Service.Location, it dosn't see the region defined in child window. Can you point me to a sample or a start how to use Prism navigation using child window?

Thanks for your help.

Developer
Nov 9, 2012 at 6:18 PM

Hi Julie,

Based on my understanding, the reason behind why the ChildWindow's region is not present in the RegionManager is because your ChildWindow has no RegionManager attached to it.

By default, Prism automatically attaches its main RegionManager to the RootVisual element of your Silverlight application. However, as far as I know, for any other element which is not part of the visual tree of your RootVisual element, you will need to set the RegionManager in it manually, for example, by using the following method:

RegionManager.SetRegionManager(childWindow, regionManager);

You can find a sample that uses navigation on a region inside a ChildWindow in the following SkyDrive account with the name RegionInChildWindowWithNavigation.zip:

I hope you find this useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Nov 13, 2012 at 2:59 PM
Edited Nov 13, 2012 at 3:16 PM

Hi Damian,

Thanks for the example. I was able to use it and converted to use Unity container. Manually set RegionManager was required to make my child window work, even you didn't need it in your example.

Now I'm trying to understand how this works. My child window is in the same location as Shell. Shell will recieve Prism events from different modules and open up child window with different views from those modules. I have this line in my ChildWindow constructor:

container.RegisterType<WizardChildWindow>(new ContainerControlledLifetimeManager());

And in my ShellViewModel, in event subscriber:

//ChildWindow wizard = ServiceLocator.Current.GetInstance<Main.Views.ChildWindow>(); This works too
ChildWindow wizard = this._container.Resolve<Main.Views.ChildWindow>();
RegionManager.SetRegionManager(wizard, _regionManager);
wizard.Show();
_regionManager.RequestNavigate("ChildWindowRegion", "ViewFromOtherModule");

In this implementation, is "RegisterType" in the right place? Should "Resolve" and "SetRegionManger" for ChildWindow only run once, so they should not be in event subscriber?

Using "RegisterType" in Unity is going to register an instance? There is the same instance of ChildWindow evey time child window is opened?

Thanks for your help!

Developer
Nov 13, 2012 at 6:24 PM

Hi Julie,

In my opinion, the registration of the ChildWindow type should not be in the constructor of that same type. Based on my understanding, by doing this the ChildWindow type would be registered again each time it's constructed, which can lead to unexpected behaviors. If the ChildWindow class is defined in the Shell project then you can register it during the bootstrapping process, for example in the ConfigureContainer method of your Bootstrapper class. On the other hand, if the class is defined in a module, you can register it in its Initialize method.

Based on my understanding, even if you are retrieving the ChildWindow from the container and setting its RegionManager each time the event is raised, it should not generate any problems in your scenario. As you are registering the ChildWindow type as a singleton (using the ContainerControlledLifetimeManager) each time you resolve it from the container you are obtaining the same instance of ChildWindow. Then, you are setting the same RegionManager and showing the same ChildWindow than before.

However, if you are planing to use always the same ChildWindow for the wizard, in my opinion it would be a cleaner approach to obtain the ChildWindow from the container and setting its RegionManager only once, for example, in the constructor of the ShellViewModel.

I hope this helps,

Damian Cherubini
http://blogs.southworks.net/dcherubini