wpf.net-4.0treeviewdatatemplatehierarchicaldatatemplate

WPF TreeView HierarchicalDataTemplate - binding to object with multiple child collections -> Reloaded


I've seen several posts with similar problems and I've already tried to follow them all. Now finally I get all data on screen, but not the way I want it to be. But let's get started.

I have a ViewModel which provides the data like this:

/// <summary>
/// Returns a collection of all the ContinentListViewModel objects
/// </summary>
public static IList<Object> Items
{
    get
    {
        IList<object> childNodes = new List<object>();


        foreach (ContinentViewModel continent in _instance)
        {
            childNodes.Add(continent);
            foreach (CountryViewModel country in continent.CountrytList)
            {
                childNodes.Add(country);
                foreach (BusinessunitViewModel bu in country.BusinessunitList)
                {
                    childNodes.Add(bu);
                }
            }
        }
        return childNodes;
    }
}

This is my xaml-TreeView-code:

            <TreeView Name="tvwBuList" ItemsSource="{Binding BusinessunitList.Items}" HorizontalAlignment="Left" VerticalAlignment="Top" MinHeight="230" MinWidth="265" MaxHeight="230" MaxWidth="265">
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="{x:Type local:ContinentViewModel}" ItemsSource="{Binding}">
                            <TextBlock Text="{Binding Path=ContinentCode}" />
                        </HierarchicalDataTemplate>
                    <HierarchicalDataTemplate DataType="{x:Type local:CountryViewModel}" ItemsSource="{Binding}">
                            <TextBlock Text="{Binding Path=CountryCode}" />
                    </HierarchicalDataTemplate>
                    <DataTemplate DataType="{x:Type local:BusinessunitViewModel}">
                        <RadioButton GroupName="BUGroup" Content="{Binding Path=BuCode}" />
                    </DataTemplate>
                </TreeView.Resources>
                <TreeView.ItemContainerStyle>
                    <Style TargetType="TreeViewItem">
                        <!--Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/-->
                        <Setter Property="IsExpanded" Value="True"/>
                        <Setter Property="Foreground" Value="Yellow"/>
                    </Style>
                </TreeView.ItemContainerStyle>
            </TreeView>

And this is what the output looks like:

http://imgh.us/bu_treeview.jpg

What I want to have is a complete structure like this:

+ AP
|--+ AU
   O-- 164
|--+ CN
   O-- 258
   O-- 277

...

So what am I missing here? Help appreciated, thank you!


Solution

  • Your HierarchicalDataTemplates are at the same level of the tree because your for loops are putting them into the same collection. Essentially your collection doesn't match your bindings in XAML.

    I believe to get this to work you would need separate collections for each level you want. So you would need one collection for the continent and a second for the countries.

    Then you would need to update your resources to this:

            <TreeView Name="tvwBuList" ItemsSource="{Binding BusinessunitList.Items}" HorizontalAlignment="Left" VerticalAlignment="Top" MinHeight="230" MinWidth="265" MaxHeight="230" MaxWidth="265">
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="{x:Type local:ContinentViewModel}" ItemsSource="{Binding Path=Continents}">
                            <TextBlock Text="{Binding Path=ContinentCode}" />
                        </HierarchicalDataTemplate>
                    <HierarchicalDataTemplate DataType="{x:Type local:CountryViewModel}" ItemsSource="{Binding Path=Countries}">
                            <TextBlock Text="{Binding Path=CountryCode}" />
                    </HierarchicalDataTemplate>
                    <DataTemplate DataType="{x:Type local:BusinessunitViewModel}">
                        <RadioButton GroupName="BUGroup" Content="{Binding Path=BuCode}" />
                    </DataTemplate>
                </TreeView.Resources>
                <TreeView.ItemContainerStyle>
                    <Style TargetType="TreeViewItem">
                        <!--Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/-->
                        <Setter Property="IsExpanded" Value="True"/>
                        <Setter Property="Foreground" Value="Yellow"/>
                    </Style>
                </TreeView.ItemContainerStyle>
            </TreeView>
    

    That should give you what you want. I've used the same model for defining a message structure with the treeview and the only difference between our code is I have each level in its own collection and bind explicitly to that collection.