Q.Rey
Q.Rey

Reputation: 723

TreeView HierarchicalDataTemplate with mixed types

i'm actually developping my first WPF application which must display all components of my computer in a treeview with hierarchical data.

Since yesterday i'm facing a little problem, i read tons of examples of treeview binding but I did not succeed with multiples types binding...

It must look like this :

My machine (level 0)

-----Keyboards⬇️(level 1)

--------Keyboard1⬇️(level 2)

--------Keyboard2⬇️(level 2)

-----OS⬇️(level 1)

-----CPU⬇️(level 1)

--------CPU1⬇️(level 2)

--------CPU2⬇️(level 2)

-----VideoCard⬇️(level 1)

---------VideoCard1⬇️(level 2)

---------VideoCard2⬇️(level 2)

I have a viewmodel with all my components device :

DeviceInfo.cs :

public class DeviceInfo
{
    public string ComputerName { get; set; }

    public Bios Bios { get; set; }
    public ComputerSystem ComputerSystem { get; set; }
    public List<Keyboard> Keyboards { get; set; }
    public OperatingSystem OperatingSystem { get; set; }
    public List<Processor> Processors { get; set; }
    public List<VideoCard> VideoCards { get; set; }
}

Each component contain specific attribute, for example Keyboard.cs:

public class Keyboard
{
    public string Description { get; set; }
    public string DeviceID { get; set; }
}

I tried something like that for my treeview, i'm binding data in Mainwindow like this :

DeviceTree.ItemsSource = deviceInfos;

MainWindow.xaml :

 <TreeView Margin="10" BorderThickness="2" BorderBrush="Black" Name="DeviceTree">
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="x:Type data:DeviceInfo" ItemsSource="{Binding Keyboards}">
                        <TextBlock Text="{Binding Description}"></TextBlock>
                    </HierarchicalDataTemplate>
                    <HierarchicalDataTemplate DataType="x:Type data:DeviceInfo" ItemsSource="{Binding OS}">
                        <TextBlock Text="{Binding Version}"></TextBlock>
                    </HierarchicalDataTemplate>
                    <HierarchicalDataTemplate DataType="x:Type data:DeviceInfo" ItemsSource="{Binding VideoCard}">
                        <TextBlock Text="{Binding SerialNumber}"></TextBlock>
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
   </TreeView>

Actually It look like this in my treeview template:

"Model.DeviceInfo"

Every link of similar examples will be helpful for me. Thanks in advance

Upvotes: 2

Views: 2653

Answers (3)

mm8
mm8

Reputation: 169218

A HierarchicalDataTemplate supports only a single child property. It makes no sense to define three templates for the same type. Only of them can be applied at runtime anyway.

What you should do is to transform your DeviceInfo class into a data-binding friendly view model class that has a single child property:

public class Item
{
    public string Header { get; set; }
    public IEnumerable<Item> Children { get; set; }
}

You would then bind the ItemsSource property to an IEnumerable<Item> of four Item root objects, i.e. the level 1 keyboard, OS, CPU and VideoCard nodes.

Also note the sytax for setting the DataType property to an actual type in XAML:

<TreeView Margin="10" BorderThickness="2" BorderBrush="Black" Name="DeviceTree">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:Item}" ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding Header}" />
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

Edit:

If the total number of levels is not dynamic, i.e. you always have a total of two levels, you could set or bind the ItemsSource property to a new List<DeviceInfo>(1) { deviceInfos } and add the "static" root levels to the TreeView explicitly in your XAML markup:

<TreeView Margin="10" BorderThickness="2" BorderBrush="Black" Name="DeviceTree">
    <TreeViewItem Header="Keyboards" ItemsSource="{Binding Keyboards}">
        <TreeViewItem.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Description}" />
            </DataTemplate>
        </TreeViewItem.ItemTemplate>
    </TreeViewItem>
    <TreeViewItem Header="Operating Systems" ItemsSource="{Binding OperatingSystem}">
        <TreeViewItem.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Version}" />
            </DataTemplate>
        </TreeViewItem.ItemTemplate>
    </TreeViewItem>
    <!-- + TreeViewItems for Processors and VideoCards -->
</TreeView>

Upvotes: 2

Guilhem Prev
Guilhem Prev

Reputation: 979

To make what you want you just have to put TreeViewItem in your primary TreeView. And if you want to up a level, you just have to add an ItemTemplate with a TreeViewItem inside. I give you an example for a simple object (Bios) and then for a List of object (Keyboards). The ItemSources of the TreeView is a list of DeviceInfo.

xaml :

<TreeView x:Name="MyTreeView">
    <TreeView.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Vertical">
                <TreeViewItem Header="{Binding ComputerName}">
                    <TreeViewItem.Items>
                        <TreeViewItem Header="Bios">
                            <StackPanel Orientation="Vertical">
                                <TextBlock Text="{Binding Bios.Description}"/>
                                <TextBlock Text="{Binding Bios.Name}"/>
                                <TextBlock Text="{Binding Bios.Version}"/>
                            </StackPanel>
                        </TreeViewItem>
                        <TreeViewItem Header="Keyboard" ItemsSource="{Binding Keyboards}">
                            <TreeViewItem.ItemTemplate>
                                <DataTemplate>
                                    <TreeViewItem Header="{Binding DeviceID}">
                                        <TextBlock Text="{Binding Description}"/>
                                    </TreeViewItem>
                                </DataTemplate>
                            </TreeViewItem.ItemTemplate>
                        </TreeViewItem>
                    </TreeViewItem.Items>
                </TreeViewItem>
            </StackPanel>
        </DataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

Upvotes: 1

Eugene Kim
Eugene Kim

Reputation: 31

This normally happens when WPF doesn't know how to display your model on the view. In your source code, you have defined the template which show each properties of the model in the TextBox. But you haven't applied them to your view.

So It just shows default ToString() of your model. That's why you only see the text "Model.DeviceInfo".

The following link would be helpful for you.

Data Templating Overview

Upvotes: 0

Related Questions