nabulke
nabulke

Reputation: 11255

Add different types of childs to treeview

I'd like to visualize a collection of Test class (POCO from model assembly) in a TreeView. Each Test instance has got a collection of Readers and Groups:

Test class pseudo code

public class Test 
{
    // properties
   public  ObservableCollection<Reader> Readers { get; set; }
   public  ObservableCollection<Group> Groups { get; set; }
}

What I want

My goal is to visualize the tests in a TreeView like that:

Test 1  
   |- Reader 1  
   |- Reader 2  
   |- Group 1   
   |- Group 2

Test 2  
   |- Reader 1  
   |- Group 4   
   |- Group 5

What I got so far

I can show tests and readers by using a HierarchicalDataTemplate

<HierarchicalDataTemplate DataType="{x:Type model:Test}" ItemsSource="{Binding Readers}">
    <TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate> 

Basically I want to tell the TreeView, "Hey there is another child item source with another template in my test class, use it!".

I tried using a CompositeCollection of readers and groups, but got stuck because I don't want to change the Test class (it is generated code).

Upvotes: 0

Views: 323

Answers (2)

AnjumSKhan
AnjumSKhan

Reputation: 9827

Create a Converter and use it in your HierarchicalDataTemplate.ItemsSource.

Converter :

public class ReadersGroupsCombineConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ObservableCollection<Reader> readers = (value as Test).Readers;
        ObservableCollection<Group> groups = (value as Test).Groups;

        ObservableCollection<object> readersGroups = new ObservableCollection<object>();
        foreach (Reader reader in readers)
            readersGroups.Add(reader);

        foreach (Group group in groups)
            readersGroups.Add(group);

        return readersGroups;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

XAML :

    <HierarchicalDataTemplate x:Key="HDTReaderGroups" ItemsSource="{Binding ., Converter={StaticResource ReaderGroupsCombineCnvKey}}">
        <HierarchicalDataTemplate.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}"/>
            </DataTemplate>
        </HierarchicalDataTemplate.ItemTemplate>
        <TextBlock Text="{Binding Name}"/>
    </HierarchicalDataTemplate>

Upvotes: 1

Carlos Teixeira
Carlos Teixeira

Reputation: 744

What I've done in the past, and recommend you to do, is to create a wrapper object for each type you want to represent in the treeview. You can initialize that structure in the viewmodel. When you have all your objects set up, you can do this:

<HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type Model:TestNode}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>

And now the templates for the children:

<HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type Model:ReaderNode}">
    <TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>

<HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type Model:GroupNode}">
    <TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>

This way you will have a template for each type of object you are modeling.

As I've said before, I recommend you to do this, because a binding to an object that doesn't implement INotifyPropertyChanged leaks memory, and usually POCOs and DTOs don't implement it. You can see more here: https://support.microsoft.com/en-us/kb/938416

Upvotes: 0

Related Questions