C#

New Article On How To Create Fluent APIs

Of late there has been a rise in the number of people using Fluent APIs, you literally see them everywhere, but what are these "Fluent APIs"….Where can I get me one of those.

Here is what our friend Wikipedia has to say on the matter:

In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a way of implementing an object oriented API in a way that aims to provide for more readable code. A fluent interface is normally implemented by using method chaining to relay the instruction context of a subsequent call (but a fluent interface entails more than just method chaining). Generally, the context is defined through the return value of a called method self referential, where the new context is equivalent to the last context terminated through the return of a void context.

This style is marginally beneficial in readability due to its ability to provide a more fluid feel to the code however can be highly detrimental to debugging, as a fluent chain constitutes a single statement, in which debuggers may not allow setting up intermediate breakpoints for instance.

http://en.wikipedia.org/wiki/Fluent_interface up on date 14/01/2011

So what do these Fluent APIs look like, well her is an example from Fluent NHibernate:

public class CatMap : ClassMap<Cat>
{
  public CatMap()
  {
    Id(x => x.Id);
    Map(x => x.Name)
      .Length(16)
      .Not.Nullable();
    Map(x => x.Sex);
    References(x => x.Mate);
    HasMany(x => x.Kittens);
  }
}

Want to know more, like how to create your own Fluent API. Well I just wrote a small article over at codeproject that will show you how to build you own, here is the articles Fluent API that is covered:

//Threaded Version, with correct Fluent API ordering
new DummyModelDataProvider()
    .IsThreaded()
    .SortBy(x => x.LName, ListSortDirection.Descending)
    .GroupBy(x => x.Location)
    .RunThreadedWithCallback(SetDemoData);

.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; }

If you want to learn more about all of this, have a read of the article over at this url:

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

Enjoy

.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; }

Advertisements
Cinch, MVVM, Silverlight, WPF

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

MVVM, WPF

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

C#, MVVM

Cinch V2 : Question For The Reader

As some of you may know I have written a fairly popular MVVM framework called Cinch I continue to listen to peoples feedback/requests etc etc. I like to make these changes when enough requests have come through to warrant pushing out new codebase.

Unless there is of course a serious bug, in which case I will try and fix that straight away.

Question is, are you readers happy with this approach, or would you prefer to have updates as soon as possible?

They are enhancements really, and there is nothing wrong with the current codebase, but from time to time a good suggestion comes along that I like to include. Question is are you lot happy to wait for these to creep into the framework, or do you want them like now, and just have to download code again?

Could you let me know your thoughts

PS: I will not be answering these forum entries, as I just want to hear from you lot.

C#, MVP

New Years Treat

I have just received an email from Microsoft stating that I am still a Most Valuable Professional (MVP for those in the know, nudge nudge wink wink) for 2011….Cool

The MVP award means a lot to me, as it is not something one can study a book and take an exam for, its driven by your community contributions and must go before a Microsoft committee each year, to see if you still qualify, so its always good to know you did it again.

MVVM, WPF

CinchV2 : Latest News

I have just uploaded a new set of source code files for Cinch. I have taken this opportunity to fix several issues/suggestions that people put forward, and also fixed 1 silly MEF related mistake I made.

The release notes/source code codeplex comments tell the full story, but if you are using CinchV2, you should grab the latest copy, as it has 1 important fix that you should make sure you have latest code to fix.

Thanks