Category Archives: Prism

Using the TransitionPresenter with Prism

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();
        }
    }
}