2

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

Community
  • 1
  • 1
Mauri
  • 630
  • 1
  • 5
  • 11

1 Answers1

2

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...

Marc
  • 12,706
  • 7
  • 61
  • 97
  • Hi Marc, thanks for your help, due to your suggestions I managed to bind the data properly. In particular I've used the latter solution, creating a non-generic wrapper (even though this added a lot of code replication in my project). I want to give you a more detailed explanation about why I needed to use a data wrapper. I'm working on a project where the amount of data to display in the gui is very big, and I found out a way to optimize the loading operation using virtualization (look at [this](http://www.zagstudio.com/blog/378#.VTpB5pMQuq9)). This solution worked like a charm with DataGrid – Mauri Apr 24 '15 at 13:24
  • The next step was to put this "virtualization" on a TreeView too. Unfortunately I found out that this approach seems to be not supported by the TreeView control. The big difference between DataGrid and TreeView in fact, is that DataGrid access to the elements of the binded collection only when the element is going to be displayed, while the TreeView loads all the elements at the very first access. – Mauri Apr 24 '15 at 13:25