19

For my treeview I have two different classes that provide the ItemsSource.

public class TreeViewModel : ViewModelBase
{
    public ObservableCollection<NodeViewModel> Items { get; set; }
}

public class NodeViewModel : ViewModelBase
{
    public string Id { get; set; }
    public string Name { get; set; }
    public ObservableCollection<NodeViewModel> Children { get; set; }
}

Now I want my TreeView to display the Items in TreeViewModel and show hierarchical data as provided by the NodeViewModel.

Here is my XAML

<Window x:Class="TreeViewMasterDetails.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TreeViewMasterDetails" 
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TreeView Height="Auto" 
                  HorizontalAlignment="Stretch" 
                  Margin="10" 
                  VerticalAlignment="Stretch" 
                  Width="Auto">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="x:Type local:TreeViewModel" ItemsSource="{Binding Items}">
                    <TextBlock Text="{Binding Path=Name}"></TextBlock>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="x:Type local:NodeViewModel" ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Name}"></TextBlock>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
    </Grid>
</Window>

Have tried to provide Items as the ItemsSource of the TreeView. It does not show the data hierarchically, if displaying anything.

And I tried using the ItemTemplate instead of the TreeView.Resources, too.

What is wrong about it?

Perhaps a problem is the first TextBlock Text Binding? I want to display the Name property of the NodeViewModel in Items there.

4
  • I think this is a duplicate of [WPF TreeView HierarchicalDataTemplate - binding to object with multiple child collections][1]. [1]: stackoverflow.com/questions/1912481/… Commented Mar 6, 2013 at 6:30
  • Yes, I already have seen that. But it does not work here. Commented Mar 6, 2013 at 6:32
  • TreeViewModel does not have a Name property but that's probably not the issue Commented Mar 6, 2013 at 6:49
  • Any luck for doing this on Windows Phone? Commented Nov 8, 2013 at 15:02

2 Answers 2

34

You should only have to declare the HierarchicalDataTemplate for NodeViewModel as this is the only thing showing in the TreeView, and bind the actual ItemSource to the TreeView

<TreeView ItemsSource="{Binding Items}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:NodeViewModel}" ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding Name}"></TextBlock>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

Full Example

Xaml:

<Window x:Class="WpfApplication13.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication13"
        Title="MainWindow" x:Name="UI" Width="343" Height="744.625" >

    <TreeView DataContext="{Binding ElementName=UI, Path=TreeModel}" ItemsSource="{Binding Items}">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:NodeViewModel}" ItemsSource="{Binding Children}">
                <TextBlock Text="{Binding Name}"></TextBlock>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>

</Window>

Code:

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();
    }

    public TreeViewModel TreeModel
    {
        get
        {
            return new TreeViewModel
            {
                Items = new ObservableCollection<NodeViewModel>{
                           new NodeViewModel { Name = "Root", Children =  new ObservableCollection<NodeViewModel> {
                              new NodeViewModel { Name = "Level1" ,  Children = new ObservableCollection<NodeViewModel>{ 
                                  new NodeViewModel{ Name = "Level2"}}} } }}
            };
        }
    }
}

public class TreeViewModel
{
    public ObservableCollection<NodeViewModel> Items { get; set; }
}

public class NodeViewModel
{
    public string Id { get; set; }
    public string Name { get; set; }
    public ObservableCollection<NodeViewModel> Children { get; set; }
}

Result:

enter image description here

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, it works. Was sure that I have tried that before. Thank you so much!
Hi, thanks for sharing, I used your solution, however it doesn't seem to let me select anyhting and also the arrows on the left are missing. The tree looks frozen. One change I did to you code, I bind my TreeModel from my ViewModel class not from MainWindow.
Worked fine for me. Also see stackoverflow.com/questions/2251260 if you want CheckBoxes that propagate instead of TextBlocks.
4

As @sa_ddam213 said, you only need the HierarchicalDataTemplate for NodeViewModel, but the only problem with your code was the missing braces ({ and }) for DataType="x:Type local:TreeViewModel" in your data template definitions (it should be DataType="{x:Type local:TreeViewModel}"). Adding brackets and ItemsSource binding solves the problem:

The additional HierarchicalDataTemplate for TreeViewModel is not used, but it does not harm.

2 Comments

You are right, this is really the problem. Strangely enough, it works without the braces when used in ItemTemplate, but not in Resources.
@MareInfinitus It is because when used int ItemTemplate, it deos not need to look at the DataType property. You are directly saying to the TreeView to use the given template for items. So no need for DataType.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.