Showing heterogenous data in RadTreeListView

Thread is closed for posting
1 posts, 1 answers
  1. Answer
    FCB826E1-16E1-4099-9158-481548C7C067
    FCB826E1-16E1-4099-9158-481548C7C067 avatar
    314 posts
    Member since:
    Feb 2008

    Posted 18 Sep 2010 Link to this post

    NOTE: This approach is not supported any more. Please check our online demos and documentation for most recent examples.

    Requirements

    RadControls version
    .NET version   4.0
    Visual Studio version   2010
    programming language   C#
    browser support

    all browsers supported by RadControls


    PROJECT DESCRIPTION

    I need to show hierarchical heterogenous data. In summary, it looks as follows:
    public class Group
        {
            public string Description { get; set; }
            public List<Group> Subgroups { get; set; }
            public List<Item> Items { get; set; }
     
        }
        public class Item
        {
            public string Description { get; set; }
            public int MyProperty { get; set; }
            public int MyProperty2 { get; set; }
            public int MyProperty3 { get; set; }
            public int MyProperty4 { get; set; }
            public int MyProperty5 { get; set; }
        }
        public class MyViewModel
        {
            public List<Group> Children { get; set; }
        }

    As you can see data is hierechical and heterogenous. The TreeListView control seemed the best option in this case, but it needs homogenous data as a TreeListViewTableDefinition must be provided. I set TreeListViewTableDefinition to Subgroups, the enitre hierarchy would be shown, but no items would be present. If I set TreeListViewTableDefinition to Items, only the firs level items would be shown but hierarchy would be missed.

    My solution was to make data being homogenous, So I defined an interface as a merge of the two types involved (Group and Item). The result looked as follows:
    public interface IData
        {
            int MyProperty { get; set; }
            int MyProperty2 { get; set; }
            int MyProperty3 { get; set; }
            int MyProperty4 { get; set; }
            int MyProperty5 { get; set; }
            string Description { get; set; }
            List<IData> AllChildren { get; set; }
        }
        public class Group: IData
        {
            public Group(List<Group> subGroups, List<Item> items)
            {
                Subgroups = subGroups;
                Items = items;
                AllChildren = new List<IData>();
                AllChildren.AddRange(Subgroups.ToArray());
                AllChildren.AddRange(Items.ToArray());
     
            }
            public int MyProperty { get; set; }
            public int MyProperty2 { get; set; }
            public int MyProperty3 { get; set; }
            public int MyProperty4 { get; set; }
            public int MyProperty5 { get; set; }
            public string Description { get; set; }
            public List<IData> AllChildren { get; set; }
            public List<Group> Subgroups { get; set; }
            public List<Item> Items { get; set; }
     
        }
        public class Item: IData
        {
            public int MyProperty { get; set; }
            public int MyProperty2 { get; set; }
            public int MyProperty3 { get; set; }
            public int MyProperty4 { get; set; }
            public int MyProperty5 { get; set; }
     
            public string Description { get; set; }
     
            public List<IData> AllChildren
            {
                get { return null; }
                set { }
            }
        }

    I Data interface defines an AllChildren collection property. Item class returns null in its getter. Group class merges in AllChildren collection its Subgroups and its Items. Now I can set TreeListViewTableDefinition in TreelistView to AllChidren property. Another matter arises now. I don't want Group rows showing cells, they must be show just the Group's description property. I wanted Group looking like grouping rows in GridView. The solution was providing a new RowStyle for Goup instances (Item instances would use the default row style) and create an StyleSelector to force the TreeListView to use this new row style when needed
    public class RowStyleSelector: StyleSelector
        {
            public override Style SelectStyle(object item, DependencyObject container)
            {
                if (item is Group)
                    return Application.Current.Resources["GroupRowStyle"] as Style;
                return base.SelectStyle(item, container);
            }
        }


    Easy Style selector. The page with TreelistView looks as follows:
    <UserControl x:Class="RadControlsSilverlightApp1.MainPage"
        xmlns:local="clr-namespace:RadControlsSilverlightApp1"
        mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
        <UserControl.Resources>
            <local:MyViewModel x:Key="ViewModel"/>
            <local:RowStyleSelector x:Key="RowStyleSelector"/>
        </UserControl.Resources>
      <Grid x:Name="LayoutRoot" DataContext="{StaticResource ViewModel}">
            <telerik:RadTreeListView ItemsSource="{Binding Path=Children}" AutoGenerateColumns="False" RowStyleSelector="{StaticResource RowStyleSelector}" >
                <telerik:RadTreeListView.ChildTableDefinitions>
                    <telerik:TreeListViewTableDefinition ItemsSource="{Binding AllChildren}"/>
                </telerik:RadTreeListView.ChildTableDefinitions>
                <telerik:RadTreeListView.Columns>
                    <telerik:GridViewDataColumn Header="Description" DataMemberBinding="{Binding Path=Description}"/>
                    <telerik:GridViewDataColumn Header="MyProperty" DataMemberBinding="{Binding Path=MyProperty}"/>
                    <telerik:GridViewDataColumn Header="MyProperty1" DataMemberBinding="{Binding Path=MyProperty1}"/>
                    <telerik:GridViewDataColumn Header="MyProperty2" DataMemberBinding="{Binding Path=MyProperty2}"/>
                    <telerik:GridViewDataColumn Header="MyProperty3" DataMemberBinding="{Binding Path=MyProperty3}"/>
                    <telerik:GridViewDataColumn Header="MyProperty4" DataMemberBinding="{Binding Path=MyProperty4}"/>
                    <telerik:GridViewDataColumn Header="MyProperty5" DataMemberBinding="{Binding Path=MyProperty5}"/>
                </telerik:RadTreeListView.Columns>
            </telerik:RadTreeListView>
      </Grid>
    </UserControl>

    About the GridViewRow control template to avoid showing cells I will not paste the entire xml code, is really large. I'll just say that the key is to edit the default control template and replace the DataCellsPresenter named "PART_DataCellsPresenter" by a ContentPresenter as follows:
    <ContentPresenter VerticalAlignment="Center" DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource TemplatedParent}}" Content="{Binding Description}" Grid.Column="3" />

    Of course, a little bit more of xaml work is neede to give the "GroupRowTemplate" a nice look. And that's all. I'm attaching the entire demo solution.
Back to Top

This Code Library is part of the product documentation and subject to the respective product license agreement.