Dynamically Creating Regions without XAML

Topics: Prism v4 - WPF 4
May 31, 2013 at 9:03 PM
Hello,
In my current project I've run into an issue with the RegionManager where I needed to register views with regions, that didn't exist, at the time that the view is created. I tried using RegisterViewWithRegion, but that presented an issue when I wanted to associate multiple views with a region. So then I thought that the best way to approach this issue was to create the regions up front, before any of the wpf views are created, that way the regions would always exist when the views were added to a region. Then I would add the content controls to various views as needed.

However, while I was able to get this to work, I don't like how I've accomplished this and I was wondering if I have missed a simpler way to accomplish this functionality. Here is my code:
    public class RegionState
    {
        public string strRegionName;
        public string strActiveViewName;  // The name of the view that is currently in the region.
        public ContentControl contentControl;   // The content control associated with this view.

        public RegionState()
        {
            strRegionName = string.Empty;
            strActiveViewName = string.Empty;
            contentControl = new ContentControl();
        }
    }

        // This function is located in a much larger class that is separate from the above RegionState class.
        public void AddRegion(string strRegionName)
        {
            RegionState state = null;
            // Add a new region state if one doesn't already exist.
            lock (lk_dcRegions)
            {
                // Gets the state if it already exists.
                state = GetUserControlState(strRegionName);
                // If the manager doesn't exists.
                if (state == null)
                {
                    state = new RegionState();
                    state.strRegionName = strRegionName;
                    dcRegions.Add(strRegionName, state);
                }
            }

            // Then add the region to the region manager.
            if (!regionManager.Regions.ContainsRegionWithName(strRegionName) && state != null)
            {
                RegionManager.SetRegionName(state.contentControl, strRegionName);
                RegionManager.SetRegionManager(state.contentControl, regionManager);

                FieldInfo fieldUpdateRegionListeners = typeof(RegionManager).GetField("updatingRegionsListeners", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
                Object oUpdateRegionListeners = fieldUpdateRegionListeners.GetValue(state.contentControl);
                FieldInfo fieldListeners = oUpdateRegionListeners.GetType().GetField("listeners", BindingFlags.NonPublic | BindingFlags.Instance);
                List<DelegateReference> lsDelgateEvents = (List<DelegateReference> )fieldListeners.GetValue(oUpdateRegionListeners);
                DelegateReference dr = lsDelgateEvents.SingleOrDefault(e =>
                    {
                        if (e.Target.Target is DelayedRegionCreationBehavior)
                        {
                            return ((DelayedRegionCreationBehavior)e.Target.Target).TargetElement == state.contentControl;
                        }
                        return false;
                    });
                ((DelayedRegionCreationBehavior)dr.Target.Target).Detach();
                lsDelgateEvents.Remove(dr);

                RegionAdapterMappings regionAdapterMappings = ServiceLocator.Current.GetInstance<RegionAdapterMappings>();
                IRegion region = ccRegionAdapter.Initialize(state.contentControl, strRegionName);
            }
        }
Thank you for any assistance or suggestions.
Developer
Jun 3, 2013 at 6:45 PM
Hi,

I have not reviewed your code in deep, but it seems to be a valid approach to address your scenario.

Personally, when I find a scenario where using the RegisterViewWithRegion option won't suffice, I first check if the region exists using the ContainsRegionWithName method of the Regions collection in the RegionManager. If it doesn't, I subscribe to the CollectionChanged event of the Regions property. Each time a Region is created and added to the RegionManager this event is fired. Hence, you can be notified when a Region is available through it and add the corresponding view in it. Perhaps this could also be encapsulated in a service in order to decouple the aforementioned logic from the view models.

I hope this helps,

Damian Cherubini
http://blogs.southworks.net/dcherubini