微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Creating a simple Pivot table using LINQ and Telerik RadTreeView for Silverlight

This article is compatible with the latest version of Silverlight.


What is a Pivot table/grid? According to Wikipedia it is a data summarization tool found in spreadsheet applications. Still when I was a child I learned that people understand the best when they see an example.

Consider you have a table that contains the nutrition of given food,say a pizza:

Group Name Quantity
Carbohydrates Total carbohydrates 27.3
Carbohydrates Total disaccharides 5.7
Carbohydrates Total polysaccharides 21.6
minerals Calcium 147
minerals Phosphorus 150
minerals Potassium 201
minerals copper 0.13
minerals Magnesium 19
minerals sodium 582
minerals Selenium 4
minerals Total iron 0.7
minerals Zinc 1.07
Vitamins Beta-carotene 173.8
Vitamins Nicotinic 1.5
Vitamins Total vitamin B6 0.127
Vitamins Total vitamin D 0.3
Vitamins Total vitamin E 2.1
Vitamins Vitamin B1 0.1
Vitamins Vitamin B12 0.59
Vitamins Vitamin B2 0.16
Vitamins Vitamin C 10

In the data above you see that every nutrition is contained in a specific Group - 3 groups and 21 nutrition in total. To display the nutrition in a more meaningful way in most cases you need to group the nutrition (rows in the general case) by their Group attribute and display them in columns instead of in rows. Now we are closer to what we call a Pivot table - group and turn rows into columns.

So the above table displayed in a Pivot would look like that:

Carbohydrates   minerals   Vitamins  
Total carbohydrates 27.3 Calcium 147 Beta-carotene 173.8
Total disaccharides 5.7 Phosphorus 150 Nicotinic 1.5
Total polysaccharides 21.6 Potassium 201 Total vitamin B6 0.127
    copper 0.13 Total vitamin D 0.3
    Magnesium 19 Total vitamin E 2.1
    sodium 582 Vitamin B1 0.1
    Selenium 4 Vitamin B12 0.59
    Total iron 0.7 Vitamin B2 0.16
    Zinc 1.07 Vitamin C 10

I searched for a 3rd party control that can help me achieve this goal out of the Box,but I Couldn't find one. Looking for a way to do it I finally made it work with the help of LINQ - for grouping and the Telerik RadTreeView for Silverlight - for displaying.

Loading the data with LINQ

First,consider we have the initial table of nutrition exported to XML. The output look like that:


    
    
<?xmlversion="1.0"encoding="utf-8"?><Nutritions>    <NutritionGroup="Carbohydrates"Name="Total carbohydrates"Quantity="27.3"></Nutrition>    <NutritionGroup="Carbohydrates"Name="Total disaccharides"Quantity="5.7"></Nutrition>    <NutritionGroup="Carbohydrates"Name="Total polysaccharides"Quantity="21.6"></Nutrition>    <NutritionGroup="minerals"Name="Calcium"Quantity="147"></Nutrition>    <NutritionGroup="minerals"Name="Phosphorus "Quantity="150"></Nutrition>

Create a business object Nutrition that will be used later when loading the XML with LINQ.


    
    
publicclassNutrition{    publicstringGroup {get;set; }    publicstringName {get;set; }    publicstringQuantity {get;set; }}

and NutritionGroup:

 public class NutritionGroup
 {
    public string NutritionGroupHeader { getset; }
    public Collection<Nutrition> Nutritions { getset; }
 }

Now,it's time to load the XML document with LINQ. Martin Mihaylov published a great article on using LINQ to XML in Silverlight so if you are not familiar you'd better go read it first.


    
    

List data = ( from nutritioninnutritionsDoc.Descendants("Nutrition")            selectnewNutrition            {                Group = nutrition.Attribute("Group").Value,                Name = nutrition.Attribute("Name").Value,                Quantity = nutrition.Attribute("Quantity").Value            } ).ToList();

Grouping the data with LINQ and building the tree

Ok,this is the core of this article. The ability to group is a great feature in LINQ. It really does simplify the code to minimum.

We need to group by the Group attribute.

 IEnumerable<string,Nutrition>> query = data.GroupBy( nutrition => nutrition.Group );

Now,each nutrition group should be a root node in the tree and each nutrition in this group should be added to the nutritions in the corresponding root. When the ItemSource property is set to the collection of nutrition groups,the RadTreeView will be populated with the corresponding data:


    
    
 
 
 
 
Collection<NutritionGroup> nutritions =newCollection<NutritionGroup>();foreach( IGrouping<string,Nutrition> nutritionGroupinquery ){    NutritionGroup group =newNutritionGroup()    {        NutritionGroupHeader = nutritionGroup.Key,    };    group.Nutritions =newCollection<Nutrition>();    foreach( Nutrition nutritioninnutritionGroup )    {        group.Nutritions.Add( nutrition );    }    nutritions.Add( group );}nutritionTree.ItemsSource = nutritions;

Ok,we are almost over. Let's take a look at the NutritionGroupTemplate and NutritionTemplate that we will use. First,we will need the following schema:

Having that,follows both the templates:

NutritionGroupTemplate


     
     
<telerik:HierarchicalDataTemplatex:Key="NutritionGroupTemplate"          ItemsSource="{Binding Nutritions}"ItemTemplate="{StaticResource NutritionTemplate}">    <BorderBorderThickness="1"BorderBrush="#ececec"CornerRadius="4">        <BorderBorderThickness="1"BorderBrush="White"Padding="1"CornerRadius="4">            <Border.Background>                <LinearGradientBrushEndPoint="0.5,1"StartPoint="0.5,0">                    <GradientStopColor="#f8f8f8"/>                    <GradientStopColor="#ececec"Offset="1"/>                </LinearGradientBrush>            </Border.Background>            <TextBlockText="{Binding NutritionGroupHeader}"FontWeight="Bold"/>        </Border>    </Border></telerik:HierarchicalDataTemplate>

NutritionTemplate


   
   
<telerik:HierarchicalDataTemplatex:Key="NutritionTemplate">    <StackPanelOrientation="Horizontal">        <TextBlockText="{Binding Name}"Width="150"></TextBlock>        <TextBlockText="{Binding Quantity}"FontWeight="Bold"></TextBlock>    </StackPanel></telerik:HierarchicalDataTemplate>

The default orientation of the nodes in the RadTreeView,as expected,is vertical. However in our case it makes more sense to arrange the root nodes on the horizontal and only the child elements to the vertical:


     
     
<Styletargettype="telerik:RadTreeViewItem"x:Key="TreeViewItemStyle">    <SetterProperty="IsExpanded"Value="True"></Setter>    <SetterProperty="ItemsPanel">        <Setter.Value>            <ItemsPanelTemplate>                <StackPanelHorizontalAlignment="Center"                            Margin="4,6"Orientation="Vertical"/>            </ItemsPanelTemplate>        </Setter.Value>    </Setter></Style>

And the RadTreeView element:

<telerik:RadTreeView x:Name="nutritionTree"
                     ItemTemplate="{StaticResource NutritionGroupTemplate}"
                     ItemContainerStyle="{StaticResource TreeViewItemStyle}">
    <telerik:RadTreeView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel VerticalAlignment="Top" Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </telerik:RadTreeView.ItemsPanel>
</telerik:RadTreeView>
http://www.silverlightshow.net/items/Creating-a-simple-Pivot-table-using-LINQ-and-RadTreeView-for-Silverlight.aspx
文章转载from:

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐