Bag of Tricks if a very cool project, it contains a lot of eye candy WPF controls that are easy to use and that serve as a great base for learning more WPF advanced features.
Inside Bag of Tricks there’s a control called the TransitionPresenter, and there’s a bunch of Transitions in the package, some of them are very cool.
This control works like a normal ContentControl, you replace it’s Content and it will transition from the previous Content to the new Content with the Transition that’s associated with it.
When a project uses Prism, there are Regions, usually inside ContentControls and we normally do a RequestNavigate(…) on a specific region to tell Prism to Navigate (getting things out of the Dependency Injection Container, swap the Content, etc.).
Extending Prism – Region Mappings
Our ultimate goal is to have Regions inside a TransitionPresenter control, and be able to write something like this:
<t:TransitionPresenter x:Name="MainContent" cal:RegionManager.RegionName="MainRegion" />
To accomplish this we need to add a Region Mapping on our Bootstrapper, on the ConfigureRegionAdapterMappings override, add a new line with the type of TransitionPresenter and the specific RegionAdapter, in our case we will call it TransitionPresenterRegionAdapater:
protected override RegionAdapterMappings ConfigureRegionAdapterMappings() { var regionAdapterMappings = ServiceLocator.Current.GetInstance<RegionAdapterMappings>(); if (regionAdapterMappings != null) { regionAdapterMappings.RegisterMapping(typeof(Selector), ServiceLocator.Current.GetInstance<SelectorRegionAdapter>()); regionAdapterMappings.RegisterMapping(typeof(ItemsControl), ServiceLocator.Current.GetInstance<ItemsControlRegionAdapter>()); regionAdapterMappings.RegisterMapping(typeof(ContentControl), ServiceLocator.Current.GetInstance<ContentControlRegionAdapter>()); regionAdapterMappings.RegisterMapping(typeof(TransitionPresenter), ServiceLocator.Current.GetInstance<TransitionPresenterRegionAdapater>()); } return regionAdapterMappings; }
Creating the Region Adapter
The code below has some flavors of Prism already present:
- The implementation uses MEF as the Dependency Injection Container.
- The TransitionPresenter is used on the main shell, so a SingleActiveRegion is preferred over AllActiveRegion.
The implementation is as follows:
using System; using System.Linq; using Microsoft.Practices.Prism.Regions; using WPF.Controls.Transitions; using System.Collections.Specialized; using System.ComponentModel.Composition; namespace Sigep.WPF.Infrastructure { [Export(typeof(TransitionPresenterRegionAdapater))] [PartCreationPolicy(CreationPolicy.NonShared)] public class TransitionPresenterRegionAdapater : RegionAdapterBase<TransitionPresenter> { [ImportingConstructor] public TransitionPresenterRegionAdapater(IRegionBehaviorFactory regionBehaviorFactory) : base(regionBehaviorFactory) { } protected override void Adapt(IRegion region, TransitionPresenter regionTarget) { if (regionTarget == null) throw new ArgumentNullException("regionTarget"); var contentIsSet = regionTarget.Content != null; if (contentIsSet) { throw new InvalidOperationException("ContentControlHasContentException"); } region.ActiveViews.CollectionChanged += delegate { regionTarget.Content = region.ActiveViews.FirstOrDefault(); }; region.Views.CollectionChanged += (sender, e) => { if (e.Action == NotifyCollectionChangedAction.Add && !region.ActiveViews.Any()) { region.Activate(e.NewItems[0]); } }; } protected override IRegion CreateRegion() { return new SingleActiveRegion(); } } }