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.

Do you have NuGet? if not GoGet

I use Jounce as MVVM framework for my development. Earlier I used to download the latest version put it in some reference folder and let my application reference that folder. All was working good till I found NuGet. NuGet is a open source package management system. Never used a package manager before in my VS development so never bothered about it till now. It is easy to get started with NuGet, go to the link and install the NuGet.

For testing, lets create a new Silverlight application project. Next I want to add a jounce reference. There is a better way to create Jounce project that I will explain later. When you right click on the project, you will see a drop down with following options

image

Lets select the last option and then choose Online in the left most options as shown below.

image

What I want to install is Jounce, since I know the name I search directly using the search option on the top right hand corner and it will take us to the package directly.

image

Now if you install it, it will create the package folder in the solution and adds the references to the solution with local reference. That is it. I really like NuGet on this perspective it is very easy to find and add correct references in the solution.

Now going back to the first point, what is the better way to add Jounce solution, of course using Jounce template. Go to Jounce Codeplex page

image

and install the template. Now create a new project and again, search for Jounce at the top right hand corner which will take you directly to Jounce template and create you project and you are set.

image

Thats all about it.

XAP optimization

I created a very simple example which have two grids, one is master grid and another one is total grid. Total gird, totals any field which has decimal field in it. Nothing complicated. As any developer, I was adding code if I miss any namespace I add them. Some time, I add some system references that I might not even use later as I progress but forget to remove from the solution. So with that all in mind, after building the solution and run as I expected it to run and deploy it. Some time you night get a complain that it takes for ever to load. If you ever hear or if you see that yourself when you start testing, take a look at the size of the XAP file in ClientBin folder. Chances are your XAP is big.

Going back to the sample I was talking about, with out any code changes, the XAP file size is 880KB. Next we are going to see how we can reduce the size of the file and user experience is better. I attempted that with couple of ways.

1. Using Component One XAP optimizer:

I got a license for Component One XAP optimizer and thought of give a world and see how much size reduction happens. I pass the current XAP as the input and it can generate new XAP file or override the existing one. Here is the result of the XAP optimization.

image

The new file size is 336KB, more than 50% size reduction. In this approach the files are still in single XAP file and there are no external files to download. What I attempted was a very simple solution, it seems it has lot more features that you could use for more complex projects.

2. Using Visual Studio XAP optimization using application library caching:

From SL3 and forward,  there is a way we can optimize the XAP files by removing the system and third party controls from the required elements of XAP. You can read more about how it is done in Tim’s blog. Using that approach I was able to get the XAP file size reduced to 229KB. All the required dlls are separated out to its on ZIP files.

image

[Following was incorrect. As of now, following combination broke the Silverlight application. Once I know why it is not working, I will update here.]

3. Using Component One Optimization on top Visual Studio optimization:

As you have guessed, we should be able apply C1 optimization and get a better initial performance. With the optimization applied the XAP file size reduced to 166KB.

I am really happy with the overall size reduction from 880KB to 166KB. If any of you have any other better way of doing optimization, would love to hear it.

ForEach in IEnumerable

Recently one of my friend asked me, is it possible to do foreach on an IEnumerable. I said ‘yes’ based on my knowledge on List. But it turned out I was wrong. You can not do ForEach on an IEnumerable right out of the box. It doesn’t mean, you can’t do it, it was not implemented. So I asked the question, can’t you use foreach? The answer was, sure. It was the person’s curiosity that led me to see why it was not implemented to start with. I did couple of Google search and got the following link, which explained very well why it was not implemented and if you want how you would implement it.

It is a very good read for anyone interested.

http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx

Also there was a little debate in StackOverflow on the same subject.

http://stackoverflow.com/questions/200574/linq-equivalent-of-foreach-for-ienumerablet

http://stackoverflow.com/questions/858978/lambda-expression-using-foreach-clause

In my opinion, I would stick with ‘foreach’ instead of ‘ForEach’.

If I would need to get fancy and show off, I would write the extension rather than ‘.ToList()’.ForEach’. When you perform, ToList, it creates the copy of the object before send it to ForEach.

Out of curiosity, I wrote a small unit test code to test the performance of the three flavors. It turned out, traditional ‘foreach’ have a very thin lead in the process. Here is what the program does, I have a person model as follows; what we are trying to do is remove all the children from all the parent which have any children in them. For simplicity, we assume there is only two levels.

public class Person
{
   public string Name { get; set; }
   public int Age { get; set; }
   public List<Person> Children { get; set; }
   public Person()
   {
       Children = new List<Person>();
   }
}

I have a class library which does all three different flavor of for each

public class LinqTesting
{
   public List<Person> SourceList;
   public List<Person> TargetList;
   public void RemoveChildrenWithLinq()
   {            
       SourceList.Where(p => p.Children.Count() > 0).ToList().ForEach(p => p.Children.Clear());
   }
   public void RemoveChildrenWithForEach()
   {
       foreach (var item in SourceList.Where(p=>p.Children.Count() > 0))
       {
           item.Children.Clear();
       }
   }
   public void RemoveChildrenWithLinqExtension()
   {
       SourceList.Where(p => p.Children.Count() > 0).ForEach(p => p.Children.Clear());
   }
}

We load the data as follows

private List<Person> LoadSourceData()
{
     List<Person> ppl = new List<Person>();
     for (int i = 0; i < 1000; i++)
     {
         Person singlePerson = new Person() { Name = string.Format("Parent {0}", i), Age = i + 10 };
         if (i % 3 == 0)
         {
             for (int j = 0; j < 5000; j++)
                 singlePerson.Children.Add(new Person() { Name = string.Format("Child {0}", j), Age = j + 10 });
         }
         ppl.Add(singlePerson);
     }
     return ppl;
 }

The tree test methods are

[TestMethod]
public void TestMethodWithLinq()
{
    start = DateTime.Now;
    tester.RemoveChildrenWithLinq();
    end = DateTime.Now;
    PerformCommonAssert();
}

[TestMethod]
public void TestwithForEach()
{
   start = DateTime.Now;
   tester.RemoveChildrenWithForEach();
   end = DateTime.Now;
   PerformCommonAssert();
}

[TestMethod]
public void TestwithExtensions()
{
   start = DateTime.Now;
   tester.RemoveChildrenWithLinqExtension();
    end = DateTime.Now;
   PerformCommonAssert();
}

And the result is

0:0:4 (m:s:ms)

0:0:3 (m:s:ms)

0:0:4 (m:s:ms)

3 passed, 0 failed, 0 skipped, took 7.44 seconds (MSTest 10.0).

With the above set of input, both Linq and Linq extenstion method took 4ms, while the traditional for each only took 3ms. With 1ms better, traditional ‘foreach’ is the better way to do it. Not only that, the code is very easy to understand and easy to maintain.

If anyone have different opinion or suggestions, please let me know.

Creating Treeview using DataGrid – (Component One)

In my previous posts I have explained how you can create TreeView look and feel in DataGrid using Cell Factory in Component One C1FlexGrid.  In that blog, I also mentioned it is round about way of doing it and there is a better way to do it. In this blog, we will look at the correct way to create TreeView look and feel in DataGrid. Before we go there, why are we attempting to create tree view in data grid? There are couple of reasons for that;

1. If your collection is large and each node have large number of children underneath it. Tree view takes time to load the children in memory when you expand for the first time. Because of that, if you have lot of nodes with lot of children under the nodes, your performance will suffer so switch to Data Grid which enjoys full virtualization. Since it has full virtualization expand and collapse in Data Grid is fast.

2. If you would like to get multi column look and feel with column heading.

Lets jump into the example, Here is what we are trying to achieve

image

We would like to get a tree view look with first column a check box and second column the description of the mode. In the above screen shot you can see, it looks like tree view with expand and collapse icons and also with proper indentation when expanded.

 

First look at the model; Nothing special here, it has IsChecked boolean which is the first column in our display and SourceDescription is the second column in the grid. In this example I defined children as observable collection. If you have large number of children under each node, I would recommend you to read this blog on when to use Observable collection and when not to use it.

public class Person:INotifyPropertyChanged
{
    public string ID { get; set; }
    public string Name { get; set; }
    public bool IsChecked { get; set; }
    public ObservableCollection<Person> Children { get; set; }
    public Person()
    {
        Children = new ObservableCollection<Person>();
        IsChecked = false;
    }

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

Lets load the data

private void LoadPeople()
{
     _people = new List<Person>();
     for (int i = 0; i < 10; i++)
     {
         Person ppl= new Person() { ID = i.ToString(), Name = string.Format("Parent{0}",i.ToString()), IsChecked = false };
         if (i % 3 == 0)
         {
             for (int j = 0; j < 1000; j++)
             {
                 Person child = new Person() { ID = j.ToString(), Name = string.Format("Child{0}", j.ToString()) };
                 ppl.Children.Add(child);
             }
         }
        _people.Add(ppl);
     }
 }

Now lets look at the XAML

<c1:C1FlexGrid x:Name="_flex" HeadersVisibility="None" AutoGenerateColumns="False" ChildItemsPath="Children">
     <c1:C1FlexGrid.Columns>
         <c1:Column Binding="{Binding IsChecked, Mode=TwoWay}"/>
         <c1:Column Binding="{Binding Name}"/>
     </c1:C1FlexGrid.Columns>
</c1:C1FlexGrid>

As simple as that, only thing new in here is ‘ChildItemsPath’. It is the new property added to C1FlexGrid to mimic the tree view look and feel. So this big blog is all about this property.With this property, you do not require the different classes and all crazy event mechanisms.

If you do not want to have multiple columns like the one I did and want to have true one column look, use cell template to stack the items in one column and you will get the exact tree view.

By default, when you use the grid like this, it will put column and row header around the control to make it show as grid. To turn off the grid controls around it, make sure to use HeaderVisibility=”None”

 

Observable Collection, second look.

Observable Collection by definition provide notification when an item is added, removed or refreshed. It is pretty cool nifty item to have. So if you want a type of collection that automatically notifies the UI to update when underlying data changes, it has to be Observable Collection. Less code, more feature out of the box. But I want to point out two things when using Observable Collection.

Most of the people forget the very import thing, if you are using Observable collection then for every change, Observable Collection fires an event. If it is very small numbers then you will not notice the performance issue. But if for some reason you are adding and/or removing 100s or 1000s of rows then you will see visible performance degradation. If your data is flat or if it does not have a collection inside the collection then there should not be any performance hit either. I wrote a sample code to time it so that I  can document the performance issue if any.

Before we go into the example, I would like to point out the second issue of Memory Leak when using Observable Collection. Once you initialize a bound observable collection, do not new up again, rather, clear the collection and then add new items to the same collection. You can read about it in here and also here.

Now lets look at the performance timings.

Scenario 1: Simple observable collection class.

My backend data model is PERSON class

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Now the XAML

<Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="80"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid HorizontalAlignment="Center">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Button Name="Add" Content="Add" Click="Add_Click" Grid.Column="0" HorizontalAlignment="Center" Margin="4,4,4,4"/>
            <Button Name="Clear" Content="Clear" Click="Clear_Click" Grid.Column="1" HorizontalAlignment="Center" Margin="4,4,4,4"/>
            <TextBox Name="Numbers" Grid.Column="2" Width="100"/>
        </Grid>
        <c1:C1FlexGrid Name="_grid" Grid.Row="1" />
    </Grid>

The top part has two buttons, one to add rows and another one to remove rows from the collection. The third is a textbox, where you can enter how many rows you want to add or remove. What we are currently interested in is, adding rows to the grid on the fly.

private void Add_Click(object sender, RoutedEventArgs e)
{
     DateTime dt = DateTime.Now;
     for(int i=0;i<int.Parse(Numbers.Text);i++)
        _people.Add(new Person() { Age = i + 10, Name = "Name" + i.ToString() });
     DateTime dt1 = DateTime.Now;
     TimeSpan dt2 = dt1.Subtract(dt);
      Debug.WriteLine(string.Format("{0}:{1}:{2}:{3}", dt2.Hours, dt2.Minutes, dt2.Seconds, dt2.Milliseconds));
}

Armed with above code and XAML if you would run, the time it takes to add 1000 new object to the collection is 107ms. Not bad, no performance hit.

Scenario 2: Hierarchical Collection using Observable Collection.

We modify the Person Class as follows to include a children of same type.

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public ObservableCollection<Person> Children { get; set; }
    public Person()
    {
       Children = new ObservableCollection<Person>();
    }
}

With this change, if you would run the same code, it takes 10.263s. You can see why the time jumped by 10 seconds, if I would remove the constructor from the code, it still comes down to 9.623ms. So the constructor is not the problem here.Lets move on to the third scenario.

Scenario 3: Hierarchical Collection using Custom Class derived off of Observable collection.

This is an interesting scenario that I did not think about it till I ran into a performance issue with grid. The idea behind this scenario is that, since by definition, Observable Collection fires an event notification for any change to the data, in our case, when we are adding a bunch of data, we do not want to fire event for each and individual change rather, fire an event at the end of all the changes are made. So the solution is to derive a new class off of Observable Collection and make sure you turn off the notification before adding range and at the end turn the notification on. I followed the Smart Collection explained in Daamir blog. Just in case, I added the class definition right here as well.

    public class SmartCollection<T> : ObservableCollection<T>
    {
        public SmartCollection()
            : base()
        {
            _suspendCollectionChangeNotification = false;
        }


        public SmartCollection(List<T> list) : base(list) { }


        bool _suspendCollectionChangeNotification;

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (!_suspendCollectionChangeNotification)
            {
                base.OnCollectionChanged(e);
            }
        }

        public void SuspendCollectionChangeNotification()
        {
            _suspendCollectionChangeNotification = true;
        }

        public void ResumeCollectionChangeNotification()
        {
            _suspendCollectionChangeNotification = false;
        }


        public void AddRange(IEnumerable<T> items)
        {
            this.SuspendCollectionChangeNotification();
            int index = base.Count;
            try
            {
                foreach (var i in items)
                {
                    base.InsertItem(base.Count, i);
                }
            }
            finally
            {
                this.ResumeCollectionChangeNotification();
                var arg = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                this.OnCollectionChanged(arg);
            }
        }

        public void Repopulate(IEnumerable<T> items)
        {
            this.Clear();
            this.AddRange(items);
        }
    }

If you look at the code, three piece of information interesting to current article. SuspendCollectionChangeNotification, which is to turn off the notification and ResumeCollectionChangeNotification to turn on the notification. These two methods need to be invoked if you are adding one row at a time through your code. On the other hand, if you are adding a collection to the Observable Collection, then call AddRange method, which internally will take care of turning on and off the notification. Now lets look at the code change

public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public SmartCollection<Person> Children { get; set; }
        public Person()
        {
            Children = new SmartCollection<Person>();
        }
    }

Modify the code bind and change all Observable Collection Reference to SmartCollection. Also change the for loop where we add individual items to SmartCollection to List as follows

private void Add_Click(object sender, RoutedEventArgs e)
        {
            DateTime dt = DateTime.Now;
            Debug.WriteLine(string.Format("{0}:{1}:{2}:{3}", dt.Hour, dt.Minute, dt.Second, dt.Millisecond));

            List<Person> ppl = new List<Person>();
            for(int i=0;i<int.Parse(Numbers.Text);i++)
                ppl.Add(new Person() { Age = i + 10, Name = "Name" + i.ToString() });
            _people.AddRange(ppl);

            DateTime dt1 = DateTime.Now;
            TimeSpan dt2 = dt1.Subtract(dt);
            Debug.WriteLine(string.Format("{0}:{1}:{2}:{3}", dt2.Hours, dt2.Minutes, dt2.Seconds, dt2.Milliseconds));
        }

With these changes if you would run the program, you will see the 1000 row insertion only took 31ms.  Now the question is, why can’t we do the step as creating temporary collection and then assign it back to observable collection? Wouldn’t it work the same way? One approach would be

var concatList = _people.Concat(pp);

_people = new ObservableCollection(concatList)

in my opinion, newing Observable collection had some memory problem in Silverlight. The recommendation was always new up only once and from there on, if you want to add items to it, you add item to it or clear and then add item to it. That is the only reason I did not try it out.

So the bottom line is that, when we use Observable Collection take care not to fire event when you are working on too large of data. As I mentioned earlier, if your data is flat then you will not incur any performance problems but if you have hierarchical data then I would recommend you to switch to a model to turn on and off the notification model.

If any of you have good way to do it, please feel free to drop me a note. I am very much interested in learning and understand new ways of doing things.

Creating TreeView using Grid in Silverlight (Component One – Cell Factory) – III

[Component one already have a new attribute in C1FlexGrid ‘ ChildItemsPath=”Children” which will create the tree view look and feel without any of this custom cell factory. I did it anyway as a means to learn]

In the previous blog post, we took our first step in creating tree view look and feel using C1FlexGrid. With some basic changes we were able to get to the result close enough.

image

Few things missing for the grid to look like tree view, they are

1. When parent do not have a child, the expand and collapse icon should not appear.

2. We are missing check box along with parent id.

We can resolve both the problems using Cell Factory.  What does cell factory do? Cell Factory is used by C1FlexGrid to draw cells. It has bunch of methods that you can override so that you can implement your own drawing mechanism. In our case, when it create the cell content, I need to check if the content is a group row, then add my own cell creating logic put check box else let the grid do its work. So we create our custom class off of CellFactory. All the code you are going to see below is stripped down version of Component One’s iTune sample code.

public class MyCellFactory:CellFactory
{
}

The method we need to override to achieve custom cell content create is ‘CreateCellContent’ method. In this method, we will check, if the cell belongs to a group row and if it is first column then create me the custom cell.

static Thickness _emptyThickness = new Thickness(0);

//bind a cell to a range
 public override void CreateCellContent(C1FlexGrid grid, Border bdr, CellRange range)
{
     var row = grid.Rows[range.Row];
     var col = grid.Columns[range.Column];
      var gr = row as GroupRow;

      if (gr != null)
          bdr.BorderThickness = _emptyThickness;

      if (gr != null && range.Column == 0)
     {
          BindGroupRowCell(grid, bdr, range);
          return;
      }
      base.CreateCellContent(grid, bdr, range);
}


One point of interest in the above method call is ‘BindGroupRowCell’. This method will create the custom cell for us. This has two important parts in it, first one is to make sure the group row has a databinding source and also create custom cell and add it to its cell content.

private void BindGroupRowCell(C1FlexGrid grid, Border bdr, CellRange range)
{
     var row = grid.Rows[range.Row];
     var gr = row as GroupRow;

     if (range.Column == 0)
     {
          if (gr.DataItem == null)
         {
              gr.DataItem = BuildGroupDataItem(gr);
         }

        Type cellType = typeof(ParentCell);
        bdr.Child = (ImageCell)new ParentCell(row);

     }
}

In our grid, every row has an associated data row except the group row. Since group row does not have data item, we will, create an temporary data row, that we can use to bind it to the grid. When we group the rows to generate the grouping in data grid, the group knows about all the children of the group. We conveniently pick the first row and use the data to generate the dummy row that we use to bind it to group row.

CustomCellFactoryForTreeView.MainPage.Person BuildGroupDataItem(GroupRow gr)
{
     var gs = gr.GetDataItems().OfType<CustomCellFactoryForTreeView.MainPage.Person>();
     CustomCellFactoryForTreeView.MainPage.Person p = new CustomCellFactoryForTreeView.MainPage.Person();
      if (gs != null && gs.Count() > 0)
            p = gs.ElementAt(0) as CustomCellFactoryForTreeView.MainPage.Person;
       return new CustomCellFactoryForTreeView.MainPage.Person()
      {
            ParentID = p.ParentID,
            Description = p.Description,
            ChildID = p.ChildID,
            ChildDescription = p.ChildDescription
       };
 }

Now lets look at the main core functionality to  create the check box and text in the group row. Again following code is purely stripped down version itunes sample in C1 samples.  Lets first create the ParentCell

    public  class ParentCell : ImageCell
    {
        const double ALPHA = 0.5;
        GroupRow _gr;
        Image _nodeImage;
        static ImageSource _bmpExpanded, _bmpCollapsed;

        public ParentCell(Row row)
            : base(row)
        {
            CustomCellFactoryForTreeView.MainPage.Person per = row.DataItem as CustomCellFactoryForTreeView.MainPage.Person;
            if (per != null && per.ChildID != null)
            {
                // create collapsed/expanded images
                if (_bmpExpanded == null)
                {
                    _bmpExpanded = ImageCell.GetImageSource("Expanded.png");
                    _bmpCollapsed = ImageCell.GetImageSource("Collapsed.png");
                }

                // store reference to row
                _gr = row as GroupRow;

                // initialize collapsed/expanded image
                _nodeImage = new Image();
                _nodeImage.Source = _gr.IsCollapsed ? _bmpCollapsed : _bmpExpanded;
                _nodeImage.Width = _nodeImage.Height = 9;
                _nodeImage.VerticalAlignment = VerticalAlignment.Center;
                _nodeImage.Stretch = Stretch.None;
                _nodeImage.MouseLeftButtonDown += img_MouseLeftButtonDown;
                _nodeImage.MouseEnter += img_MouseEnter;
                _nodeImage.MouseLeave += img_MouseLeave;
                _nodeImage.Opacity = ALPHA;
                Children.Insert(0, _nodeImage);
            }
            // make text bold
            TextBlock.FontWeight = FontWeights.Bold;
        }
        void img_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var img = sender as Image;
            var cell = img.Parent as NodeCell;
            cell.IsCollapsed = !cell.IsCollapsed;
        }
        void img_MouseEnter(object sender, MouseEventArgs e)
        {
            var img = sender as Image;
            img.Opacity = 1;
        }
        void img_MouseLeave(object sender, MouseEventArgs e)
        {
            var img = sender as Image;
            img.Opacity = ALPHA;
        }
        public override Row Row
        {
            set
            {
                // update image
                _gr = value as GroupRow;
                _nodeImage.Source = _gr.IsCollapsed ? _bmpCollapsed : _bmpExpanded;
                _nodeImage.Opacity = ALPHA;

                // update text
                base.Row = value;
            }
        }
        public bool IsCollapsed
        {
            get { return _gr.IsCollapsed; }
            set
            {
                _gr.IsCollapsed = value;
                _nodeImage.Source = value ? _bmpCollapsed : _bmpExpanded;
            }
        }
    }

The point of interest in here is the constructor, where we check if there are any children available. If there is any child available, then we show expand or collapse icon. If there are no children then do not show any icon. We also add event handler which listens to the click event on the image and based on the event, it toggles the state. With this change, we took care the icon to show only when there is children. One thing left to do is, adding check box to the control. This is accomplished at base class ‘ImageCell’.

The Image cell is derived from StackPanel so it is easy to customize it to the look you want.

    public abstract class ImageCell:StackPanel
    {
        public ImageCell(Row row)
        {
            Orientation = System.Windows.Controls.Orientation.Horizontal;

            CheckBox box = new CheckBox();
            box.VerticalAlignment = System.Windows.VerticalAlignment.Center;
            box.Click += new RoutedEventHandler(box_Click);
            Children.Add(box);

            TextBlock tb = new TextBlock();
            tb.VerticalAlignment = System.Windows.VerticalAlignment.Center;
            Children.Add(tb);

            BindCell(row.DataItem);
        }

        void box_Click(object sender, RoutedEventArgs e)
        {
            int k = 0;
        }

        public TextBlock TextBlock
        {
            get { return Children[Children.Count - 1] as TextBlock; }
        }

        public CheckBox CheckBox
        {
            get
            {
                return Children[Children.Count - 2] as CheckBox;
            }
        }

        public virtual Row Row
        {
            set { BindCell(value.DataItem); }
        }

        private void BindCell(object dataItem)
        {
            var binding = new Binding("Description");
            binding.Source = dataItem;
            TextBlock.SetBinding(TextBlock.TextProperty, binding);
            var cbbinding = new Binding("TwoState");
            cbbinding.Source = dataItem;
            CheckBox.SetBinding(CheckBox.IsCheckedProperty, cbbinding);
        }

        public static ImageSource GetImageSource(string imageName)
        {
            var bmp = new BitmapImage();
            bmp.CreateOptions = BitmapCreateOptions.None;
            var fmt = "Resources/{0}";
            bmp.UriSource = new Uri(string.Format(fmt, imageName), UriKind.Relative);
            return bmp;
        }
    }

The final result of course is like the following

image

Our requirement is to have a check box and a text block in the group row and that is what we did in the constructor of the ImageCell. Once it is created we need to bind it to the proper fields. That’s is what done in the BindCell method. One thing, it is important here on how you get to the control for doing the binding. Please see the TextBlock getter property, which in turn take the first child from the children collection and return it for binding. If you remember the children have three elements and they are in the following order. First element (at 0) is image for collapse and expand. Second one is the check box (at 1) and third one is the TextBlock (at 2). I was so lazy to I hard coded it to get the elements by hard coded index. You can traverse and identify the control to make it flexible if you want to move around the control. One another thing, you may want is to listen to the check box click event that you can listen with click event.

I would like to thank Bernardo @ Component One to take time to answer my questions and excellent example of itunes on their web site. This three part blog was more for me to understand how the whole components works together and what you can do with this. You can customize the grid any way you want. In this whole example we looked at only one method, create cell, but there are five or six more methods available completely change the look of the grid.