Search code examples
c#wpfblend

Insert textblock into treeviewitem


I added textblock to treeviewitem. but treeviewitem.header could not bind to this textblock. what should I do? I want to add objects on treeview. want to develop a custom treeview.

<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="19" Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
        <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
    </Border>
    <ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/>
</Grid>

TO

<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid Background="#15232e">
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="19" Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
        <TextBlock x:Name="PART_Header" Text="{Binding ??????}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
    </Border>
    <ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/>
</Grid>

Solution

  • There are probably other ways around your issue, but to speak to your problem directly, the ContentPresenter is getting the entire object.

    So if your view model looked like this:

    public class Data 
    {
       public string Name { get; set; }
       public List<Data> Children { get; set; }
    }
    

    Then basically the ContentPresenter's ContentSource property is basically going to set Content, ContentTemplate, etc. (See https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.contentpresenter.contentsource?view=netframework-4.8)

    And in your treeviews hierarchical data template might look like this:

    <TreeView.ItemTemplate>
       <HierarchicalDataTemplate ItemsSource="{Binding Children}">
          <TextBlock Text="{Binding Name}" />
       </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
    

    Where the inner part will basically be the data template given to the presenter, and the ItemsSource will be how children are determined.

    So - for your case, you're either going to want to bind Text to data directly in the HierarchicalDataTemplate as noted above, or if you really do want to customize the ControlTemplate of TreeViewItem, you'll can provide the TextBlock as the PART_Header, but with a binding to an element of the tree. Given the Data class above, that would look like this:

    <ControlTemplate>
       ...
       <TextBlock x:Name="PART_Header" Text="{Binding Name}"/>
       ...
    </ControlTemplate>
    

    Let me know if that hits your use-case, hard to say without more info unfortunately. Good luck!