2
votes

I have a TreeView and I want to bind some data to it; I want to display different TreeViewItem layout for each type of data and looking at this example I figured out how to do it.

So far I have hence the following classes:

public class Category
{
    public string Name { get; set; }
    public List<Product> Products { get; set; }
}
public class Product
{
    public string Name { get; set; }
}

Now I need to use a wrapper like this to handle data:

public class DataWrapper<T> where T : class
{

    public T Data { get; set; }
}

And I would like to set as ItemSource for the TreeView a list created like this:

IList<DataWrapper<Category>> list = new List<DataWrapper<Category>>();

Category c = new Category() { Name = "C1", Products = new List<Product>() { new Product() { Name = "P1" }, new Product() { Name = "P2" } } };
list.Add(new DataWrapper<Category>() { Data = c });

c = new Category() { Name = "C2", Products = new List<Product>() { new Product() { Name = "P3" }, new Product() { Name = "P4" } } };
list.Add(new DataWrapper<Category>() { Data = c });

c = new Category() { Name = "C3", Products = new List<Product>() { new Product() { Name = "P5" }, new Product() { Name = "P6" } } };
list.Add(new DataWrapper<Category>() { Data = c });

So what I've done is to set the DataContext to the treeView:

myTreeView.DataContext =list;

and this is the xaml:

<TreeView x:Name="myTreeView">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type src:Category}" ItemsSource="{Binding Path=Data}">
                <StackPanel>
                    <TextBlock Text="Category:" />
                    <TextBlock Text="{Binding Path=Name}" />
                </StackPanel>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type src:Product}">
                <StackPanel>
                    <TextBlock Text="Product:" />
                    <TextBlock Text="{Binding Path=Name}" />
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>

But of course it's not working :) Could anyone exaplain me how to properly bind such List of objects?

Thank you

1

1 Answers

2
votes

The reason it is not working is that you bind the ItemsSource to a property called Data on the DataContext which is of type List<DataWrapper<Category>> and doesn't have this property.

I am not really sure what you need the wrapper for. The easiest way is to get rid of the wrapper, make the list a list of item type Category and use this list as the ItemsSource:

IList<Category> list = new List<Category>();

Category c = new Category() { Name = "C1", Products = new List<Product>() { new Product() { Name = "P1" }, new Product() { Name = "P2" } } };
list.Add(c);

...

// Set this list as ItemsSource
myTreeView.ItemsSource=list;

That will do as then the type bindings of your data templates will get applied correctly.

Alternatively, if you need the wrapper, just make the wrapper non-generic:

public class CategoryWrapper
{
    public Category Data { get; set; }
}

and modify the category template:

<HierarchicalDataTemplate DataType="{x:Type src:CategoryWrapper}" ItemsSource="{Binding Path=Data.Products}">
    <StackPanel>
        <TextBlock Text="Category:" />
        <TextBlock Text="{Binding Path=Data.Name}" />
    </StackPanel>
</HierarchicalDataTemplate>

The reason for making it non-generic, is that it is not really easy to specifiy the generic type as the DataType of the template:

<!-- Doesn't work! -->
DataType="{x:Type src:DataWrapper<Category>}" 

Hope this helps! Let me know if this solution doesn't work in your case, I'll have a look at it again...