Scoped Regions in TabControls

Nov 12, 2011 at 9:23 PM
Edited Nov 12, 2011 at 9:30 PM

Hi All,

i know, that there are several discussions about this topic. But they did not give me a solution, so i hope i can explain my "problem" good enough that someone understand it and will give me the tip i need.

In a shellview i have a tabcontrol with a regionname "ShellTabRegion".

There are two views

=> "ProducttListView" (defined as CreationPolicy.Shared) which enables the user to search and list searchresults

=> "ProductFormView" (defined as CreationPolicy.NonShared) which shows one Product (called from ProductListView) or to create a new one (called via menu).

To make a view visible i create/call an existing one (via navigation and the INavigationAware-Interface implemented in the views) like this way:

    new System.Uri("ProductFormView" + this.ParametersUriQuery,

All this works proper. ProductListView is shown maximum one times, ProductFormView as offen as needed. And, the main point, they will show in the tabcontrol of the shell as defined. Now to my Problem:

The "ProductFormView" own a TabControl with an Region "ProductFormViewTabRegion" to show further informations (by sub-views) about the product like MasterData, Stockdata and so on - one tab for each subview.

For this TabControl a need a scoped region to make the view independing from the other (ProductForm)-Views and the shell. Where do i have to define what? Does it happen in the Module-Initialize (as found in one example)? Or via a own RegionController as found in the UICompositionQuickStart?

Is it possible to register a scoped region in code behind in the ProductFormView after the view was instantiated?

I found several examples, but no one gives me the final eyecatcher.

Regards and thanks for any help

Nov 14, 2011 at 1:33 PM
Edited Nov 14, 2011 at 1:34 PM

AddOn: Actual i have a small sample app which shows the problem in full source. Will send it zipped via email...

As everone i need help very urgent (!) :-)

Nov 14, 2011 at 2:28 PM


It would be helpful if you could upload that sample into a page like SkyDrive for us to check it.


Agustin Adami


Nov 14, 2011 at 3:36 PM

Okay - the sample is placed on skydrive. The main parts are marked with "P&P" so you will find the relevant code by searching for that string.

is the link if you logged in.

Regards and thanks for any help and the time

Nov 15, 2011 at 6:11 PM
Edited Nov 15, 2011 at 9:02 PM


Prism Region Navigation does not provide a way of using scoped regions out-of-the-box. If you need to use scoped regions you could use the view injection approach (with the Add method of the region) to add the ProductFormView views to the ShellTabRegion. You can find more information about this in the following thread were a similar topic were discussed:

Based on my understanding of your scenario, you seems to be using the Prism Region Navigation to check if the specified record id is already being shown in a view and to send information (in this case, the record id) to that view as a parameter. As a possible approach, you could implement your own custom logic to check if the specified record id is being shown in the region and add a new view or activate an existing one when required without requiring to use Prism Region Navigation.

If you believe that scoped regions should be supported by Prism Region Navigation out-of-the-box, you can create a work item in the Issue Tracker so that the p&p team analyzes it for future releases.

I hope you find this useful,

Damian Cherubini

Nov 18, 2011 at 10:11 PM
Edited Nov 18, 2011 at 10:13 PM

Hi Damian,

tx again for reply.

Scoped regions are discriped in the official Documentation. But the regions did not belong to a control like a tabcontrol. If i create a (global) region in the shell (xaml) like:

        <TabControl Name="TabControlMain"
                    Grid.Row="4" Grid.Column="1"
                    cal:RegionManager.RegionName="{x:Static InfraStructure:ShellRegionNames.ShellTabRegion}"
                    ItemContainerStyle="{DynamicResource TabHeaderStyle}" 

and add views to the region like:

    new System.Uri("ProductFormView",

it works fine. Now the view "ProductFormView" owns a tabcontrol ("ProductFormViewTabRegion"), too. And it that tabcontrol "ProductFormViewTabRegion" i want to add views in the same way as i do it in the shell-tabcontrol "TabControlMain". For an example an "sub"view to show the masterdata and a second one for the stock. Another important fact is, that i need the possibility, to show more than one "ProductFormView" in the "TabControlMain" - different products are shown in there own "ProductFormView"s. Everything inside the "ProductFormView" should be "local"!

Up to know, i did not have a working way. Pherhaps you can take my small sample app and show me in code how i can implement that behaviour. The subviews are not important - important is HOW i make the "ProductFormViewTabRegion" local.

Did i understand it right, that this can not be implement with prism? I read so much about regions, that i am currently confused *smile*

Thanks again for help

Nov 21, 2011 at 7:55 PM
Edited Nov 21, 2011 at 7:57 PM


Based on my understanding to achieve navigation using Scoped Regions, you could try a similar approach like the one Guido Maliandi suggested in the aforementioned thread, which is based on modifying the Prism library, specifically the LoadContent method of the RegionNavigationContentLoader (which is internally called by the RegionNavigationService).

In case the requested view isn't present in the region at the moment navigation is requested, the RegionNavigationContentLoader will add the view to the region using the Region.Add method. There, you could specify that the view is added using a Scoped Region Manager. However this approach will only work with the view discovery approach, since you won’t be able to store or retrieve the scoped region manager generated when calling the Region.Add method.

I believe you could add some other modifications that might be helpful:

For example you could decide if you want to use Scoped Regions or not, based on a parameter in the navigation request. (e.g. ScopedRegionManagerName). If some value is specified, then scoped regions will be used, and if no value is specified, scoped regions won’t be used.

Also it would be helpful to save the scoped region manager returned by the call to the Region.Add method, in case you need to use it in the future. A possible way could be to store it in a shared dictionary, where you can save the value passed in the parameter as a key, and the scoped region manager as its corresponding value.

Note that if you intend to navigate to a view using this approach with a duplicate name, it would crash because it would try to add a duplicate key to a dictionary.

For example, the LoadContent method of your custom RegionNavigationContentLoader could look like this:

public object LoadContent(IRegion region, NavigationContext navigationContext)

var scopedRegionManagerName = navigationContext.Parameters["ScopedRegionManagerName"];

if (string.IsNullOrEmpty(scopedRegionManagerName))

else { var scopedRegionManager = region.Add(view, null, true); var dictionary = ServiceLocator.Current.GetInstance<ScopedRegionManagersSharedDictionary>(); dictionary.Add(scopedRegionManagerName, scopedRegionManager); } return view; } (...) }


Where ScopedRegionManagersSharedDictionary can be a class that implements an Add method and an indexer that returns the corresponding IRegionManager based on the key provided.

On the other hand, we created a workitem in the issue tracker so that the Prism team considers this for a future release.

I hope you find this handy.

Agustin Adami

Nov 22, 2011 at 11:15 AM

Would it be possible to see a simple example app of using this workaround?

Nov 23, 2011 at 9:16 PM


We thought of an alternative approach which I believe might be a more elegant solution. The approach consist of obtaining the region manager returned by the call of the Region.Add method, through the NavigationResult passed in the navigation callback from the RequestNavigate method instead of using a shared dictionary to save it.

As the result you will be able to navigate with scoped regions, like in the following code snippet:


                new Uri("HelloWorldView?createRegionManagerScope=true", UriKind.Relative), 
                (result) =>
                    var myRegionManager = result.ExtractRegionManager();
                    myRegionManager.RequestNavigate("NestedRegion", new Uri("View1", UriKind.Relative));

Below you will find the details of this implementation:

To achieve this scenario, the first thing we needed was a NavigationResult that allows us to pass the region manager instance. For this we created a CustomNavigationResult class that inherits from NavigationResult, but with another constructor which added an IRegionManager parameter, that sets its RegionManager property.

Next, to obtain the region manager returned by the call of the Region.Add method, we needed the LoadContent method in the RegionNavigationContentLoader to return a Tuple<object,IRegionManager> instead of only an object view. Therefore we created a CustomRegionNavigationContentLoader and its corresponding interface. Also we changed the name of the parameter passed with the view when navigating to "createRegionManagerScope" and verify if its value is “true” to specify if a new region manager must be created (in case scoped regions are used).

This changes can be seen in the following code snippet:

public Tuple<object, IRegionManager> LoadContent(IRegion region, NavigationContext navigationContext)
if (view != null)
                return new Tuple<object, IRegionManager>(view, region.RegionManager);

            view = this.CreateNewRegionItem(candidateTargetContract);

            bool createRegionManagerScope = navigationContext.Parameters["createRegionManagerScope"] == "true";

            var rm = region.Add(view, null, createRegionManagerScope);

            return new Tuple<object, IRegionManager>(view, rm);

Also, as the ExecuteNavigation method in the RegionNavigationService is the one that calls the LoadContent method, we had to create a CustomRegionNavigationService, to let it receive the returned tuple. In this same method instead of passing the default NavigationResult to the navigationCallback we pass our CustomNavigationResult with the returned region manager as a parameter.

You can find this modifications in the following code snippet:


private void ExecuteNavigation(NavigationContext navigationContext, object[] activeViews, Action<NavigationResult> navigationCallback)
  Tuple<object, IRegionManager> tuple = this.regionNavigationContentLoader.LoadContent(this.Region, navigationContext);

                // Raise the navigating event just before activing the view.


                // Update the navigation journal before notifying others of navigaton
                IRegionNavigationJournalEntry journalEntry = this.serviceLocator.GetInstance<IRegionNavigationJournalEntry>();
                journalEntry.Uri = navigationContext.Uri;

                // The view can be informed of navigation
                InvokeOnNavigationAwareElement(tuple.Item1, (n) => n.OnNavigatedTo(navigationContext));

                navigationCallback(new CustomNavigationResult(navigationContext, true, tuple.Item2));

Finally to avoid modifying the prism library we used the export attribute at the top of our custom classes (CustomRegionNavigationContentLoader and CustomRegionNavigationService) which allows the MefBootstrapper to provide these classes as a default implementation.

How to use:

If you apply this changes, then you will be able to call the RequestNavigate method with a delegate method as the navigation callback, which will receive a NavigationResult. The only problem is that you will have to cast the NavigationResult to our CustomNavigationResult class, in order to obtain the desired regionManager. Hence we created an extension method called ExtractRegionManager in the NavigationResultExtension class, which will make things easier.

For those interested, we prepared a sample application that portrays the aforementioned modifications. This sample shows two instances of a view being navigated to using the RequestNavigate method, inside a region in a TabControl. Each of these views has an inner region, and because this region names will be duplicated they must be defined as scoped regions. You can find the application sample in my Skydrive account under the name NavigationWithScopedRegionSample.

I hope you find this useful


Agustin Adami

Nov 30, 2011 at 2:28 PM

Thank you, this is very useful. I'm probably saying something very simple here, but how would you pass the new regionmanager to the newly scoped viewmodel? There isn't a way to get this from the navigationcontext is there?

I am wanting to navigate within the scoped viewmodel changing the region within.

Nov 30, 2011 at 8:56 PM


I'm glad you find this useful. Regarding your question, you might find this blog post useful, where we implemented the aforementioned suggestions and also added the posibility to pass the new RegionManager to the corresponding ViewModel. To achieve this we used the RegionManagerAwareBehavior proposed in the following blog post from Damian Cherubini.

I hope you find it helpful

Agustin Adami

Dec 1, 2011 at 11:17 AM

Thank you that has sorted me out!

Mar 30, 2012 at 10:51 PM
Edited Mar 31, 2012 at 2:18 AM

I would like to offer another, simpler workaround for this problem.

The issue could be separated into two parts: to force content loader to add view to the region using scope when required, and accessing correct RegionManager in scoped view.

To solve first part of the problem we could use interface or custom attribute on the view type. So with just a few lines of code added to LoadContent function we could make the loader to add views with scope when necessary:

public object LoadContent(IRegion region, NavigationContext navigationContext)

    // Check if scoped region is required
    IProvideRegionScopeInfo info = (view as IProvideRegionScopeInfo) ??
        .GetCustomAttributes(typeof(ScopedRegionManagerAttribute), false).FirstOrDefault();

    if (null == info)
        region.Add(view, info.ViewName, info.CreateRegionManagerScope);

    return view;

Accessing the correct manager is even easier. When view is added to the region attached property RegionManager.RegionManageris added and updated with reference to instance of the manager responsible for that view. So if the view is added with scope this property will have reference to correct scoped instance of the manager.
All we have to do is to bind to that attached property, this is what these attached properties are for, and use the manager in the View or a ViewModel.

Sample project could be downloaded on this page:

If you need more explanation please see it here:

Jan 27, 2014 at 4:25 PM
Is there any chance of actually implementing this to be a part of Prism 4.2?
Feb 25, 2014 at 11:46 AM
Hello? Any feedback on this?