Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically creating regions with Prism

Tags:

.net

wpf

prism

I am creating an app with Prism and am running into a bit of a roadblock.

I have a tab control that is a prism region and has an ItemsSource collection that we are binding a model to. This model contains the data needed to set the tab caption, a view name, and a random id (Guid in this case) that we use to generate a dynamic prism region to be a container in the tab content with its own prism regions and can be navigated to.

+Prism region(tab control)
|+ Prism region (dynamically created with Guid name)
 |+ Inserted view
  |+ Prism region
  |+ Prism region
  |+ Prism region
|+ Prism region (dynamically created with Guid name)    |
 |+ Inserted view
  |+ Prism region
  |+ Prism region
  |+ Prism region

The hiccup I am running into is the region we are trying to generate does not appear to be registered within the region manager even though we appear to be registering them correctly.

A series of searches and questions around the team have not brought any working solutions unfortunately.

I am wondering if anyone has tried this before or if there are any good resources on dynamically generating prism regions in code and registering them.

like image 831
Twisted Mentat Avatar asked Oct 22 '12 10:10

Twisted Mentat


1 Answers

I have done this in my application. Here is the code I came up with:

string regionName = "MyRegionName";
ContentPresenter RegionContentControl = new ContentPresenter { Focusable = false };

// This creates the region
Microsoft.Practices.Prism.Regions.RegionManager.SetRegionName(RegionContentControl, regionName);

// This adds the region to your region manager.
Microsoft.Practices.Prism.Regions.RegionManager.SetRegionManager(RegionContentControl, RegionManager);

// Get the region back
IRegion newRegion = RegionManager.Regions.FirstOrDefault(x => x.Name == regionName);

I get the RegionManger from Unity.

Update:

Mark noted that a ContentPresenter is not allowed out of the box. Here is the adapter that adds that functionallity in:

public class ContentPresenterRegionAdapter : RegionAdapterBase<ContentPresenter>
{
    public ContentPresenterRegionAdapter(IRegionBehaviorFactory behaviorFactory)
        : base(behaviorFactory)
    {
    }

    protected override void Adapt(IRegion region, ContentPresenter regionTarget)
    {
        region.Views.CollectionChanged += (s, e) =>
            {
                if (e.Action == NotifyCollectionChangedAction.Add)
                {
                    foreach (FrameworkElement element in e.NewItems)
                    {
                        regionTarget.Content = element;
                    }
                }
                else if (e.Action == NotifyCollectionChangedAction.Remove)
                {
                     foreach (FrameworkElement currentElement in e.OldItems)
                         regionTarget.Content = null;
                }
            };
    }

    protected override IRegion CreateRegion()
    {
        return new AllActiveRegion();
    }
}

To register this mapping you would need to add this to your bootstrapper:

protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
   RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings();
   mappings.RegisterMapping(typeof(ContentPresenter), 
                            Container.Resolve<ContentPresenterRegionAdapter>());
   return mappings;
}
like image 189
Vaccano Avatar answered Sep 20 '22 12:09

Vaccano