Category Archives: WPF

Binding To Nullable Enums

This post will be a short post about how you can easily bind to nullable enums value in WPF. This is quite useful when you have optional values.

So lets start with a simple ViewModel shall we, it can be seen that this ViewModel uses a Nullable<ProductType> and that the ProductType itself uses the DescriptionAttribute

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;


namespace WpfApplication1
{
    public enum ProductType
    {
        [Description("Wet Food")]
        WetFood=1,
 
        [Description("Dry Food")]
        DryFood=2
    }
    public class MainWindowViewModel : INotifyPropertyChanged
    {

        private ProductType? selectedProductType ;

        public ProductType? SelectedProductType
        {
          get
          {
              return selectedProductType;
          }
          set
          {
              selectedProductType = value;
              OnPropertyChanged();
          }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(
            [CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, 
                new PropertyChangedEventArgs(propertyName));


        }
    }
}

All good so far, so now lets look at the XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:sys="clr-namespace:System;assembly=mscorlib"
       xmlns:local="clr-namespace:WpfApplication1"
       Title="MainWindow" Height="350" Width="525">


    <Window.Resources>

        <ObjectDataProvider x:Key="ProductTypeEnumProvider"
                MethodName="GetValues"
                ObjectType="{x:Type sys:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:ProductType" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>



    <Grid>


        <ComboBox HorizontalAlignment="Center" VerticalAlignment="Center"
                  
                  
                SelectedItem="{Binding SelectedProductType, 
                    Converter={x:Static local:NullableEnumConverter.Instance}, 
                        ConverterParameter={x:Static local:ProductType.DryFood}}">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock  Text="{Binding   Path=., Mode=OneWay, 
                        Converter={x:Static local:NullableEnumToFriendlyNameConverter.Instance}}"
                        Height="Auto"
                        Margin="0" 
                        VerticalAlignment="Center"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
            <ComboBox.ItemsSource>
                <CompositeCollection>
                    <x:Static Member="local:NullHelper.NullComboStringValue"/>
                    <CollectionContainer Collection="{Binding 
                        Source={StaticResource ProductTypeEnumProvider}}" />
                </CompositeCollection>
            </ComboBox.ItemsSource>
        </ComboBox>


    </Grid>
</Window>

Most of that is standard stuff. What is nice with my approach here is the use of the CompositeCollection which allows you to treat disparate sources as one overall source, in this case an empty string, and the actual enum values form the final ItemSource for the ComboBox

The empty string is within this small helper class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WpfApplication1
{
    public class NullHelper
    {
        public static string NullComboStringValue
        {
            get
            {
                return "None";
            }
        }
    }
}

And there are also a couple of value converters that deal with the nullable enum value:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Data;


namespace WpfApplication1
{
    public class NullableEnumConverter : IValueConverter
    {
        private NullableEnumConverter()
        {

        }

        static NullableEnumConverter()
        {
            Instance = new NullableEnumConverter();
        }

        public static NullableEnumConverter Instance { get; private set; }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
            {
                return NullHelper.NullComboStringValue;
            }
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Type enumType = parameter.GetType();
            if (value.ToString().Equals(NullHelper.NullComboStringValue))
            {
                return null;
            }
            object rawEnum = Enum.Parse(enumType, value.ToString());
            return System.Convert.ChangeType(rawEnum, enumType);
        }
    }
}

And also one that is responsible for showing the friendly name of the DescriptionAttribute that the enum values make use of:

using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows.Data;


namespace WpfApplication1
{
    /// <summary>
    /// This class simply takes an enum and uses some reflection to obtain
    /// the friendly name for the enum. Where the friendlier name is
    /// obtained using the DescriptionAttribute, which hold the localized
    /// value read from the resource file for the enum
    /// </summary>
    [ValueConversion(typeof(object), typeof(String))]
    public class NullableEnumToFriendlyNameConverter : IValueConverter
    {

        private NullableEnumToFriendlyNameConverter()
        {

        }

        static NullableEnumToFriendlyNameConverter()
        {
            Instance = new NullableEnumToFriendlyNameConverter();
        }

        public static NullableEnumToFriendlyNameConverter Instance { get; private set; }


#region IValueConverter implementation
 
        /// <summary>
        /// Convert value for binding from source object
        /// </summary>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // To get around the stupid wpf designer bug
            if (value != null && !string.IsNullOrEmpty(value.ToString()) && !value.ToString().Equals(NullHelper.NullComboStringValue))
            {
                FieldInfo fi = value.GetType().GetField(value.ToString());
 
                // To get around the stupid wpf designer bug
                if (fi != null)
                {
                    var attributes =
                        (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
 
                    return ((attributes.Length > 0) &&
                            (!String.IsNullOrEmpty(attributes[0].Description)))
                               ?
                                   attributes[0].Description
                               : value.ToString();
                }
            }
 
            return NullHelper.NullComboStringValue;
        }
 
        /// <summary>
        /// ConvertBack value from binding back to source object
        /// </summary>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new Exception("Cant convert back");
        }
        #endregion    
    }
}

Hope that helps you in some small way. I know this post was a small one, but hopefully its useful

Advertisements

ViewModel 1st Child Container PRISM Navigation

I have recently just started work on a greenfield WPF project using PRISM 4. When I started I knew that we would be used a workspace driven design and that I wanted to go VM first route, and that I wanted to make use of PRISMs navigation API.

I was also pretty keen to try and use child IOC containers for my workspaces where possible, such that the life cycle of the child container could be coupled to the VM that would be shown for a workspace. That way when the VM was closed the child container and all its dependencies would also be cleaned up.

So I had a bit of a play around with PRISM and managed to get that work out quite nicely. If this sounds like it would be of use to you, you can learn more by reading the full article, which is available right here:

http://www.codeproject.com/Articles/640573/ViewModel-1st-Child-Container-PRISM-Navigation

MVVM Diagram Designer

A while back a user called “sucram (real name Marcus)” posted a series of articles here about how to create a diagram designer using WPF. Sucrams original links are as follows:

I remember being truly blown away by this series of articles, as they showed you how to do the following things:

  • Toolbox
  • Drag and Drop
  • Rubber band selection using Adorners
  • Resizing items using Adorners
  • Rotating items using Adorners
  • Connecting items
  • Scrollable designer surface, complete with zoombox

WOW that sounds fantastic, sounds exactly like the sort of things you would need to create a fully functional diagram designer. Well Yeah, its was and still is, but……..the thing is I have used WPF a lot, and trying to use the code attached to sucrams series of article in WPF just wasn’t that great. He had taken a very control centric view, in that everything was geared around adding new controls and supplying static styles for said controls.

In reality it was more like working with a Win Forms application. Not that there is anything wrong with that, and I really truly do not mean to sound ungrateful, as that could not be further from the truth, without that original series of articles it would have taken me a lot longer to come up with a working diagram designer that I was happy with. So for that I am truly grateful, thanks sucram you rock.

Anyway as I say sucrams original codebase took a very control centric point of view, and added controls using code behind, and held collections of items directly in the diagram surface control. As I say if that is what you want cool, however, it was not what I wanted. What I wanted was

  • All of the features of curams original code (actually I didn’t want any rotating of items, or resizing of items)
  • A more MVVM driven approach, you know allow data binding of items, delete of items via ICommand etc. etc.
  • Allow me to control the creation of an entire diagram from within a single ViewModel
  • Allow for complex objects to be added to the diagram i.e. ViewModels that I could style using DataTemplate(s). Sucrams original code only allowed simply strings to be used as a DataContext which would control what ImageSource an Image would use to show for a diagram item. I needed my items to be quite rich and allow popups to be shown and associated with the diagram item, such that the data related to the diagram item could be manipulated
  • Allow me to save the diagram to some backing store
  • Allow me to load a previously saved diagram from some backing store

To this end I have pretty much completely re-written sucrams original code, I think there is probably about 2 classes that stayed the same, there is now more code, a lot more, however from an end user experience, I think it is now dead easy to control the creation of diagrams from a centralized ViewModel, which allows a diagram to be created via well known WPF paradigms like Binding/DataTemplating.

So I decided to give this a go, you can read more about it here : http://www.codeproject.com/Articles/484616/MVVM-Diagram-Designer

 

Hope its of some use to someone

Metro Style Panorama Control For WPF

The other day as part of a bigger article I am working on I wanted a control something like the Metro (Win8/Metro) UI, but for WPF. I had a look around and there weren’t that many out there, and the ones that were out there seems to scroll in weird and unfamiliar ways. So I decided to write my own, now its not exactly the same as the Windows8 one, but it does offer these features

  • Templating ability via DataTemplates (in your own code…Bonus)
  • Its a lookless control, as such template/style it it as you see fit
  • Its easy to use
  • 2 forms of scrolling, either snapback or using friction to current mouse co-ordinates

 

Here is a screen shot of it

 

PanoramaBig

Here the full article which has the code and describes how to use it:

http://www.codeproject.com/Articles/370650/Simple-Metro-Style-Panorama-Control-For-WPF

200% Reflective Class Diagram Creation Tool

Some of you may have been www.codeproject.com members for quite some time, and may recall about 4 years ago I published a article which drew a class diagram from a Dll/exec called "AutoDiagrammer" I was quite lucky with that article, as it turned out to be very popular, and got loads of votes and a tonne of views, basically people seemed to love it, which is ace…I was very happy with that. Every author here wants people to like the stuff they publish (myself included, its the whole vanity thing I suppose).

Thing is, I wrote that orginal article a long time ago, when I was just getting into WPF, and although I was pretty happy with it, I always thought it could be so much better. So fast forward a couple of years, I now know enough WPF to really do justice to the orginal article and get it how I always envisaged it could be.

The things that I felt were wrong with the 1st  "AutoDiagrammer" article were as follows:

  1. The drawing of class associations was based on a grid layout
  2. The user could not move the classes around on the design surface, once they were laid out that was it
  3. The Association lines were not that clear to see
  4. The user could not scale the produced diagram that well (it was possible, but was not that great)
  5. The loading of the Dll/Exe to be drawn as a class diagram was done in the same AppDomain as the AutoDiagrammer.exe app, so when reflecting would be forced into loading ALL the additionally reflected types from the Dll/Exe into the AutoDiagrammer.exe apps AppDomain. Ouch…Not cool
  6. People found is slightly cumbersome figuring out how to get a diagram actually produced

That said, there were things I feel I definately got right such as

  1. The overall idea (people seemed to generally like it, and find it a very useful tool)
  2. The reflecting of information was correct
  3. The ability to fine tune what was show on the diagram

With all these good and bad points in mind coupled with the fact that I now know enough WPF to do the original code justice and do it how I always wanted to do it, I thought..YES the time is right, do a complete re-write of the original article.

So that is what this article is, it is a complete re-write of the original  "AutoDiagrammer" article, the feature list of this new articles code is:

  1. Detection of valid .NET assembly (Yes same as the 1st article, this tool only works with .NET Assemblies)
  2. The ability to move the classes in the design surface within the diagram
  3. The ability to not show classes that did not have any associations on the diagram, but still allow the user the ability to view these from a drop down list. This aids in keeping the diagram clutter free, only show what is absolutely needed
  4. Persisted settings, so that the next time the application is run, your personal settings will be as you left them
  5. Proper scaling of objects as vectors, so whatever scale the diagram is viewed at the objects are as clear as they could be
  6. Saving of the diagram to a XPS (Extensible Paper Standard) document which can easily be viewed using the standard Window XPS Viewer
  7. Printing a XPS document to a printer
  8. Loading the Dll/Exe into a seperate AppDomain that does not poluate the AutoDiagrammer.exe AppDomainwith the loaded Dll/Exe types
  9. Integrated help
  10. The classes show a full Association popup with all Associations shown a list of strings
  11. The Association lines show in a different color when the user hovers over them with the mouse
  12. Better detection of Associations between classes via parsing of method body IL (Intermediate Language)
  13. The ability to view method body IL (Intermediate Language)

As you can see I have kept what was good with the old article/codebase and have added more features to it. I am really happy with how it turned out and I hope you will be to.

 

if you want to know more you can read the full article over at this link:

http://www.codeproject.com/KB/WPF/AutoDiagrammerII.aspx

And here is a small screen shot of the new codebase in action:

image

WPF : Carousel Control

I have just been messing around with the PathListBox and some nice codeplex available extensions to it, which enabled me to create a nice re-usable CarouselControl for WPF.

Here is the results

images1

images2

images3

images4

images5

 

It allows things like:

  • Custom path
  • Use of inbuilt paths
  • Animation easing
  • Different buttons
  • Different templates for data

 

Want to know more?

You can read the full article over at :

 http://www.codeproject.com/KB/WPF/WPFCarouselControl.aspx

Mole2010 (a mans Visual Debugger)

A Bit Of History

As some of you may recall some time ago (seems like ages) Josh Smith (WPF Guru) wrote a Visual Studio DebuggerVisualizer which he called WoodStock, then some time later Joshs protégé Karl Shifflett wrote a new  DebuggerVisualizer  called Mole which was and still is an extremely useful debugging aid when developing WPF apps.

After Karl wrote the 1st draft of Mole, he quickly contacted Josh and they joined forced to create various flavours/versions of Mole, before being joined by Andrew Smith from Infragistics (whom Josh calls a guru, now Karl calls Josh a guru, so I think you can see what sort of calibre of people are involved with Mole).

So that was then, that was all a about a year ago, many moons have passed since then, so what have team Mole been up to, well it turns out they have been very very busy bunnies indeed….Team Mole have only gone and rewritten Mole entirely. They are calling the new offering Mole 2010.

Now I should point out that the new Mole 2010 is not a free tool, as its predecessors were, but I think the new version is way way better than the old versions, and you can take it for a demo ride before you decide.

I think it is fairly well priced at $49.99, for what it can do for you as a developer.

Now I know it sounds like I am trying to push Mole 2010, which I guess I am in some way, Josh and Karl are both friends and I want their venture to go well. That said I told Josh that I would not be blogging about Mole 2010 until I had taken it for a test ride and was comfortable with what it did and I would only be telling people the truth about it. It just happens that the truth is that it is a very cool useful tool, and I can not think of much that is actually missing.

 

Enough Enough…..Lets Have A Look At Mole 2010

As I stated Mole 2010 is a Visual Studio (2010) debugger visualizer which you can use instead of the default debugger visualizer, and when you you choose to do that you will get into the Mole 2010 interface.

So say I have some breakpoint as such.

image

It can be seen that I now get a Mole 2010 option, so let’s accept that and see what we get

image

This is what looks like when it launches it offers these sorts of view when it first loads

  • VisualTree
  • LogicalTree
  • XAML
  • SnapShot
  • Properties
  • Fields
  • All
  • Favourites

Lets further examine some of these.

VisualTree Area

image

From here we can drill as far into the VisualTree as we wish, and we can set things to expand or be used as initial node etc etc

LogicalTree

image

The LogicalTree view is the same sort of thing except we only see the items in the logical tree.

SnapShot

image

This is able to show a snapshot of the xaml as it would be rendered, which you may choose to save as an image. You may also control this updates Auto or Manually.

Xaml

image

We are also able to see XAML snippets for selected item in the VisualTree/LogicalTree

 

Properties/Fields

image

This is one of my favourite areas, where we can see what all of the property/fields of certain VisualTree/LogicalTree elements are set to. We can also choose to make certain ones favourites, so they will appear in the favourites list.

We are also able to drill in to collections, as shown above, whilst still maintaining a complete breadcrumb of where we have visited.

image

For another example lets follow some Style.Triggers

image

image

image

image

I am sure you will agree that is pretty powerful.

Visual Studio Like IDE

You can actual pin/arrange things just as you would in Visual Studio

image

 

More Mole 2010 Information

The creators of mole have written a sponsored article over at codeproject:

http://www.codeproject.com/KB/solution-center/Mole-2010.aspx

 

Final Word

Anyway that is all I wanted to say about Mole 2010, whether you buy it or not it up to you, I would recommend downloading the demo version and at least taking it for a test drive, it really is quite a cool tool.

WPF : Weird 3D Level Tree Like Control

I have just published a new article which shows a new control that I have made. When I created this control, these were the requirements I had for the control.

  • Supports transparency in 3d
  • Could pan
  • Could zoom
  • Supported some of tree like data structure in 3d space

I am pretty pleased with it overall, you can read more about the control over at codeproject : http://www.codeproject.com/KB/WPF/LevelTree3D.aspx

CinchV2 and PRISM 4 Interoperability

I have been working on 2 small demo apps using my CinchV2 MVVM framework code used in conjunction with the latest PRISM 4 release (which now uses MEF).

I am actually pretty happy with the results of how easy these 2 frameworks work together, it is almost seamless.

So if you are a fan of PRISM features such as Regions/Modules etc etc, but want some of the goodness from Cinch like the ViewModel base classes and UI Services, then the article I have made to cover these demo apps could be for you.

The url to the article is right here : http://www.codeproject.com/KB/WPF/CinchV2AndPRISM4.aspx

PRISM 4 Custom Transitioning Region

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.

image

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