Sharker Khaleed Mahmud Silverlight Tips & Tricks

August 8, 2010

81. Deeply nested Path Binding using ItemsControl in Silverlight

Filed under: Silverlight — Tags: , , — Sharker Khaleed Mahmud | shamrat231 @ 9:30 AM

 [tweetmeme source=”shamrat231” only_single=false]

The idea is very simple. Lets say you received a lots of data from your BLL and the object that is returned to you is not…say simple format. By simple format, I mean that it is not easily bindable to the datagrid but most of the value that you need is nested deeper than the first layer of that object. 

You can see the live example here [live demo]   

The SOURCE CODE(.zip) is at the end of the page for download.   

In other words the object returned in not as simple as for say…

eg. Person class
        public class Person
        {
            public int Id { get; set; }
            public string Title { get; set; }
        } 

So now you can do two things to the returned object.
1. Iterate at every level and create a collection like Person class that can easily bindable to DataGrid or…
2. Bind the object as it has been returned to Datagrid and display the information that you required in DataGrid by implementing deep nested path binding 

In this entry, I will show you how to achieve the second option without doing any kind of data manipulation from managed code to get the desired output. So for now lets start by building a scenario and then work on it to create a object. Suppose a survey has been done for ABC company on their customer and asked about what type of products they have at their home. So basically the survey is being done for say three kinds of product, Wood, Steel and Plastic (took three eg. from top of my head :). So lets create a simple data structure. 

Data.cs 

public class Data
    {
        public int CustomerId { get; set; }
        public object Wood { get; set; }
        public object Steel { get; set; }
        public object Plastic { get; set; }
    } 

Ok, now say on the survey , customer gave some response say wooden spoon, pencil when asked about materials they have used related to wood. At the moment, I have a public object Wood { get; set; }. So from the customer answer, I can say that, that their could be multiple response to a particular category. So lets create a object say WoodType having a List<T> for multiple responses. 

    public class WoodType
    {
        public List<Item> Items { get; set; }
    } 

Where say for each item I am keeping record of the title and pulling an image related to the product. 

    public class Item
    {
        public string Title { get; set; }
        public BitmapImage Img { get; set; }
    } 

Now, the changed data structure of the class would be

    public class Data
    {
        public int CustomerId { get; set; }
        public WoodType Wood { get; set; }
        public SteelType Steel { get; set; }
        public PlasticType Plastic { get; set; }
    } 

 

Notice, that I am actually creating a complicated object for demonstration purpose. In reality, the data structure could differ in many variations. Ok, so we are done with a simple data structure where the title is not in first layer of the object. Now I will add some feedback data and create a collection, something like this
List<Data> entries = new List<Data>();
entries.Add(..) 

Anyway, look at the class below. 

    public class FeedBackData
    {
        public static System.Collections.IEnumerable GetCustomerFeedBack()
        {
            List<Data> entries = new List<Data>(); 

            //demonstration purpose…ideally it should follow MVVM structure
            //Customer 1
            entries.Add(new Data
            {
                CustomerId = 1,
                Wood = new WoodType
                {
                    Items = new List<Item> {
                    new Item { Title = “Pencil” , Img = new BitmapImage(new Uri(“Images/Wood/WoodenPencil.png”,UriKind.Relative)) },
                    new Item { Title = “Wooden Spoon” , Img = new BitmapImage(new Uri(“Images/Wood/WoodenSpoon.png”,UriKind.Relative))}}
                },
                Steel = new SteelType
                {
                    Items = new List<Item> {
                    new Item { Title = “Sword”, Img = new BitmapImage(new Uri(“Images/Steel/Sword.jpg”,UriKind.Relative)) },
                    new Item { Title = “Lock”, Img = new BitmapImage(new Uri(“Images/Steel/lock.png”,UriKind.Relative)) },
                    new Item { Title = “Key”, Img = new BitmapImage(new Uri(“Images/Steel/key.png”,UriKind.Relative))}}
                },
                Plastic = new PlasticType
                {
                    Items = new List<Item> {
                    new Item { Title = “Plastic Bag”, Img = new BitmapImage(new Uri(“Images/Plastic/plasticBag.png”,UriKind.Relative))},
                }
                }
            }); 

            //Customer 2
     // reapeat above….
            return entries;
        }
    } 

If you look at the above screen shot, you will see that at one level we have CustomerId and at more deeper level we have the Title and an image related to it. So we initially set out to create a complicated object to bind and at this moment we have done it. In other words, the data return is not as simple as a person class.

Now, how do we represent this two sets of data at different level in the object?. For this entry, I am going to show using Datagrid and ItemsControl. Similarly, various other ways can be used to achieve the same output in Silverlight.

We do know that the main Data.cs has a property CustomerId, so this can easily be achieved if we add a DataGridTextColumn, some thing like this

But for the rest, we have to use templateColumn. So lets, break the scenario, at the moment, we are getting a list of customer feedback. Those are the rows. Now we know that for each row, it is returning this

 

Ok, using the above scenario lets create a sample DataTemplate. In the above DataTemplate, we know that in the grid for each row it will return a list of Items. So add a ItemsControl and set the ItemSource like this. 

<ItemsControl Margin=”10″ ItemsSource=”{Binding Plastic.Items}”> 

So, now we now that for each Item in ItemsControl we have a Item having Title and Image. So lets bind the Titel in the ItemTemplate for the ItemsControl.  Look at the code below. 

<data:DataGridTemplateColumn Header=”Plastic”>
                        <data:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ItemsControl Margin=”10″ ItemsSource=”{Binding Plastic.Items}”>
                                    <ItemsControl.Template>
                                        <ControlTemplate TargetType=”ItemsControl”>
                                            <ItemsPresenter/>
                                        </ControlTemplate>
                                    </ItemsControl.Template>
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <StackPanel Orientation=”Vertical”/>
                                        </ItemsPanelTemplate>
                                    </ItemsControl.ItemsPanel>
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <TextBlock Margin=”3,3,3,0″ FontSize=”12″ HorizontalAlignment=”Center” Text=”{Binding Path=Title}”/>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                            </DataTemplate>
                        </data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn> 

So basically this will follow for the rest product type. If we now bind our datagrid to the object, It will return as shown below. 

Notice, that if a customer has multiple answers, it will show below, but on the same row. You can change the order by changing the orientation of ItemPanelTemplate.

<ItemsPanelTemplate>
 <StackPanel Orientation=”Vertical”/>
</ItemsPanelTemplate>

Well, the hard path is done, Now we need to modify ItemTemplate

<ItemsControl.ItemTemplate>
 <DataTemplate>
 <StackPanel>
  <Image Source=”{Binding Img}” Height=”100″ />
  <TextBlock Margin=”3,3,3,0″ FontSize=”12″ HorizontalAlignment=”Center” Text=”{Binding Path=Title}” TextAlignment=”Center”/>
 </StackPanel>
 </DataTemplate>
</ItemsControl.ItemTemplate>

The final .xaml is this

<data:DataGrid AutoGenerateColumns=”False” Margin=”10″ Name=”dg” VerticalAlignment=”Top”>
                <data:DataGrid.Columns>
                    <data:DataGridTextColumn Header=”CustomerId” Binding=”{Binding CustomerId}” />
                    <data:DataGridTemplateColumn Header=”Plastic”>
                        <data:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ItemsControl Margin=”10″ ItemsSource=”{Binding Plastic.Items}”>
                                    <ItemsControl.Template>
                                        <ControlTemplate TargetType=”ItemsControl”>
                                            <ItemsPresenter/>
                                        </ControlTemplate>
                                    </ItemsControl.Template>
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <StackPanel Orientation=”Vertical”/>
                                        </ItemsPanelTemplate>
                                    </ItemsControl.ItemsPanel>
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <StackPanel>
                                                <Image Source=”{Binding Img}” Height=”100″ />
                                                <TextBlock Margin=”3,3,3,0″ FontSize=”12″ HorizontalAlignment=”Center” Text=”{Binding Path=Title}” TextAlignment=”Center”/>
                                            </StackPanel>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                            </DataTemplate>
                        </data:DataGridTemplateColumn.CellTemplate>
                    </data:DataGridTemplateColumn>
                    <data:DataGridTemplateColumn Header=”Wood”>
                        <data:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ItemsControl Margin=”10″ ItemsSource=”{Binding Wood.Items}”>
                                    <ItemsControl.Template>
                                        <ControlTemplate TargetType=”ItemsControl”>
                                            <ItemsPresenter/>
                                        </ControlTemplate>
                                    </ItemsControl.Template>
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <StackPanel Orientation=”Vertical”/>
                                        </ItemsPanelTemplate>
                                    </ItemsControl.ItemsPanel>
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <StackPanel>
                                                <Image Source=”{Binding Img}” Height=”100″ />
                                                <TextBlock Margin=”3,3,3,0″ FontSize=”12″ HorizontalAlignment=”Center” Text=”{Binding Path=Title}” TextAlignment=”Center”/>
                                            </StackPanel>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                            </DataTemplate>
                        </data:DataGridTemplateColumn.CellTemplate>
                    </data:DataGridTemplateColumn>
                    <data:DataGridTemplateColumn Header=”Steel”>
                        <data:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ItemsControl Margin=”10″ ItemsSource=”{Binding Steel.Items}”>
                                    <ItemsControl.Template>
                                        <ControlTemplate TargetType=”ItemsControl”>
                                            <ItemsPresenter/>
                                        </ControlTemplate>
                                    </ItemsControl.Template>
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <StackPanel Orientation=”Vertical”/>
                                        </ItemsPanelTemplate>
                                    </ItemsControl.ItemsPanel>
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <StackPanel>
                                                <Image Source=”{Binding Img}” Height=”100″ />
                                                <TextBlock Margin=”3,3,3,0″ FontSize=”12″ HorizontalAlignment=”Center” Text=”{Binding Path=Title}” TextAlignment=”Center”/>
                                            </StackPanel>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                            </DataTemplate>
                        </data:DataGridTemplateColumn.CellTemplate>
                    </data:DataGridTemplateColumn>
                </data:DataGrid.Columns>
            </data:DataGrid>

As always, you can download the source code from here [download link]   

Sharker Khaleed Mahmud
Web Developer

2 Comments »

  1. […] Deeply nested path binding using ItemsControl in Silverlight (Sharker Khaleed Mahmud) […]

    Pingback by Windows Client Developer Roundup 036 for 8/9/2010 - Pete Brown's 10rem.net — August 9, 2010 @ 11:01 PM

  2. Dear Sharker,

    Just a clarification …
    If I have a VM that have let’s say Item (of type entity) and sheetlist (of type enumerable), if I bound the grid in xaml to item then the nested bombobox in the grid will have no access to the sheetlist … is this correct (also they both have access to VM)…

    How can this be solved
    Appreciate your answer
    Waleed

    Comment by Waleed — February 19, 2011 @ 11:04 AM


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.