0

I have the following datas :

public class Category {
    string title {get;set;}
    List<Category> Childs {get;set;}
    List<Element> Elements {get;set;}
}

public class Element{
    string Title {get;set;}
    string Description {get;set;}
}

I would like to display it in a TreeView and a DataGrid, on x levels deep, like the following example :

CategoryA 
    CategoryB
         Element1-Title  Element1-Description (in a gridView)
         Element2-Title  Element2-Description (in a gridView)
CategoryC
    Element3-Title  Element3-Description (in a gridView)
CategoryD 
    CategoryE
         CategoryF
             Element4-Title  Element4-Description (in a gridView)
             Element5-Title  Element5-Description (in a gridView)

How can I achieve this ?

Thanks for any advices

Mikke

1 Answers1

0

The simplest way is to add a combined property to hold all of the children of a Category object.

public class Category
{
    public string Title { get; set; }
    public List<Category> SubCategories { get; set; }
    public List<Element> Elements { get; set; }

    public IEnumerable<object> Children => SubCategories.Union(Elements.Cast<object>());
}

Build a list of the Category items that form the root level of the tree and assign this (either diectly or via data binding) to the ItemsSource of your TreeView control.

Then in the Resouces section of your TreeView, create a HierarchicalDataTemplate for Category items which binds to thes combined property for its ItemsSource, and a simple DataTemplate for Elements (assuming that Elements never have children).

<TreeView ItemsSource="{Binding RootCategories}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:Category}" ItemsSource="{Binding Children}">
            <TextBox Text="{Binding Title}" />
        </HierarchicalDataTemplate>

        <DataTemplate DataType="{x:Type local:Element}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="200" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <TextBox Text="{Binding Title}" />
                <TextBox Grid.Column="1" Text="{Binding Description}" />
            </Grid>
        </DataTemplate>
    </TreeView.Resources>
</TreeView>
Peregrine
  • 4,287
  • 3
  • 17
  • 34
  • Hello Peregrine, thanks for your help. It works fine. Let's complicate a little more. For my "Element" I have multiple types and all inherits from an IElement. Let's assume I have ElementA, ElementB that inherits from IElement. How can I use it in the DataTemplate ? Instead of using local:Element, I Would like to use local:IElement and apply the same visual for every types. Thanks for your advices. – IMikkeI Jan 19 '21 at 09:10
  • @IMikkeI You can define a data template for an interface type, but the binding is slightly more complicated. https://stackoverflow.com/questions/15023441/how-to-bind-datatemplate-datatype-to-interface – Peregrine Jan 19 '21 at 11:26
  • Yes I've tried this. When I use this technique, in each "Element" lane, I have the class name instead of title and description attributes. This worked when I put my DataTemplate in the HierarchicalDataTemplate.ItemTemplate but the hierarchy of the TreeView is broken then. – IMikkeI Jan 19 '21 at 11:40