如何更改HierarchicalDataTemplate?

时间:2017-12-03 18:54:32

标签: wpf datatrigger hierarchicaldatatemplate

如何在TreeView中通过DataTrigger更改HierarchicalDataTemplate?

<TreeView Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"
          ItemsSource="{Binding Nodes}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="IsExpanded" Value="True" />
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
            <HierarchicalDataTemplate.Triggers>
                <DataTrigger Binding="{Binding Type}" Value="group">
                    <Setter Property="Content">
                        <Setter.Value>
                            <TextBlock Text="{Binding Title}" />
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding Type}" Value="page">
                    <Setter Property="Content">
                        <Setter.Value>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding Page.Name}" />
                                <TextBlock Text="{Binding Page.Format}" />
                            </StackPanel>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </HierarchicalDataTemplate.Triggers>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

在TreeView的ItemSource中,我放置了Node对象的列表:

public class Node
{
    public string Title { get; set; }
    public Page Page { get; set; }
    public string Type { get; set; }
    public List<Node> Nodes { get; set; } = new List<Node>();
}

这就是结果:

And result

我做错了什么?

1 个答案:

答案 0 :(得分:2)

在WPF中,创建复杂内容的“正确”方法是使用模板。

我尝试了下面的XAML,但它确实有效。在内部Content="{Binding}"上绑定ContentControl的地方,只是将contentcontrol的内容绑定到父级的DataContext - 在本例中为Node对象。

您也可以通过编写两个完整的HierarchicalDataTemplates and a DataTemplateSelector来完成此操作。这将是一种更为正统的WPF方式,但这是纯粹的XAML并且非常简单。

<TreeView 
    Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"
    ItemsSource="{Binding Nodes}"
    >
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="IsExpanded" Value="True" />
        </Style>
    </TreeView.ItemContainerStyle>

    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
            <ContentControl
                x:Name="PART_ContentControl"
                Content="{Binding}"
                />
            <HierarchicalDataTemplate.Triggers>
                <DataTrigger Binding="{Binding Type}" Value="Group">
                    <Setter Property="ContentTemplate" TargetName="PART_ContentControl">
                        <Setter.Value>
                            <DataTemplate>
                                <TextBlock Text="{Binding Title}" />
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding Type}" Value="Page">
                    <Setter Property="ContentTemplate" TargetName="PART_ContentControl">
                        <Setter.Value>
                            <DataTemplate>
                                <StackPanel Orientation="Vertical">
                                    <TextBlock Text="{Binding Page.Name}" />
                                    <TextBlock Text="{Binding Page.Format}" />
                                </StackPanel>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </HierarchicalDataTemplate.Triggers>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

您会注意到Type的触发器值在我的标记中大写。我用枚举替换了你的字符串,以避免可能的错误来源:

public enum NodeType {
    Page, Group
}

public class Node
{
    public string Title { get; set; }
    public Page Page { get; set; }

    public NodeType Type { get; set; }

    public List<Node> Nodes { get; set; } = new List<Node>();
}