WPF TreeView how to add TreeViewItem control template for child elements of TreeViewItem

0xDEAD BEEF picture 0xDEAD BEEF · Mar 29, 2013 · Viewed 12.1k times · Source

how do I create treeview like this one:

 <TreeViewItem Header="Customers" ItemsSource="{Binding Customers}">
  • Customers
    • Anna
      • Delete
      • Open
    • Peter
      • Delete
      • Open
    • Andrew
      • Delete
      • Open

I would like to create child item template something like this

 <TreeViewItem Header="{Binding Header}">
   <TreeViewItem Header="Delete"/>
   <TreeViewItem Header="Open"/>
 </TreeViewItem>

But it does not quite work that well because I end up having treeviewitem with datatemplate treeviewitem, but I would like to override controltemplate of child elements, but not parent. Sure, I want to avoid my binding to be TreeViewItem, nor I want to create children with those static obejct "Open", "Delete".

Answer

Pavel Voronin picture Pavel Voronin · Apr 2, 2013

Here is one of the best articles about TreeView I ever read.

Inside TreeView.Resources you could declare several DataTemplates with different DataType if Delete and Open commands were items of some collection. (TargetType for the commands would be ICommand).

But it seems to mee you do not need TreeView at all. Customers is a header of the list. If you want it to be epxpandable use Expander control.
Then it is sufficient to provide one data template for each customer.

<DataTemplate DataType="CustomerTypeName">
    <Expander Header="{Binding CustomerName}">
        <Button Command="{Binding DeleteCustomerCmd}" Content="Delete" Margin="15,0,0,0"/>
        <Button Command="{Binding OpenCustomerCmd}" Content="Open" Margin="15,0,0,0"/>
    <Expander/>
<DataTemplate>

But here you'll have some troubles with selection highlight.

public class CommandWrapper
{
    ICommand Command {get;set;}
    string CommandName {get;set;}
}

public class CustomerViewModel
{
    Customer Customer {get;set;}
    IEnumerable<CommandWrapper> Commands {get;}
}

Let Customers be collection of CustomerViewModel. Then the following XAML can help:

<TreeView ItemsSource="{Binding ...}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="TypeHoldingCustomersCollection" 
            ItemsSource="{Binding Customers}">
            <TextBlock Text="Customers"/>
        </HierarchicalDataTemplate>

        <HierarchicalDataTemplate DataType="CustomerViewModel" 
            ItemsSource="{Binding Commands}">
            <TextBlock Text="{Binding Path=Customer.Name}"/>
        </HierarchicalDataTemplate>

        <DataTemplate DataType="CommandWrapper">
            <Button Content="{Binding CommandName}" Command="{Binding Command}"/>
        </DataTemplate>
    </TreeView.Resources>
</TreeView>