PDC09 – Meet the Griffs Code drop

Ian and myself really enjoyed presenting our pre conference session  “Getting the most out of Silverlight” and we both hope that you enjoyed the sessions. The slide decks will be posted at some point by the event team and I will update the post when this happens so that you can get copies of the decks.

As promised I have stashed all the final code examples up on my skydrive folder so that you can download and play with the samples. As we ran out of time in the last session what I will do in the next week or so is to record a Camtasia session and capture what I unfortunately did not get time to go over during the session.

I have named the zip files as intuitively as possible so these line up with the title of the session.

What I also wanted to briefly mention is that in the MEF and Ninject demos you will see that I am using Commands from the Silverlight Extensions project on CodePlex. The command pattern that is used here is a standard command pattern common to WPF. In the current release there is no support for Commands so what you will see included in the projects are the Command classes that I need in order to harness the power of Commands.

In a previous life I wrote a post on WPF commands that you may want to take a look at if you are not familiar to the Command pattern used in WPF and how it helps to separate out UI logic into you View Model and helps increase the testability of your code that responds to the behaviours in your application. The refactor that I did here was to remove the click event handler on the button and replace this with a command. There are 3 steps for refactoring out the event handler.

First we need to create a commands.cs file and create a Commands class which will hold all our commands associated with our view model. In essence we are going to be providing a list of possible actions that the View Model can perform in relation to the view. Once we have created the class we need to define our commands that we want which in our demo is called RefreshFeedItems then we need to add in public mechanism so that we can invoke the command from the view so that it can be wired up to a button.


using StandardViewModel.SLExtensions.Input;

public class Commands
{
      private static readonly Command refreshFeeds = new Command(RefreshFeedItems);

      public static Command RefreshFeedItems

      { get { return refreshFeeds; } } }

Now that we have defined the command that we want to fire we need to do the second part which is to wire up the command in the Xaml of the view.

     Input:CommandService.Command=RefreshFeedItems

     <Button Content=Refresh
                    Grid.Column=2
                    Margin="3,3,3,3"
                    IsEnabled="{Binding IsRefreshEnabled}"
                    Input:CommandService.Command="RefreshFeedItems" />

We can now remove the click handler code behind of the view.

The finally part is to implement the CanExecute and Executed code in the ViewModel, so move into the Constructor of the ViewModel and here wire up the commands.

       Commands.RefreshFeedItems.CanExecute += (sender, args) args.CanExecute = true;
       Commands.RefreshFeedItems.Executed += delegate(object sender, ExecutedEventArgs args)
         {
                        Refresh();
         };

And we are done. Enjoy. One thing to note is that there are other types of commands, RelayCommand and DelegateCommand which are also very cool black belt ninja moves for dealing with separation when building your MVVM apps

Using contextual design time data with SketchFlow

Design time data can be used to provide contextual data for your sketches and prototypes when demonstrating these ideas to your clients.  I want to highlight some of the areas that I am leveraging today that have helped to speed up the process of creating prototypes and my interaction with User Experience and Visual designers.

WelcomBackScreen My aim was to build a simple prototype using design time data in the prototype in order to provide a more contextually rich prototype for the user to interact with. This can be done alongside the sketches which the User Experience person is putting together or later once you have drilled  down to a couple of sketches which your client want to move into a prototype phase. From a developer prospective getting to know what data you have available and the ability to communicate with the UX on how this can be visualise early on in the process I have found to be invaluable.

So the prototype that I want to attempt is a simple shopping cart style application that communicates to the client what we are thinking about with regards to a User Journey which illustrates; how users will login into the application; a filtered list of products which meet previous buying habits; the ability to the user purchase items; and a page to show the checkout of those items. There is also a design element which means that the user has a personalised greeting on each of the pages.

To create each of the screens is trivial, in the sketchflow flow document window right click and add your screens give them the right names and link the screens together to illustrate the flow for the user journey. Next take the sketches from the UE and import them into Blend, luckily for me the designs are in a psd format so I can easily import these into Blend and get up and running, if this is not there are other supported formats which can be imported easily. Once we have the screens in place and sketches imported the next step is to add navigation behaviours so that when the prototype runs in the player our client can interact with the prototype and follow the journey.DesignTimeDataDataTab
As we are not intending on writing any logic at all and adding the design time data support is something we want to do in the lightest possible way our goal is to communicate the flow of the application and the journey the user will follow when interacting rather than logic and branding. The prototype at this stage is really to uncover the functionality and highlight where the complexity may be when implementing that logic, in order for us to communicate with the client potential areas of functionality which are going to be expensive to build in order for the client to assess the ROI of the features to be built in our initial brief. Therefore, we should not be including design elements at this stage or anything that lets our client get distracted from the journey and proposed experience that we want to take the user on when performing this particular task. For me, design elements come later when we have done a couple of iterations and have decided on the idea which we are going to take into production.
My intentions were to create a collection for the shopping basket and get this to contain a custom data type of productitem however when I attempted to do this blend does not recompile the .cs file correctly and thus I get an error in the design time data Xaml.

How does the design time data work?

When you are creating deign time data from the Blend menu, Blend is kindly generating the code behind to support your data structures that you are specifying for your prototype. The Xaml file produced is where you data that populate the code behind lives. The xsd is the mapping of the types and their definition. The xsd is an auto generated from the .cs file which Blend creates.

Unfortunately in the current release there is no support for copying and pasting data, so there is no support for creating a collection and then copying these contents to another collection, this is also the case for copying and pasting complex objects around your data source. The scenario why it would be good to have this functionality can be seen in our sample prototype, we have a list of products and we want to add the products collection to our shopping basket collection, therefore the ability to copy our predefined data into our new collection would be very helpful. Especially when we take into consideration that both collections are of the same type. So what choices do we have, well from what I can find there seems to be 2 options; BuyScreenfirst re adding the items using the Blend UI; or roll up your sleeves and edit the cs manually. If you are nervous about cs then option 1 is the right way.
One of the reasons why this functionality does not seem to be present in Blend is that there is a certain level of heuristics involved where Blend has to interpret what we mean and this in itself could become a nontrivial piece of functionality however, it is still possible and I hope to see this functionality in the next release (fingers crossed).

  1. If you want to change the cs file here are the steps :-
    1. First create the design time data structure that is required for the products collection, next create your Shopping basket collection.
    2. Save and build the project.
    3. Open up the .cs file and in here you will find the classes for the product and the product collection classes, you will also find the new definitions for the shopping basket collection and the items contained in that collection.
    4. Remove the shopping basket item class and modify the collection so that it contains a type of product item class.
    5. Save the project and build. You should get a compilation error in the Xaml file as the ShoppingBasket Item class is no longer defined.
    6. Open up the Xaml file and copy the product items from the product collection and paste them into the shopping basket collection.
    7. Save and build the project and you should have a successful build. We can then bind the shopping basket to the shopping basket user control.

So although there is some manual work to do its rather trivial hence the reason why i think this process could be automated.

Once again the power of design time data can be harnessed to provide a richer experience for your prototype, it is however important to only start doing these tasks at the right iteration, and at the moment this is normally around when you have started to dig into a reduced set of ideas that could be used to move into a prototype and its at this iteration where analysis of the datasets needs to be cleared up and an understanding of what data needs to be presented to the UI in order to provide a rich User Experience.
Using data templates to present the data means that we can layout and display contextual data for those parts of the user journey, Blend support for GUI editing of data templates when used in itemscontrols provides a quick and graphical mechanism for editing the layout. Its also the creation of these styles and templates later on in the final stages of the prototyping have potential high levels of reusability when moving into build the clients POC, what is interesting is that around this stage you are more than likely to be building visuals for the POC. Designers assets produced as vector graphics, adobe illustrator and Photoshop files can be imported into Blend in order to create styles and templates in order to recreate the visual design. Those datatemplates which were built in the earlier iterations can be reused with new Styles and Control templates providing you with the ability to speed up the entire process and potentially create a higher number of prototypes that show different visualisations of data and potential experiences.

MVVM, design time data, and Blendability

DesigntimedataprojectstructureWith the introduction of design time data support in Blend I thought that I would try and take advantage of using design time data and MVVM. For a while now I have been using Ninject, with a Service Locator Pattern to provide the ability to build WPF and Silverlight apps in an MVVM pattern where I prefer to use a View first mechanism. There are a number of benefits from using this approach, one of the ones that we are good to drill to in this post is around Blendability of the controls that developers create. Prior to me using Ninject I would have a heavy reliance on the DesignerProperties IsInDesignMode call to check to see if the control was being render in Blend, as i would normally have to do something to stop the control from crashing and allow myself and the designer to use Blend in order for us to Style and Template the controls we created.

What we are going to cover here is the journey which i went on when adding support for design time data to my project, I really like it as the refactoring from the standard inbuilt mechanism in Blend to the final output is a nice series of steps that feel good.
Designtimedata

The screen shot on the right shows the simple looking UI displaying contextual data in Blend allowing the designer to see how the control will look. I think providing the ability for your application to look exactly the same at design time as at run time is going to mean that you can produce better looking applications quicker as the designer is design the screens in the context of the data.

When first adding the design time data to your project Blend takes over control and this means that you need to use Blend to shape your design time data classes to match your data types used in the system. So if we were building a throw away prototype then I would agree this is the best way forwards, but when you are moving from prototype to production this does not really work. On of the reasons behind the research for this post is around the transition from prototype to production and even from sketch to prototype, once we have sign off from the client on a number of ideas and we want to start to build these out then there is a high potential one will become production quality and because of this its good to have the right architecture in place, so reshaping to MVVM early on will almost certainly cost your client less.

The Xaml below is what i put together to represent the shape of data that was in the mock classes. Blend then hooks this data up to the design time data context for you.

Xaml data for shopping cart

<local:ShoppingCartViewModel xmlns:local="clr-namespace:DesignDataSample;assembly=DesignDataSample">
    <local:ShoppingCartViewModel.ShoppingCart xmlns:local="clr-namespace:DesignDataSample;assembly=DesignDataSample">
        <local:ShoppingCart>
            <local:ShoppingCart.Items>
                <local:ShoppingCartItem ItemName="Book Name 1"
                                        ItemDescription="A very nice book!"
                                        ItemImage="MySampleDataImages/Tree.jpg" />
                <local:ShoppingCartItem ItemName="Book Name 2"
                                        ItemDescription="A very nice book!"
                                        ItemImage="MySampleDataImages/Tree.jpg" />
                <local:ShoppingCartItem ItemName="Book Name 3"
                                        ItemDescription="A very nice book!"
                                        ItemImage="MySampleDataImages/Tree.jpg" />
                <local:ShoppingCartItem ItemName="Book Name 4"
                                        ItemDescription="A very nice book!"
                                        ItemImage="MySampleDataImages/Tree.jpg" />
            </local:ShoppingCart.Items>
        </local:ShoppingCart>
    </local:ShoppingCartViewModel.ShoppingCart>
</local:ShoppingCartViewModel>

When the design time data shape matches your real data shape you can then go ahead and use the new d:DataContext Dependency Property and bind your design time data to this property.

Xaml Source code for the control

<UserControl
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="DesignDataSample.ShoppingCartView"
             d:DataContext="{d:DesignData Source=ShoppingCartSampleData.xaml}"
             DataContext="{Binding Path=ShoppingCartViewModel, Source={StaticResource serviceLocator}}"
             Height="347"
             Width="494">

Nothing too tricky there, the new design time data context is the key to making all this happen, it also means that you can bind any sort of data you want to the design time data context to provide contextual data in Blend during design time. It was at this point that i started to think about how we can really bend the design time data features. My initial refactor was not a great result in that I ended up with 2 sets of mock data; one set of data would be used by the designers in Blend; and the second set of data would be used by the unit test, Not nice, management nightmare to ensure that both data sets are keep in sync.

So the goal was to provide design time data which was the same data used by the unit tests, meaning that we only have one data set to maintain and manage, allowing us to leverage the powerful features of design time data in Blend and also keeping our unit tests looking sweet, pleasing both the designers and the developers on the team.

In order to do this I needed to restructure the existing shape of my data classes that I use in my mock service layer classes, first I needed to change the OnCompleted method to be a virtual implementation and also the method which retrieves the data. This simple change means that we can now provide two mock services that can be injected in.

Refactored mock service class with new virtual methods

    using System;
    using System.Collections.ObjectModel;

    public class MockShoppingCartService : IShoppingCartService
    {
        public event GetShoppingCartCompletedHandler GetShoppingCartCompleted;

        public bool LoginToShoppingCart(string username, string password)
        {
            throw new System.NotImplementedException();
        }

        public virtual void RetrieveShoppingCart()
        {
            this.OnGetShoppingCartCompleted(null, MockShoppingCartData.CreateShoppingCartRuntime());
        }

        protected virtual void OnGetShoppingCartCompleted(Exception error, ShoppingCart result)
        {
            if (this.GetShoppingCartCompleted != null)
            {
                this.GetShoppingCartCompleted(new GetShoppingCartCompletedEventArgs(error, result));
            }
        }
    }

The new mock service class which is used specifically for working with Blend

namespace DesignDataSample.Mocks
{
    public class MockShoppingCartServiceDesignData : MockShoppingCartService
    {
        public override void RetrieveShoppingCart()
        {
            this.OnGetShoppingCartCompleted(null, MockShoppingCartData.CreateShoppingCartDesigntime());
        }
    }
}

How we can use ninject to inject the service we want to use, design time data, mock or real.

this.Bind<IShoppingCartService>().To<MockShoppingCartService>().OnlyIf(c => isBrowser);
this.Bind<IShoppingCartService>().To<MockShoppingCartServiceDesignData>().OnlyIf(c => isBlend);
this.Bind<IShoppingCartService>().To<ShoppingCartService>().OnlyIf(c => isBrowser);
this.Bind<ShoppingCartViewModel>().ToSelf();

Xaml code for how we leverage the data context and the new design time data context for providing contextual data.

<UserControl
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="DesignDataSample.ShoppingCartView"
             d:DataContext="{Binding Path=ShoppingCartViewModel, Source={StaticResource serviceLocator}}"
             DataContext="{Binding Path=ShoppingCartViewModel, Source={StaticResource serviceLocator}}" Height="347" Width="494">
<!--d:DataContext="{d:DesignData Source=ShoppingCartSampleData.xaml}"-->
    <UserControl.Resources>
        <DataTemplate x:Key="ShoppingCartItemTemplate">
            <Grid Height="50">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>

                <Image Source="{Binding ItemImage}"
                       Grid.RowSpan="2" />
                <TextBlock Text="{Binding ItemName}"
                           Grid.Column="1"
                           Margin="4,0,0,0" />
                <TextBlock Text="{Binding ItemDescription}"
                           Grid.Column="1"
                           Grid.Row="1"
                           Margin="4,0,0,0" />
            </Grid>
        </DataTemplate>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot"
          Background="#FFB2B2B2">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="129" />
            <ColumnDefinition Width="121" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="50" />
        </Grid.RowDefinitions>
        <ListBox Margin="8,8,8,26"
                 Grid.ColumnSpan="3"
                 ItemsSource="{Binding Mode=OneWay, Path=ShoppingCart.Items}"
                 ItemTemplate="{StaticResource ShoppingCartItemTemplate}" />
        <TextBlock Grid.Row="1"
                   Text="Total Items:"
                   TextWrapping="Wrap"
                   Grid.Column="1" />
        <TextBlock Grid.Column="2"
                   Grid.Row="1"
                   Text="{Binding ShoppingCart.Items.Count}"
                   TextWrapping="Wrap" />
    </Grid>
</UserControl>

 

So I hope that this article has opened your eyes to how useful design time data can be to enhance the Blendability of the controls which you produce both lookless and user. In the majority of cases designers that you are working with really like that they can view the control at deign time how it will appear when running in your application and populated with data.  When implementing the MVVM pattern in you application incorporating support for design time data is also possible and provides you with the ultimate Xaml Ninja experience.

You can download the source from my Skydrive.