Search code examples
c#wpfdatatemplate

Concat list of strings in one TreeViewItem


Currently I'm digging myself into WPF and I have the following problem:

My data model (see below) has hierarchical data in 3 layers (a file, a line in a file, the line broken in parts). This I want to display in a TreeView in 2 levels, such that the first level are the files and the second level items are the concatenated strings of the TextParts list (formatted differently according to the IsMatch property).

So this sample data

{ fileA("filename1"): { 
    line1: { part1("text1", false), part2("text2", true), part3("text3", false) }, 
    line2: { part4("text4", false) } 
} }

should look like:

  • filename1
    • text1 text2 text3
    • text4

(remark: I used bold and italics here instead of the white and yellow background used in my xaml)

I already read this MS documentation, which gave me a good kick in the whole matter. I'm not sure if this can be done in xaml, or is it possible to generate the template in code-behind somehow?

My data model:

class MyModel {
    public ObservableCollection<ResultFile> FileLines { get; }
}
class ResultFile {
    public ObservableCollection<ResultLine> Lines { get; }
    public string Name { get; set; }
}
class ResultLine {
    public ObservableCollection<ResultTextPart> TextParts { get; }
}
class ResultTextPart {
    public string Text { get; set; }
    public bool IsMatch { get; set; }
}

Xaml:

<TreeView x:Name="TvSearchResults">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type m:ResultFile}" ItemsSource="{Binding Lines}">
            <StackPanel Orientation="Horizontal"><TextBlock Text="{Binding Name}"/> <!-- ... --> </StackPanel>
        </HierarchicalDataTemplate>
        <DataTemplate DataType="{x:Type m:ResultLine}">
            <!-- how to display the list of ResultTextPart as single line ? -->
        </DataTemplate>
        <DataTemplate DataType="{x:Type m:ResultTextPart}">
            <TextBlock Text="{Binding Text}" Name="tviTextPart" />
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding IsMatch}" Value="true">
                    <Setter Property="Background" TargetName="tviTextPart" Value="Yellow"/>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

Solution

  • To keep it simple:

    <DataTemplate DataType="{x:Type m:ResultLine}">
        <ItemsControl ItemsSource="{Binding TextParts}" >
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </DataTemplate>
    

    So all you need is actually to use an ItemsControl and set the horizontal oriented panel for this container.