In part 2  we learnt Prism uses named regions to inject or discover views at run time. To accomplish this feat, Prism internally uses RegionAdapter.

We also learnt that Region holds collection of views, activeviews and metadata; before we delve into ScopedRegions, it is important to understand the association between view and regions, and also RegionManager.

Views vs ActiveViews

Every Region holds  two datastructures i.e. collection of views and collection of active-views (where an active-view means: the view that is currently visible and on the screen).

A ContentControl region can have only one active view at any given time, an ItemsControl region can have multiple active-views. A Selector though not a ContentControl, also have one active view, it is when we switch between tabs, that Prism de-activates old view, and activates the new selected view.

To repeat, a region can hold multiple views, but it is not necessary that all views are currently active and visible.

A region cannot hold the same view twice or more in its collection (even ItemsControl), else we get an exception (see InnerAdd function). As you can see, Prism internally compares references and will throw an exception when the same view is added twice to a region (even in the case of ItemsControl region).

Association between Regions and Views

Each View knows the associated region it belongs to. When the view is first loaded, the RegionName attached property is stamped on the view, and one of the many reasons the same view cannot be used in two or more regions.

Region Manager

RegionManager holds collection of regions and is the main facade through which we get reference to a Region via region name.

Example: to access a region we use regionManager.Regions[“RegionName”]  – where regionManager.Regions becomes the container through which we access a named region.

Scoped Region

The Region scope is not limited to the first level view only, we can inject a view which can have another region inside it, that sub-region can further inject yet another view, that too can have yet another sub-sub region (this can go turtles all the way down)

multi region.png

Now how do we tell Prism that when a sub-view is created and if it has a region, then it should be injected with some View? As we learnt in the previous part it can be done via View Discovery

  • View Discovery – regionManager.RegisterViewWithRegion(“Whatever_Region”, typeof(view));

Prism internally creates a functor to create an instance of given type and use it to automatically inject the view to the region (using service locator)

But all this Region with sub-regions causes ambiguity, take below case for example:

Say our shell contains one main ItemsControl region “RegionA”, within RegionA we can inject multiple instances of ViewA, where each ViewA can contain another Region “RegionB”.

multi multi region

We then tell Prism that whenever you see RegionB, insert it with an instance of ViewB,  this is achieved via RegisterViewWithRegion API
regionManager.RegisterViewWithRegion(“RegionB”, typeof(ViewB));

Now, If we add two instances of ViewA, we will get an exception that “RegionB is already registered”

regionManager.Region[“RegionA”].Add(unityContainer.Resolve<ViewA>());
regionManager.Region[“RegionA”].Add(unityContainer.Resolve<ViewA>());

This is because when constructing ViewB the second time (for the second view added to RegionA), Prism would not know which RegionB are we talking about? There is a RegionB in first ViewA, and there is also a RegionB in the second instance of ViewA.

Thus Prism does not allow RegionManager’s RegionCollection to have duplicate regions. Each Region should be unique in the RegionManager.RegionCollection.

What is the fix?

As RegionManager.RegionCollection is a container, we can create a child container (this is analogous to child container in Unity and other DI frameworks in some aspect – though there is no inheritance involved when looking up for keys in Prism) and this is called a Scoped Region.

We can fix this ambiguity by telling Prism to create a Scoped RegionManager for each view it construct, this is achieved by passing a true flag to the Add function (the last parameter)

regionManager.Region[“RegionA”].Add(unityContainer.Resolve<ViewA>(), null, true);
regionManager.Region[“RegionA”].Add(unityContainer.Resolve<ViewA>(), null, true);

With ScopedRegion, each view instantiated will be associated with a new RegionManager, and not the global RegionManager.

Hope this helps explain Scoped Regions.