How to: Add a View to a Region in a particular index with Prism-v2

Yesterday a question in the Prism codeplex forum made me realize that there is no out-of-the-box way to specify the order in which a view will be added to a Region with the Composite Application Library's code shipped with the Composite Application Guidance for WPF & Silverlight.

After discussing with Matias Bonaventura what the best way to get this done was, we decided to use an extension method for the RegionManager class.

RegisterViewWithRegionInIndex method
  1. Create a new public static class named RegionManagerCustomExtensions in any place accessible to where you want to be able to use it.
  2. Add a reference to the Assembly Microsoft.Practices.ServiceLocation(located in the ~DecompressionPath\LIB\Desktop\CommonServiceLocation folder)
  3. Add the following using statements to theĀ  RegionManagerCustomExtensions class:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.Practices.Composite.Regions;
    using Microsoft.Practices.ServiceLocation;

  4. Add a method named RegisterViewWithRegionInIndex with that has the following code:
public static IRegionManager RegisterViewWithRegionInIndex(this IRegionManager regionManager, string regionName, Type viewType, int index)
       {
           IRegion mainRegion = regionManager.Regions[regionName];
           int viewsAmount = mainRegion.Views.Count();
           if (index > viewsAmount)
           {
               throw new IndexOutOfRangeException("Tried to add a view to a region that does not have enough views.");
           }

           if (index < 0)
           {
               throw new IndexOutOfRangeException("Tried to add a view in a negative index.");
           }

           object activeView = null;

           if (mainRegion.ActiveViews.Count() == 1)
           {
               activeView = mainRegion.ActiveViews.First();
           }

           var regionViewRegistry = ServiceLocator.Current.GetInstance<IRegionViewRegistry>();

           // Save reference to each view existing in the RegionManager after the index to insert.
           List<object> views = mainRegion.Views.SkipWhile((view, removeFrom) => removeFrom < index).ToList();

           //Remove elements from region that are after index to insert.
           for (int i = 0; i < views.Count; i++)
           {
               mainRegion.Remove(mainRegion.Views.ElementAt(index));
           }

           //Register view in index to insert.
           regionViewRegistry.RegisterViewWithRegion(regionName, viewType);

           // Adding previously removed views
           views.ForEach(view => mainRegion.Add(view));

           if (activeView != null)
           {
               mainRegion.Activate(activeView);
           }

           return regionManager;
       }

Putting the method to use

You should be able to use the method now. To test it, I created a couple of extra views in the HelloWorld Quickstart and wrote the following code in the HelloWorldModule class:

manager.RegisterViewWithRegionInIndex("MainRegion", typeof(Views.HelloWorldView), 0);
manager.RegisterViewWithRegionInIndex("MainRegion", typeof(Views.View1), 1);
manager.RegisterViewWithRegionInIndex("MainRegion", typeof(Views.View2), 1);

The outcome was the following. As you can see, View2 was placed where View1 was located:

image

The method could also be customized to add views to the latest index possible if the index to insert the view into was higher than the amount of views previously existing in the region.

Let me know if you find a good use to this method.