WPF Tree Datatemplate Depending on Type of Item

2019-02-26 01:16发布

问题:

I have a MVVM WPF application with a tree containing self referenced data, this data is bound to the tree with a hierarchical converter. (As in example: http://www.telerik.com/help/wpf/radtreeview-how-to-bind-to-self-referencing-data.html)

This data includes ID, ParentID, Text and Type (and more).

Example Data:

1,0,"FirstItem","Triangle"
2,1,"SubItem1","Circle"
3,1,"SubItem2","Square"
4,2,"SubItem11","Triangle"
5,2,"SubItem12","Heart"
6,3,"SubItem21","Circle"

Now I would like to have different templates for the Triangles, Hearts, Circles and Squares. I dont mean only change a Image, but really a Template. How can i accomplish such?

Kind regards, Paul.

回答1:

If your ItemsSource is made up of different Types, then you can simply create HierarchicalDataTemplates and not assign an x:Key. If there is no x:Key attribute for a DataTemplate, the framework will use this DataTemplate when it comes across the type and tries to visually display it (you can read more about implicit DataTemplates here). For example, if you have a type Circle and another type Square, you would have the following templates in your Resources:

<Window.Resources>
    <HierarchicalDataTemplate DataType="{x:Type local:Circle}" ItemsSource="{Binding Children}">
        <Ellipse Fill="{Binding Fill}" Width="25" Height="25" Stroke="Black" StrokeThickness="0.25"/>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate DataType="{x:Type local:Square}" ItemsSource="{Binding Children}">
        <Rectangle Fill="{Binding Fill}" Width="25" Height="25" Stroke="Black" StrokeThickness="0.25"/>
    </HierarchicalDataTemplate>
</Window.Resources>

Then if your TreeView encounters one of these Types in its ItemsSource, it will use the HierarchicalDataTemplate for that specific type.

You can read more about HierarchicalDataTemplates here, and this link has an example of how they are used in a TreeView.

OR

If your items are all the same Type, and only differentiated by a property (such as Type), you'll need to use a DataTemplateSelector. Here is a simple example of one:

codebehind:

public class ShapeTemplateSelector : DataTemplateSelector
{
    public DataTemplate CircleTemplate { get; set; }
    public DataTemplate SquareTemplate { get; set; }
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        Shape shape = item as Shape;
        if (shape != null)
        {
            if (shape.Type == "Circle")
                return this.CircleTemplate;
            else if (shape.Type == "Square")
                return this.SquareTemplate;
            }
            return null;
        }
}

And XAML:

<local:ShapeTemplateSelector x:Key="shapeSelector">
    <local:ShapeTemplateSelector.CircleTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:Shape}" ItemsSource="{Binding Children}">
            <Ellipse Fill="{Binding Fill}" Width="25" Height="25" Stroke="Black" StrokeThickness="0.25"/>
        </HierarchicalDataTemplate>
    </local:ShapeTemplateSelector.CircleTemplate>
    <local:ShapeTemplateSelector.SquareTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:Shape}" ItemsSource="{Binding Children}">
            <Rectangle Fill="{Binding Fill}" Width="25" Height="25" Stroke="Black" StrokeThickness="0.25"/>
        </HierarchicalDataTemplate>
    </local:ShapeTemplateSelector.SquareTemplate>
</local:ShapeTemplateSelector>

Then in your TreeView, you simply assign the selector

<TreeView x:Name="Tree" ItemsSource="{Binding Shapes}" ItemTemplateSelector="{DynamicResource shapeSelector}"/>


回答2:

If you have actual different types, you can specify the type in the HierarchicalDataTemplate using DataType attribute (How do I use the DataType property on a WPF DataTemplate?) and WPF will select the template based on the class.

If you don't have different types, but will depend on a property or value inside the class, you'll need to specify a DataTemplateSelector (http://tech.pro/tutorial/807/wpf-tutorial-how-to-use-a-datatemplateselector)



标签: c# wpf mvvm