Prism 4: RequestNavigate() not working

David Veeneman picture David Veeneman · Feb 26, 2011 · Viewed 11.2k times · Source

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:

Demo app screen shot

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.

Answer

David Veeneman picture David Veeneman · Mar 1, 2011

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 and RibbonTab objects were resolving from Unity as System.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 for IUnityContainer.RegisterType():

// Register other view objects with DI Container (Unity)
m_Container.RegisterType<Object, ModuleAView>("ModuleAView");
m_Container.RegisterType<Object, ModuleARibbonTab>("ModuleARibbonTab");

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 an ItemsControl, both RibbonTabs ended up being shown--Module A's RibbonTab wasn't unloaded when I switched to Module B. To solve that problem, I implemented IRegionMemberLifetime on the RibbonTab 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.