Question

I am trying to bind a collection to wpf TreeView control using data templates. Each item(Person) in the collection also contains two different collections(Cars, Books) of type car and book.

Here's simplified list of the objects involved to save space.

public class Person
{
  public string Name
  public List<Book> Books;
  public List<Car> Cars;
}

public class Book
{
  public string Title
  public string Author
}

public class Car
{
  public string Manufacturer;
  public string Model;
}

Here is how I am binding

    public MainWindow()
    {
        InitializeComponent();

        this.treeView1.ItemsSource = this.PersonList();
    }

    public List<Person> PersonList()
    {
        List<Person> list = new List<Person>();


        Book eco = new Book { Title = "Economics 101", Author = "Adam Smith"};
        Book design = new Book { Title = "Web Design", Author = "Robins" };

        Car corola = new Car { Manufacturer = "Toyota", Model = "2005 Corola"};
        Car ford = new Car { Manufacturer = "Ford", Model = "2008 Focus"};

        Person john = new Person { Name = "John", Books = new ObservableCollection<Book> { eco, design }, Cars = new ObservableCollection<Car> { corola } };

        Person smith = new Person { Name = "Smith", Books = new ObservableCollection<Book> { eco, design }, Cars = new ObservableCollection<Car> { ford } };

        list.AddRange(new[] {john, smith });
        return list;
    }

Here is the Xaml code

<Grid>
    <TreeView  Name="treeView1">
    </TreeView>
</Grid>

I am looking to see the tree display to look like this.

>John
  >Books
    Economics 101 : Adam Smith
    Web Design    : Robins
  >Cars
    Totota : 2005 Corola
>Smith
  >Books
    Economics 101 : Adam Smith
    Web Design    : Robins
  >Cars
    Ford: 2008 Focus

this sign > is used to show the tree folder and should not be considered in the template.

Was it helpful?

Solution

It is a bit complicated since your tree has two different child collections. WPF does not support a scenario with multiple ItemsSource definitions. Therefore you need to combine those collection into a CompositeCollection. The type matching of the composite elements (i.e. Car, Book) will be done automatically.

In XAML you need to define so-called HierarchicalDataTemplates that match your type definitions. If local points to the namepace where Book, Car and Person are defined, the simplified HierarchicalDataTemplates could look like this:

 <HierarchicalDataTemplate DataType="{x:Type local:Person}" 
                              ItemsSource="{Binding CompositeChildren}">
        <TextBlock Text="{Binding Path=Name}" />
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="{x:Type local:Book}">
        <TextBlock Text="{Binding Path=Title}" />
        <!-- ... -->
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="{x:Type local:Car}">
        <TextBlock Text="{Binding Path=Model}" />
        <!-- ... -->
    </HierarchicalDataTemplate>

Then you need to hook up your collection to the tree control. There are a few possibilities to do this, the easiest would be to define a property in your Window class and define a Binding:

<TreeView Items={Binding ElementName=myWindow, Path=Persons}/>

This should point you into the right direction, but don't take my code as compile ready :-)

OTHER TIPS

CompositeCollection is a good answer, except you can't bind the child collections to the DataContext because it's not a Freezable. You can only bind them to resources. (See this question for more on that.) That makes it kind of hard to use in a HierarchicalDataTemplate, since the ItemsSource in one needs to bind to a property in the current context to be useful.

If you don't need change notification on the collections, you can easily implement a property in your view model, e.g.:

public IEnumerable<object> Items
{
   get { return Books.Concat(Cars); }
}

If you need change notification on the collection, it's a lot less trivial.

You need a DataTemplate, otherwise WPF doesn't know how to display your object.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top