Over the XMAS break I had a chance to look into something I wanted to look at, which is cool.
The thing I wanted to look at was to try and see if the new Composite WPF/SL (PRISM) code, which is now using MEF (Managed Extensibility Framework) would work well with Cinch V2.
Great news is works just fine, and I will be writing up a codeproject article for that real soon, but as part of that codebase, I also wrote a custom PRISM region adaptor that uses a TransitionalElement from the fabolous Microsoft Transitionals project.
For those of you that not heard of Transitionals, it is a set of WPF transitions that you can use to go from one bit of content to another bit of content.
It offers the following transitions:
- FadeAndGrow
- Translate
- FadeAndBlur
- Rotate
- CheckerboardTransition
- DiagonalWipeTransition
- DiamondsTransition
- DoorTransition
- DotsTransition
- DoubleRotateWipeTransition
- ExplosionTransition
- FadeTransition
- FlipTransition
- HorizontalBlindsTransition
- HorizontalWipeTransition
- MeltTransition
- PageTransition
- RollTransition
- RotateTransition
- RotateWipeTransition
- StarTransition
- TranslateTransition
- VerticalBlindsTransition
- VerticalWipeTransition
So I took it upon myself to split that custom PRISM region adaptor into a small demo app. This blog has that demo code attached.
The demo app is very simple and has a DockPanel with a ComboBox to select the transition type and 3 images that when clicked on will set a custom transitonals based PRISM region adaptor to transition to that image. Shown below is an example of one the images 1/2 way through a transition.
So how does it all work. It’s really down to the following steps
STEP 1 : Create a custom PRISM region adaptor
This is where we create the custom region adaptor for the type of TransitionElement, as shown below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.ComponentModel.Composition;
using Microsoft.Practices.Prism.Regions;
using Transitionals.Controls;
using System.Collections.Specialized;
namespace PRISMTransitionalRegion.Regions
{
[Export("PRISMTransitionalRegion.Regions.TransitionElementAdaptor",
typeof(TransitionElementAdaptor))]
public class TransitionElementAdaptor : RegionAdapterBase<TransitionElement>
{
[ImportingConstructor]
public TransitionElementAdaptor(IRegionBehaviorFactory behaviorFactory) :
base(behaviorFactory)
{
}
protected override void Adapt(IRegion region, TransitionElement regionTarget)
{
region.Views.CollectionChanged += (s, e) =>
{
//Add
if (e.Action == NotifyCollectionChangedAction.Add)
foreach (FrameworkElement element in e.NewItems)
regionTarget.Content = element;
//Removal
if (e.Action == NotifyCollectionChangedAction.Remove)
foreach (FrameworkElement element in e.OldItems)
{
regionTarget.Content = null;
GC.Collect();
}
};
}
protected override IRegion CreateRegion()
{
return new AllActiveRegion();
}
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
STEP 2 : Create a Region to use this custom region adaptor
Now we need to actually use this custom region adaptor. Which I have decided to do directly in the Shell (standard PRISM starting window), as follows:
<Window x:Class="PRISMTransitionalRegion.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism"
xmlns:transitions="clr-namespace:Transitionals.Transitions;assembly=Transitionals"
xmlns:transitionals="clr-namespace:Transitionals;assembly=Transitionals"
xmlns:transitionalsControls="clr-namespace:Transitionals.Controls;assembly=Transitionals"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="Shell"
WindowState="Normal"
WindowStyle="ThreeDBorderWindow"
WindowStartupLocation="CenterScreen"
Width="800"
Height="800">
<DockPanel Grid.Row="1" Grid.Column="1" Margin="10"
LastChildFill="True">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top"
HorizontalAlignment="Left">
<Label Content="Pick Transition Type" FontSize="10"
Foreground="Black" FontFamily="Verdana"/>
<ComboBox Margin="5,0,0,0" Width="200"
ItemsSource="{Binding TransitionTypes}"
SelectedItem="{Binding SelectedTransitonType}"/>
<StackPanel Orientation="Horizontal" Margin="10,0,0,0">
<Image Source="/PRISMTransitionalRegion;component/Images/robot1.png"
Width="40" Height="40" Margin="5">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction
Command="{Binding ShowViewCommand}"
CommandParameter="/PRISMTransitionalRegion;component/Images/robot1.png"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<Image Source="/PRISMTransitionalRegion;component/Images/robot2.png"
Width="40" Height="40" Margin="5">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction
Command="{Binding ShowViewCommand}"
CommandParameter="/PRISMTransitionalRegion;component/Images/robot2.png"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<Image Source="/PRISMTransitionalRegion;component/Images/robot3.png"
Width="40" Height="40" Margin="5">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction
Command="{Binding ShowViewCommand}"
CommandParameter="/PRISMTransitionalRegion;component/Images/robot3.png"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
</StackPanel>
</StackPanel>
<transitionalsControls:TransitionElement
x:Name="transitionElement"
Margin="10"
VerticalAlignment="Center"
HorizontalAlignment="Center"
cal:RegionManager.RegionName="imageRegion"
Transition="{Binding TransitionToUse}">
</transitionalsControls:TransitionElement>
</DockPanel>
</Window>
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
We also create a simple ViewModel for the Shell in the Shell.xaml.cs code behind, where the ShellViewModel looks like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Primitives;
using System.ComponentModel;
using System.Windows;
using Microsoft.Practices.Prism.Regions;
using PRISMTransitionalRegion.Regions;
using PRISMTransitionalRegion.Views;
using PRISMTransitionalRegion.Interfaces;
using PRISMTransitionalRegion.Commands;
using Transitionals;
using Transitionals.Transitions;
namespace PRISMTransitionalRegion.ViewModels
{
public enum TransitionType
{
FadeAndGrow = 1,
Translate,
FadeAndBlur,
Rotate,
CheckerboardTransition,
DiagonalWipeTransition,
DiamondsTransition,
DoorTransition,
DotsTransition,
DoubleRotateWipeTransition,
ExplosionTransition,
FadeTransition,
FlipTransition,
HorizontalBlindsTransition,
HorizontalWipeTransition,
MeltTransition,
PageTransition,
RollTransition,
RotateTransition,
RotateWipeTransition,
StarTransition,
TranslateTransition,
VerticalBlindsTransition,
VerticalWipeTransition
}
public class ShellViewModel : INPCBase
{
private Transition transitionToUse = new FadeAndBlurTransition();
private Dictionary<TransitionType, Transition> transitionsLookup =
new Dictionary<TransitionType, Transition>();
private DependencyObject view;
private Lazy<IRegion> region;
public ShellViewModel(DependencyObject view)
{
this.view = view;
//add transition lookups
transitionsLookup.Add(TransitionType.FadeAndBlur,
new FadeAndBlurTransition());
transitionsLookup.Add(TransitionType.FadeAndGrow,
new FadeAndGrowTransition());
transitionsLookup.Add(TransitionType.Translate,
new TranslateTransition());
transitionsLookup.Add(TransitionType.Rotate,
new RotateTransition());
transitionsLookup.Add(TransitionType.CheckerboardTransition,
new CheckerboardTransition());
transitionsLookup.Add(TransitionType.DiagonalWipeTransition,
new DiagonalWipeTransition());
transitionsLookup.Add(TransitionType.DiamondsTransition,
new DiamondsTransition());
transitionsLookup.Add(TransitionType.DoorTransition,
new DoorTransition());
transitionsLookup.Add(TransitionType.DotsTransition,
new DotsTransition());
transitionsLookup.Add(TransitionType.DoubleRotateWipeTransition,
new DoubleRotateWipeTransition());
transitionsLookup.Add(TransitionType.ExplosionTransition,
new ExplosionTransition());
transitionsLookup.Add(TransitionType.FadeTransition,
new FadeTransition());
transitionsLookup.Add(TransitionType.FlipTransition,
new FlipTransition());
transitionsLookup.Add(TransitionType.HorizontalBlindsTransition,
new HorizontalBlindsTransition());
transitionsLookup.Add(TransitionType.HorizontalWipeTransition,
new HorizontalWipeTransition());
transitionsLookup.Add(TransitionType.MeltTransition,
new MeltTransition());
transitionsLookup.Add(TransitionType.PageTransition,
new PageTransition());
transitionsLookup.Add(TransitionType.RollTransition,
new RollTransition());
transitionsLookup.Add(TransitionType.RotateTransition,
new RotateTransition());
transitionsLookup.Add(TransitionType.RotateWipeTransition,
new RotateWipeTransition());
transitionsLookup.Add(TransitionType.StarTransition,
new StarTransition());
transitionsLookup.Add(TransitionType.TranslateTransition,
new TranslateTransition());
transitionsLookup.Add(TransitionType.VerticalBlindsTransition,
new VerticalBlindsTransition());
transitionsLookup.Add(TransitionType.VerticalWipeTransition,
new VerticalWipeTransition());
ShowViewCommand = new SimpleCommand<Object, Object>(ExecuteShowViewCommand);
region = new Lazy<IRegion>(() =>
{
IRegionManager regionManager = RegionManager.GetRegionManager(view);
return regionManager.Regions["imageRegion"];
});
}
public SimpleCommand<Object, Object> ShowViewCommand { get; private set; }
public Array TransitionTypes
{
get
{
return Enum.GetValues(typeof(TransitionType));
}
}
public TransitionType SelectedTransitonType
{
set
{
TransitionToUse = transitionsLookup[value];
}
}
public Transition TransitionToUse
{
get { return transitionToUse; }
private set
{
transitionToUse = value;
NotifyPropertyChanged("TransitionToUse");
}
}
private void ExecuteShowViewCommand(Object args)
{
if (!String.IsNullOrEmpty(args.ToString()))
ShowViewInRegion(args.ToString());
}
private void ShowViewInRegion(string imageUrl)
{
ImageView imageView =
(App.Current as App).PrismCompositionContainer.GetExportedValue<ImageView>();
((IContextualDataAware<string>)imageView).ContextualData = imageUrl;
IRegion lazyRegion = region.Value;
var oldView = lazyRegion.GetView("imageView");
if (oldView != null)
lazyRegion.Remove(oldView);
lazyRegion.Add(imageView, "imageView");
}
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
STEP 2 : Make sure the custom region adaptor is registered with PRISM
For our custom region adaptor to work with PRISM we need to make sure it registered with PRISM. We can do this in the PRISM 4.0 bootstrapping code, as follows:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Text;
using System.Windows;
using System.Reflection;
using System.Windows.Controls;
using Transitionals.Controls;
using Microsoft.Practices.Prism.MefExtensions;
using Microsoft.Practices.Prism.Regions;
using PRISMTransitionalRegion.Regions;
using PRISMTransitionalRegion.Views;
namespace PRISMTransitionalRegion
{
public class PRISMTransitionalRegionBootstrapper : MefBootstrapper
{
public override void Run(bool runWithDefaultConfiguration)
{
base.Run(runWithDefaultConfiguration);
}
protected override void ConfigureAggregateCatalog()
{
this.AggregateCatalog.Catalogs.Add(
new AssemblyCatalog(typeof(App).Assembly));
}
protected override void InitializeShell()
{
base.InitializeShell();
(App.Current as App).PrismCompositionContainer = this.Container;
Application.Current.MainWindow = (Shell)this.Shell;
Application.Current.MainWindow.Show();
}
protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings();
mappings.RegisterMapping(typeof(TransitionElement),
Container.GetExportedValue<TransitionElementAdaptor>());
return mappings;
}
protected override DependencyObject CreateShell()
{
return this.Container.GetExportedValue<Shell>();
}
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
As always here is a small demo app:
http://dl.dropbox.com/u/2600965/Blogposts/2011/01/PRISMTransitionalRegion.zip
Enjoy….Happy new year all