在WPF中的HierarchicalDataTemplate中如何获取TreeViewItem的父项

5

我正在合并两个在互联网上找到的示例。一个是关于拉伸选择样式,另一个是关于树形多选

除了树形视图的缩进之外,我已经让所有代码正常运行。我可以提供所有代码,但那样解决不了问题。

我的问题出现在以下方法中:

public static class TreeViewItemExtensions
{
    public static int GetDepth(this TreeViewItem item)
    {
        FrameworkElement elem = item;
        while (elem.Parent != null)
        {
            var tvi = elem.Parent as TreeViewItem;
            if (tvi != null)
                return tvi.GetDepth() + 1;
            elem = elem.Parent as FrameworkElement;
        }
        return 0;
    }
}

该方法试图检索树中TreeViewItem的深度。问题在于:elem.Parent始终为null,这导致深度为0。

我认为这是因为我正在使用HierarchicalDataTemplate。我的xaml的一部分如下所示。

<TreeView Name="folderTree"
          ItemsSource="{Binding Folders}"
          SelectedItemChanged="folderTree_SelectedItemChanged"
          HorizontalContentAlignment="Stretch">

    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Folders}"
                                  DataType="{x:Type Model:IFolder}">

            <StackPanel Orientation="Horizontal">
                <StackPanel.Style>
                    <Style TargetType="{x:Type StackPanel}">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding IsSelected}"
                                         Value="True">
                                <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </StackPanel.Style>

                <Image Source="{Binding Converter={StaticResource iconConverter}}" Height="{Binding ElementName=theFile,Path=ActualHeight}"/>
                <TextBlock Text="{Binding FileName}" Name="theFile"/>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

我的树形视图样式的XAML如下:
<Style x:Key="{x:Type TreeViewItem}" TargetType="{x:Type TreeViewItem}">

    <!-- leaving some stuff out here -->

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TreeViewItem}">

                <ControlTemplate.Resources>
                    <local:LeftMarginMultiplierConverter Length="19" x:Key="lengthConverter" />
                </ControlTemplate.Resources>

                <StackPanel>
                    <!-- The upper part of the TreeViewItem -->
                    <Border Name="Bd" 
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Padding="{TemplateBinding Padding}">

                        <!-- The margin is what we try to measure, how can we get the parents from the templatedParents? -->
                        <Grid Margin="{Binding Converter={StaticResource lengthConverter}, 
                                               RelativeSource={RelativeSource TemplatedParent}, 
                                               Path=.}">

                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="19" />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>

                            <ToggleButton x:Name="Expander" 
                                          Style="{StaticResource ExpandCollapseToggleStyle}"
                                          IsChecked="{Binding Path=IsExpanded, 
                                                      RelativeSource={RelativeSource TemplatedParent}}"
                                          ClickMode="Press"/>

                            <ContentPresenter x:Name="PART_Header"
                                              Grid.Column="1"
                                              ContentSource="Header"
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
                        </Grid>
                    </Border>

                    <!-- the children of the TreeViewItem -->
                    <ItemsPresenter x:Name="ItemsHost" />
                </StackPanel>

                <!-- leaving some stuff out here with triggers -->

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如何让HierarchicalDataTemplate填充Parent属性?
1个回答

7
我建议您扫描可视树来解决这个问题。
以下是一个简单(甚至不太优雅)的解决方案:
public static class TreeViewItemExtensions
{
    public static int GetDepth(this TreeViewItem item)
    {
        DependencyObject target = item;
        var depth = 0;
        while (target != null)
        {
            if (target is TreeView)
                return depth;
            if (target is TreeViewItem)
                depth++;

            target = VisualTreeHelper.GetParent(target);
        }
        return 0;
    }
}

欢呼。

我见过这个。但通常我将 TreeViewItem 添加到树中时,为什么会有父子关系呢? - Marnix
这里有另一篇关于DataTemplate中Parent属性的帖子: https://dev59.com/Bk_Sa4cB1Zd3GeqP9Bfy 然而,即使是扫描可视树也不是最好的方法。最可靠的方法是从模型中获取深度,因为树是分层模型的可视表示。可视树可能不可靠。例如,考虑您的层次结构的过滤视图:可视化会发生变化,但深度保持不变。 - Mario Vernari
是的,把它放在模型中似乎更容易,但我该如何在我的样式中指定呢?我参考的第一个教程覆盖了树视图的默认样式。如何在样式中使用模型? - Marnix
抱歉,我理解有误。逻辑深度应该在模型中计算,而视觉深度仅能依赖于视觉层。上述功能是否与所提供的示例转换器兼容? - Mario Vernari
@MarioVernari 让我们在聊天室里继续这个讨论 - Marnix
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接