2

I have built a WPF MVVM TreeView that shows different Elements.

BaseElement
- CatA
-- SubItemA
- CatB
-- SubItemB

Based on the class I would like to use a different data template. for each type.

So far I can connect to the selected Item, but I'm not sure how to manage the different data templates.

public class SubItem
{
    public string Type { get; set; }
    public string Name { get; set; }
}


    <StackPanel Grid.Column="2" DataContext="{Binding ElementName=myTreeView, Path=SelectedItem}">
        <TextBox Text="{Binding Parent.Name}" />
        <TextBox Text="{Binding Path=Name, Mode=TwoWay}" />
    </StackPanel>

[Update Nov. 15]

           <HierarchicalDataTemplate x:Key="L3Template" ItemsSource="{Binding L4Collection}" ItemTemplate="{StaticResource L4Template}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Name}" />
                </StackPanel>
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate x:Key="CategoryTemplate" ItemsSource="{Binding L3Collection}" ItemTemplate="{StaticResource L3Template}">
                <StackPanel>
                    <TextBlock Text="{Binding Name}" />
                </StackPanel>
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate x:Key="L1Template" ItemsSource="{Binding CategoryCollection}" ItemTemplate="{StaticResource CategoryTemplate}">
                <StackPanel>
                    <TextBlock Text="{Binding Name}" />
                </StackPanel>
            </HierarchicalDataTemplate>

[/Update Nov. 15]

Stef
  • 593
  • 3
  • 10
  • 23

3 Answers3

3

If the subitems are different classes, then it is rather simple: add datatemplates foreach class to the resource section. If subitems need different templates based on the value of an enum prop, then you will need a datatemplateselector. This is a bit more cumbersome.

Grafix
  • 706
  • 4
  • 6
  • Thanks. Tried to use to do it by value of an enum prop, but the datatemplateselector did not work well for me. Hence, I woul like to recode a bit to use different classes: In that case (1) do I need a parent class an subclasses for the observablecollection? (2) How will I use the HirachicalDataTemplate for the TreeView itself, if I have different Classes? – Stef Nov 14 '12 at 08:51
  • No you don't need subclasses for the observable collections. The hierarchicalDatatemplate is almost the same as a normal datatemplate, it only adds the possibility to specify the property in your object to use for the children of the treeviewitem. – Grafix Nov 14 '12 at 23:04
  • okay, I got this HierarchicalDataTemplate [Update Nov. 15] that builds a nice tree for all levels. If CatX would be one class with different names, CatX should contain different classes of objects. I could add two observableCollections of two different classes. But I don't see where I do the differentiation/switch within the XAML/HierarchicalDataTemplate since I probably can do only one ItemTemplate="{StaticResource L3Template}" statement?! – Stef Nov 15 '12 at 12:44
  • Ah I see your point. In this case you don't set the ItemTemplate but you add the datatemplates to de Resources section of your treeview (f.i.). You will have to fill in the TargetType and not use any keys. WPF then applies the template based on the class type. I will add some example code later. – Grafix Nov 19 '12 at 07:51
  • With the second answer, this works well now! I replaced the StackPanel with a ContentPresenter like here: http://stackoverflow.com/questions/1152128/wpf-databind-to-a-stackpanel-using-datatemplates then it works great. – Stef Nov 20 '12 at 12:21
2

Assuming that you named your classes L1Class, L3Class en Category and local points to the namespace of these classes:

    <TreeView ...>
        <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:L3Class}" ItemsSource="{Binding L4Collection}" >
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>

                <HierarchicalDataTemplate DataType="{x:Type local:Category}" ItemsSource="{Binding L3Collection}" >
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>

                <HierarchicalDataTemplate DataType="{x:Type local:L1Class}" ItemsSource="{Binding CategoryCollection}" >
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
    </TreeView>

Note the use of the implicit datatemplates (no keys, but DataType!) in the resource section.

Grafix
  • 706
  • 4
  • 6
  • Great! That works well. You actually revealed the mystery of TreeViews and HirachicalDataTemplates! Thanks so much. I connected it to my ViewModels like DataType="{x:Type local:CategoryViewModel}". and added a local statement xmlns:local="clr-namespace:MyApplication.ViewModel". Then it works well. – Stef Nov 20 '12 at 12:20
1

Just in case it will help someone else:

        <ContentPresenter Grid.Column="2" Content="{Binding ElementName=myTreeView, Path=SelectedItem}">
            <ContentPresenter.Resources>
                <DataTemplate DataType="{x:Type local:L1ViewModel}">
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:CategoryViewModel}">
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>

                <DataTemplate DataType="{x:Type local:L3ViewModel}">
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>

                <DataTemplate DataType="{x:Type local:L4ViewModel}">
                    <StackPanel>
                         <TextBox Text="{Binding Parent.Name}" />
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>
            </ContentPresenter.Resources>
          </ContentPresenter>
Stef
  • 593
  • 3
  • 10
  • 23