I am building a demo app to learn the navigation features of Prism 4. The app has two modules--each one has three Views:
- A UserControl with a text block ("Welcome to Module A")
- A RibbonTab (using a Region Adapter), and
- An Outlook-style Task Button (like Outlook's Mail, Calendar, and so on)
The Shell has three named regions: "RibbonRegion", "TaskButtonRegion", and "WorkspaceRegion". The Views load into these regions. To test the basic setup, I registered all three Views with the Prism Region Manager, so that they would load at startup, and all worked as expected.
Next, I modified the setup so that only the Task Buttons would load on startup. Other Views would load only on request, by clicking a Task Button. My module initializers look like this:
public void Initialize()
{
/* We register the Task Button with the Prism Task Button Region because we want it
* to be displayed immediately when the module is loaded, and for the lifetime of
* the application. */
// Register Task Button with Prism Region
m_RegionManager.RegisterViewWithRegion("TaskButtonRegion", typeof(ModuleATaskButton));
/* We register these objects with the Unity container because we don't want them
* instantiated until we navigate to this module. */
// Register View and Ribbon Tab as singletons with Unity container
m_Container.RegisterType(typeof(ModuleAView), "ModuleAView", new ContainerControlledLifetimeManager());
m_Container.RegisterType(typeof(ModuleARibbonTab), "ModuleARibbonTab", new ContainerControlledLifetimeManager());
}
When the user clicks a Task Button, it invokes an ICommand object that calls IRegionManager.RequestNavigate()
to show the views:
public void Execute(object parameter)
{
// Initialize
var regionManager = m_ViewModel.RegionManager;
// Show Ribbon Tab
var moduleARibbonTab = new Uri("ModuleARibbonTab", UriKind.Relative);
regionManager.RequestNavigate("RibbonRegion", moduleARibbonTab);
// Show View
var moduleAView = new Uri("ModuleAView", UriKind.Relative);
regionManager.RequestNavigate("WorkspaceRegion", moduleAView);
}
The command is being invoked when a Task Button is clicked, but what I get is this:
The UserControl is apparently loading as a System.Object
, and I suspect the RibbonTab is loading the same. I think the problem is with my RequestNavigate()
call, or my registration with Unity. But I can't identify the problem.
Can anyone shed any light on what's going on? Thanks for your help.
Finally figured this one out. The answer is in the Developer's Guide to Microsoft Prism (Ver 4), pp. 120-121. It has two parts:
First, the
UserControl
andRibbonTab
objects were resolving from Unity asSystem.Object
types. That's a limitation of Unity and the overload that I used to register the view objects. To get them to resolve to the correct types, you need to use a different overload forIUnityContainer.RegisterType()
:This overload maps Unity's native
System.Object
resolution to the correct type for the view requested. See the note on p. 120 of the Developer's Guide.The second problem wasn't explicitly stated in my question, but it occured when I fixed the first problem. I wanted each module's
RibbonTab
to be removed when I switched to the other module. Since my Ribbon Region acts like anItemsControl
, bothRibbonTabs
ended up being shown--Module A'sRibbonTab
wasn't unloaded when I switched to Module B. To solve that problem, I implementedIRegionMemberLifetime
on theRibbonTab
classes. That issue is covered on p. 121 of the Developer's Guide.BTW, I implemented the
IRegionMemberLifetime
interface on the View objects, rather than their View Models, because the interface does not impact the back end of the app, only the view object.