Monthly Archives: April 2012

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

Extending EF 4.x DbContext Generator to support Hashcode and Equality comparers

Currently I’m trying to fix a bunch of errors on a deep cloning template for EF 4.1 dbContext generated objects. This is done on a live database model, that’s fairly complex. One of the issues I had was the algorithm reaching a relation that it wasn’t supposed to be cloned, but later on, founding another relation where the same set of entities was supposed to be cloned, so I was left with relationships with the original entities that should be updated to the new cloned ones.

To fix this I had to keep track of what’s being cloned, so that in the end, I can run a “fixup” pass and update anything that’s referencing original entities that ended up being cloned later on. I came up with 2 ways to do this, either extend the objects and keep track of cloning information on a per object basis, or just track everything with a set of dictionaries during the process. Because many people in the team also work with these objects, and we have a junior guy, I didn’t want to pollute the objects with stuff that’s not business related, so I went with the dictionary approach.

The goal of this post isn’t to explain in detail how the template works, instead I just explain how to extend it. It contains my own flavor of code generation template syntax, that wasn’t born with T4, but with codesmith generation tools, and there I picked up a lot of habits that I still retain.

For the objects to be “Dictionary Ready” I implemented IEquatable, overrode GetHashCode() and Equals(object obj).

1.Getting a list of all the Primary Key properties in the entity

A good rule of thumb in all generation templates is to isolate all the different things you will work with in lists. The current template already isolates 3 things:

  • propertiesWithDefaultValues
  • collectionNavigationProperties
  • complexProperties
var propertiesWithDefaultValues = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && p.DefaultValue != null);
var collectionNavigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);
var complexProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity);

However we need a 4th IEnumerable containing all the primary keys for the entity, so we need to extend the previous code with:

var keyProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && ef.IsKey(p));
var propertiesWithDefaultValues = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && p.DefaultValue != null);
var collectionNavigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);
var complexProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity);

2.Implementing IEquatable on the class header

Next the class header needs to be slightly changed to implement the IEquatable interface, but still retain the base class option from EF.

I replaced:

<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#><#=code.StringBefore(" : ", code.Escape(entity.BaseType))#>

With:

<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#><# if(entity.BaseType == null) { #> : IEquatable<<#=code.Escape(entity)#>><# } else { #> : <#=code.Escape(entity.BaseType)#>, IEquatable<<#=code.Escape(entity)#>><# } #>

3. Implementing IEquatable on the class body

At the end of the class, insert the implementation of Equals(EntityName other):

    public bool Equals(<#=code.Escape(entity)#> other)
    {
        if(other == null) return false;
        var result = true;
<#
	foreach(EdmProperty key in keyProperties)
	{
#>
        if(<#=code.Escape(key)#> != other.<#=code.Escape(key)#>) result = false;
<#
	}
#>
        return result;
    }

4.Overriding GetHashCode() and Equals(object)

For the finishing part, I overrode GetHashCode and Equals, also at the end of the class, with:

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;
<#
	foreach(EdmProperty key in keyProperties)
	{
#>
            hash = hash * 23 + <#=code.Escape(key)#>.GetHashCode();
<#
	}
#>
            return hash;
        }
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as <#=code.Escape(entity)#>);
    }

The GetHashCode implementation is a bit specific as it requires support for multiple keys. It is pulled from Joshua Bloch’s Effective Java. It is translated to C# and explained very well by Jon Skeet on Stackoverflow.