Design time data – Second look

In my previous blog I went through how Jounce template for Silverlight application creates default application and generates plumbing in place to use Design Time data. All the projects I have worked on, we completely ignore it. For the last couple of months, I have been consciously taking extra steps to use Design Time data. As I mentioned in my multiple posts, it is simply of the best feature most of every one ignores. Without doubt, in my opinion it is one of the easiest one to achieve without lot of learning curve and available out of the box. Jounce Silverlight Application template already creates all interfaces and implementation in place to use it. In my previous post I went though what is available out of the box. In this blog, I am going to take it one extra step.

I need to emphasis here, this would be lot more easier if we would use Expression Blend. Since we are not designers, we are going to look at solving the problem traditional way as a coder.

Here are the requirements for the application.

1. It has to display the data in grid format.

2. The column order has to be Name, Age, Salary and Sex.

3. Salary has to currency formatted and should be right aligned.

4. In case the record allows ‘IsEnable’ then change the background color of the salary field to be RED.

First we are going to create a Silverlight application using Jounce Silverlight Application framework. What I am going to do is to crate a grid, which will show our favorite Person class information. So here is our person class.

public class Person : INotifyPropertyChanged
    {
        public string Name { get; set; }
        public int Salary { get; set; }
        public char Sex { get; set; }
        public int Age { get; set; }
        public bool IsEnabled { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }

Normally the way, I go about doing is, to crank up the XAML and run the application and then see if the grid shows my data properly if not tweak the XAML, rinse and repeat the process till you get what you want. In my opinion we are wasting time on this, where all the requirement in this case can be verified in the IDE itself. Lets see how it should have been done (IMHO).

Since we have created the Silverlight application using Jounce Template, it already created the interface for data layer. I removed the default string variable to List of Person, like the following in the IMainViewModel.cs

using System.Collections.Generic;
namespace FilteringIssueOnCellTemplate.Common
{
    public interface IMainViewModel
    {
        List<Person> People { get; }
    }
}

Just a refresher here, if you look at the solution, we are after ‘DesignMainViewModel.cs’ under SampleData. This particular class will be used for design time data. We will see later how it is hooked up for design time data. For now, lets change this class to return bunch of dummy data which covers our requirement.

using System;
using FilteringIssueOnCellTemplate.Common;
using System.Collections.Generic;

namespace FilteringIssueOnCellTemplate.SampleData
{
    public class DesignMainViewModel : IMainViewModel
    {
        public List<Person> People
        {
            get
            {
                List<Person> _ppl = new List<Person>();
                _ppl.Add(new Person() { Age = 20, Name = "A", Salary = 10000, Sex = 'F', IsEnabled = true });
                _ppl.Add(new Person() { Age = 20, Name = "B", Salary = 10000, Sex = 'M', IsEnabled = false });
                _ppl.Add(new Person() { Age = 20, Name = "C", Salary = 10000, Sex = 'F', IsEnabled = false });
                _ppl.Add(new Person() { Age = 20, Name = "D", Salary = 10000, Sex = 'F', IsEnabled = true });
                _ppl.Add(new Person() { Age = 20, Name = "E", Salary = 10000, Sex = 'M', IsEnabled = false });
                _ppl.Add(new Person() { Age = 20, Name = "F", Salary = 10000, Sex = 'M', IsEnabled = true });
                return _ppl;
            }
        }
    }
}

As you can see, I have few of the records set to IsEnabled to True so we can see if the XAML I wrote really works.

<Grid x:Name="LayoutRoot" Background="White"
          d:DataContext="{d:DesignInstance sampleData:DesignMainViewModel, IsDesignTimeCreatable=True}">
</Grid>

By default the layout grid looks like this. If you notice, the second line, where d:DataContext is set to our sample view model. So Lets put our data grid control in there and see how it looks. So I am going to add my grid and bind it to Person collection ‘People’ like the following

<c1:C1FlexGrid ItemsSource="{Binding People}"/>

Now if you see the design screen after adding the line would like the following

image 

So we need to change the column order and display only required fields. So I modify the XAML like the following

<c1:C1FlexGrid ItemsSource="{Binding People}">
            <c1:C1FlexGrid.Columns>
                <c1:Column Binding="{Binding Name, Mode=TwoWay}"/>
                <c1:Column Binding="{Binding Age, Mode=TwoWay}"/>
                <c1:Column Binding="{Binding Salary, Mode=TwoWay}"/>
                <c1:Column Binding="{Binding Sex, Mode=TwoWay}"/>
            </c1:C1FlexGrid.Columns>
        </c1:C1FlexGrid>

If you are like the normal developer here you would compile and run to see how it looks, I say ‘stop’ and look at the design panel

image 

You might have noticed, Name field appears twice so we have a bug in the XAML.  It is easy, by default, data grid AutoGenerateColumn is True so we change it to False. Now after adding and look at the design Panel, the duplicate column is gone.

image

Now we are going to tweak the XAML to add additional requirements. lets look at the simple ones, Need to change the formatting of the column to currency and right aligned. Modify the salary column to the following

<c1:Column Binding="{Binding Salary, Mode=TwoWay, StringFormat=c}" HorizontalAlignment="Right"/>

 

The interesting part here is that, as you change you can see design panel changes. With the above changes, now you got the gird to look almost close to what you want except the back ground color.

image

Now we need to set the back ground color of the salary, you can not do dynamic binding to back ground for a column, only way you can do that is through the cell template.

Before I write cell template, I am going to write a converter which will check and see if IsEnabled is set to true or false like the following

public class ColorConverterForRowType : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool item = (bool)value;

            if (item == false)
                return new SolidColorBrush(Color.FromArgb(255, 0xde, 0xe2, 0xe6));

            return new SolidColorBrush(Colors.Red);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }
    }

Now add the cell template in the XAML as follows

 

<c1:Column Binding="{Binding Salary, Mode=TwoWay, StringFormat=c}" HorizontalAlignment="Right">
                    <c1:Column.CellTemplate>
                        <DataTemplate>
                            <Grid>
                                <Border Background="{Binding IsEnabled, Converter={StaticResource ColorConverterForRowType}}"/>
                                <TextBlock Text="{Binding Salary, Mode=TwoWay, StringFormat=c}" HorizontalAlignment="Right"/>
                            </Grid>
                        </DataTemplate>
                    </c1:Column.CellTemplate>
                </c1:Column>

Now just compile the code and see what is in the panel

image

Look at it, we did not run once and we got the look and feel the initial requirement. It is very easy and avoid all those multi runs to see if the screen looks like we need.

Design Time Data in Silverlight

Recently I read an outstanding article on MVVM by Ward Bell. If haven’t read it, please go back and read it. If you don’t read it for technical aspect, read it for the way he wrote it. It was well written and have excellent content. I really like the way, he took apart the MVVM and looked at it from completely opposite side of it. I totally agree with him on the two points that he finished his article on.

1. MVVM gives good design time data.

2. Unit testing of VM.

I have been coding heavily in SL for some time now. I was developing application using MVVM from day one, but and I need to confess here, I did not do either of the items so far. I completely ignored (1) and troubled a lot with (2). Finally I gave up both the items and developed application in MVVM for easy maintenance and scalability.  After reading the article I realized, I am completely wasting a great feature SL for design time data. So I thought, I will create a simple application and show and learn how to do design time data.

Like all my application, I always starts with Jounce. If you have not looked at Jounce, I would highly recommend it. If you have any problem using Jounce, you can contact me and I will see if I can find answer for you, if not, you can always post the question in Jounce Codeplex. Hopefully you have already installed Jounce Template, if not you will find the VS2010 template at the bottom of the Jounce Ccodeplex page. So now that we have all the required items, lets start rolling.

Start VS2010 and create a brand new Jounce Application. Build the application and run it. yes, do not change anything, just compile and run it. it is supposed to build with out any errors and will display a browser window with ‘Welcome to Jounce’ message. Ok now that we got the basic program running and before we make any changes, lets look at the solution structure.

image

I did not change anything, this is the default structure. In here, you will see four folders.

Common: Interface for main view model.

Jounce: location of jounce reference dll.

SampleData: Lets put a pin here and we will come back here since it is our point of interest.

ViewModel: As the name suggests, it is the view model class.

Now, lets open XAML, it will look something like the following

image

If you see in the design screen, there is a text block which have a text block that shows “This is some design-time text.”. If you look at the XAML, the text block does not have the value. So how and where did it get it? Before I answer that question, lets look at the binding. There are two types of binding, yes, I know, I did not know this either. They are design time binding and run time binding. All the binding we have done so far is run time binding. We create a binding to a control, we run the application and see the data bound to the control, which is run time binding. On the other hand, the design time binding as the name suggests, will bind the data to the control during design time so that you can see the control how it looks. This is extremely useful, if you have designer working along with developer using expression blend to create front end UI for you. There are two important content in the XAML which did design time binding for you.

image

The first green box, establishes the xml namespace for our sample class. The second box did the design time data binding. By default, when you want to use design time data binding, you create a xml namespace pointing to blend and mark it as mc:Ignorable. The later part is to make sure XAML parser will not complain if there is a XAML parse error on design time. Lets look at the d:DataContext in the Grid. what we are saying here, is that for design time data binding, the data comes from an instance of DesignMainViewModel of name space desfined as sampleData. Also create an instance if it is not available. It is very straight forward.

Now lets look at the DesignMainViewModel class.

using System;
using JounceAppWithDesignDataAndTesting.Common;

namespace JounceAppWithDesignDataAndTesting.SampleData
{
    public class DesignMainViewModel : IMainViewModel
    {
        public string WelcomeText
        {
            get { return "This is some design-time text."; }
        }
    }
}

if you look at this, it is a very simple class, which implements IMainViewModel interface and yes, it is the data that we see in XAML design page.

namespace JounceAppWithDesignDataAndTesting.Common
{
    public interface IMainViewModel
    {
        string WelcomeText { get; }
    }
}

If you remember when you run the application the result will be something like this

image

Now where did this message comes from. Well, we did not see the run time, that is the view model implementation.

using System;
using Jounce.Core.ViewModel;
using JounceAppWithDesignDataAndTesting.Common;

namespace JounceAppWithDesignDataAndTesting.ViewModel
{
    [ExportAsViewModel("MainViewModel")]
    public class MainViewModel : BaseViewModel, IMainViewModel
    {
        public string WelcomeText
        {
            get { return "Welcome to Jounce."; }
        }
    }
}

As you can see, the WelcomeTtext return "Welcome to Jounce." during run time and that is what get bound to the text block. So the bottom line is;

1. Create an interface so that all data bound values are available during design time.

2. Create Design time view model which returns dummy data based off of the interface defined in step 1.

3. Make sure, implement the interface in the view model.

4. In XAML make sure design name spaces are defined and then bind the grid to the design time instance.

In this example, I did not make any changes to the default project since Jounce by itself creates the design time binding structure for us and that we can leverage for next examples. I will take an attempt at one more design time data binding and then go to Unit testing in Silverlight.

If any of you have any questions or comments, I would love to hear from you.