How do I register a View so that it can be resolved in a different module?

Topics: Prism v4 - Silverlight 4, Prism v4 - WPF 4
Jul 29, 2011 at 3:37 AM

Hi, I'm trying to learn modularity, but I'm a bit stuck.

When modules are loaded I register services and views with the Unity container like this:

        public void Initialize()
        {
            this.container.RegisterType<IPeopleRepository, PeopleRepository>();
            this.container.RegisterType<object, PersonSummaryUserControl>("PersonSummaryUserControl");
        }

With that I was hoping to be able to resolve the view from any place in the application without having hard references, like this:

this.regionManager.RegisterViewWithRegion(RegionNames.DetailsRegion, this.container.Resolve<PersonSummaryUserControl>());

But this doesn't work. Why not?

With hard references I can do stuff like:

            var view = this.container.Resolve<PersonSummaryUserControl>();
	   // or
            this.regionManager.RegisterViewWithRegion(RegionNames.DetailsRegion, typeof(PersonSummaryUserControl));

but, I'd like to remove the references. What should I do?
TIA
Dennis
Developer
Jul 29, 2011 at 6:46 PM

Hi,

Based on my understanding, as you are registering the view using a named type mapping, in order to resolve it you have to provide that name in the Resolve method like this:

this.container.Resolve<object>("PersonSummaryUserControl")

Additionally, the RegisterViewWithRegion method does not provide an overload which accepts an object of your view’s type; it provides one that accepts a type, and another one that accepts a lambda expression. So the line:

this.regionManager.RegisterViewWithRegion(RegionNames.DetailsRegion, this.container.Resolve<PersonSummaryUserControl>());

doesn’t use any of the RegisterViewWithRegion overloads defined by Prism.

On the other hand, note that this is not the usual approach to register a view. Usually the method RegisterViewWithRegion is called inside the module where the view is defined, so that when a region is created with that region name (regardless of where the region is created) a view of the registered type will be injected into that region.

This is what you are doing when using this code line:

this.regionManager.RegisterViewWithRegion(RegionNames.DetailsRegion, typeof(PersonSummaryUserControl));


If this code line is inside the module where the view is defined then it is not a hard reference as the view doesn’t need to be referenced outside its module in order to be shown in the region specified.

This is possible because one of the benefits of the UI Composition mechanisms provided by Prism is that you can access regions and add views to them outside the component that defined them. You might find more information about this in the UI Composition chapter from the Prism MSDN documentation.

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi

Jul 29, 2011 at 7:28 PM

Let me see if I can clarify my problem.

I have a PeopleModule with list and details views. I would like to add more details to this module so I added a PersonSummaryView (like in the PRISM UIComposition QuickStart) with a tabcontrol where I want to insert details views for Person, Addresses, Contacts etc. The UIComposition QuickStart puts all of these views (EmployeeDetails and Projects) in the same module. That's not a good idea since I will also have a CompanyModule which will use the same details views only filtered by Company.

What I'm currently trying to do is to set up the PersonModule so that when the PeopleListView is called (from a MenuModule set up with Commands) it inserts the PersonSummaryView into the Shell's DetailsRegion. The PersonSummaryView will then resolve the needed details views (located in other modules) and insert them into its own TabControl regions.

this.regionManager.RegisterViewWithRegion(RegionNamesPeopleSummary.AddressesRegion, typeof(AddressesListUserControl));
this.regionManager.RegisterViewWithRegion(RegionNamesPeopleSummary.ContactsRegion, typeof(ContactsListUserControl));
//Etc
The problem here is that to do this I need project references from PeopleModule to all other Modules (and vice versa), not exactly loose coupling. 
I thought that by registering any UserControls existing in each Module at start-up I would be able to resolve an instance of those UserControls from anywhere as long as I have a reference to the Unity container.
Am I completely wrong?
TIA
Dennis
Developer
Aug 1, 2011 at 2:34 PM

Hi Dennis,

The RegisterViewWithRegion method does not register the view into the container; its function is to register a view to a region, so that when that region is created and added to the visual tree, a view of the type specified is automatically added to it. The RegisterViewWithRegion method is the core of the View Discovery approach, which is described in the UI Composition Chapter in the Prism MSDN documentation.

Alternatively, in order to register something in the Unity Container, you have to call the RegisterType or RegisterInstance methods, which will result in your component (in this case, your view) being available throughout your whole application. However, as I've mentioned in my previous answer, the Prism UI Composition mechanisms allow you to add views to a region without from within another component that might not be the one that defined the region. Therefore, you don't need to make such references to call the RegisterViewWithRegion method to tie a view to a region; you only need to know the name of that region (which is just a string, which acts as a contract name, allowing you to avoid tight coupling between your components).

Finally, you should take into account that, while the View Discovery approach (portrayed by the RegisterViewWithRegion method) is useful to define more static layout schemes for your views, in your particular case you might benefit more from the View Injection (also explained in the UI Composition chapter) or Region Navigation (explained in the Navigation chapter of the aforementioned documentation) approaches. This is because the View Injection approach allows you to have explicit programmatic control of how views are added to regions; therefore, you could decide to add or remove views from a certain region based on a specific action, such as clicking a button. Region Navigation provides additional mechanisms that facilitate a navigation scenario like the one you've described.

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi