Producing a hierarchy of treeview in xaml

410 views Asked by At

This seems like a common question but I have not been able to get it working from the answers of other questions.

I have a company, which has multiple projects, and each project can have multiple tasks. The company class contains some metadata and also a list of projects that it owns, the project class also has some metadata and a list of tasks it has. What I'm trying to do is to display this hierarchy in a tree view. I have made a sample object of a company which has 2 projects and project1 has 2 tasks. The tree view should only display one company at a time, so the root treeviewitems are the projects.

Heres my attempt at the problem, but nothing is displayed.

<TreeView ItemsSource="{Binding listOfProjects}" Margin="10" Height="200">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding listOfTasks}" DataType="{x:Type local:Task}">
            <TreeViewItem Header="{Binding name}"/>
            <HierarchicalDataTemplate.ItemTemplate>
                <DataTemplate>
                    <TreeViewItem Header="{Binding name}" />
                </DataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

How do I go about making it correct? What should I bind to ItemsSource? For the TreeViewItem headers, how do I let it know which field to bind? At the moment, I have {Binding name}, but how do I differentiate between where its coming from (because project has a field 'name', and so does task).

I will be extending the hierarchy further (a task can have multiple parts and so on) but I'm assuming that each additional level would be done the same as the first 2.

edit: here my company, project and task classes.

class Company
{
    public List<Project> listOfProjects;
    public string name { get; set; }
    private int companyID { get; set; }

    public Company()
    {
        companyID = 0;
        name = "Default";
        listOfProjects = new List<Project>();
    }

    public Company(string inName)
    {
        companyID = 0;
        name = inName;
        listOfProjects = new List<Project>();
    }
} 
class Project
{
    private int projID { get; set; }
    public string name { get; set; }
    public DateTime startDate { get; set; }
    public DateTime endDate { get; set; }
    public string region { get; set; }
    private int companyID { get; set; }
    public List<Task> listOfTasks;

    public Project()
    {
        projID = 0;
        name = "Default";
        startDate = new DateTime();
        endDate = new DateTime();
        region = "Default";
        companyID = 0;
        listOfTasks = new List<Task>();
    }

    public Project(string inName)
    {
        projID = 0;
        name = inName;
        startDate = new DateTime();
        endDate = new DateTime();
        region = "Default";
        companyID = 0;
        listOfTasks = new List<Task>();
    }
}

Tasks atm doesnt have anything in it except a constructor. It has 2 fields, projectID and name.

2

There are 2 answers

2
ebattulga On BEST ANSWER

Your hierarchical data template override your treeview. You must rename listofProject and listofTask to same name. Therefore you create Interface or Class.Then implement Company,Project,Task from this interface.

public interface ITreeItem
    {
        string Name { get; }
        List<ITreeItem> childs { get; }
    }


    public class Company : ITreeItem
    {

        public string Name
        {
            get { return name; }
        }

        public List<ITreeItem> childs
        {
            get { return listofProjects; }
        }
    }

    public class Project : ITreeItem
    {
        public string Name
        {
            get { return name; }
        }

        public List<ITreeItem> childs
        {
            get { return listofTask; }
        }
    }

    public class Task : ITreeItem
    {
        public string Name
        {
            get { return name; }
        }

public List<ITreeItem> childs
        {
            get { return null; }
        }
    }

Then your template is

<HierarchicalDataTemplate ItemsSource="{Binding childs}" DataType="{x:Type local:ITreeItem}">
            <TreeViewItem Header="{Binding Name}"/>
            <HierarchicalDataTemplate.ItemTemplate>
                <DataTemplate>
                    <TreeViewItem Header="{Binding Name}" />
                </DataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
0
Mashton On

So the top level will all be of type "project", and all branches will be of type "task"? You can use multiple HierarchicalDataTemplates like this:

<StackPanel.Resources>
    <sdk:HierarchicalDataTemplate x:Key="TaskTemplate" 
        ItemsSource="{Binding Path=Childs}"> 
       <TextBlock FontStyle="Italic" Text="{Binding Path=Name}" />
     </sdk:HierarchicalDataTemplate>
    <sdk:HierarchicalDataTemplate x:Key="ProjectTemplate" 
        ItemsSource="{Binding Path=ListOfTasks}" 
        ItemTemplate="{StaticResource TaskTemplate}">
        <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" />
        </sdk:HierarchicalDataTemplate>
</StackPanel.Resources>

And then declare your treeview like this ...

<sdk:TreeView ItemsSource="{Binding MyProjectList}" 
    ItemTemplate="{StaticResource ProjectTemplate}" x:Name="myTreeView" />