【问题标题】:Add a border around all children of a TreeViewItem在 TreeViewItem 的所有子项周围添加边框
【发布时间】:2013-05-05 09:11:18
【问题描述】:

我有一个TreeView,我正在尝试实现一种样式,该样式允许我使用HierarchicalDataTemplate 在特定节点的所有子节点周围放置边框。我想要的一个例子如下所示:

以下代码是我目前所拥有的。

<HierarchicalDataTemplate DataType="{x:Type model:Node}" ItemsSource="{Binding Children, Mode=OneWay}">
     <StackPanel>
          <TextBlock Text="{Binding Name}"/>
     </StackPanel>
     <HierarchicalDataTemplate.ItemContainerStyle>
          <Style TargetType="{x:Type TreeViewItem}">
              //what goes in here???
          </Style>
     </HierarchicalDataTemplate.ItemContainerStyle>     
</HierarchicalDataTemplate>

我需要添加什么来实现我想要的边框?

【问题讨论】:

    标签: wpf xaml treeview hierarchicaldatatemplate


    【解决方案1】:

    要在TreeViewItem 的子集合周围渲染Border,我们需要修改TreeViewStyleItemContainerStyle

    TreeViewItem Style 默认使用&lt;ItemsPresenter x:Name="ItemsHost" /&gt; 来呈现其儿童内容。

    默认ItemContainerStyle中的儿童内容由

    <ItemsPresenter x:Name="ItemsHost"
                    Grid.Row="1"
                    Grid.Column="1"
                    Grid.ColumnSpan="2" />
    

    现在要对此进行测试,我有一个带有名为 Type 的 bool 的 Collection,并且当该 bool 为 True 时尝试渲染一个 Border

    所以我将ItemsPresenter 更新为

    <Border Grid.Row="1"
            Grid.Column="1"
            Grid.ColumnSpan="2"
            BorderThickness="1">
      <Border.Style>
        <Style TargetType="{x:Type Border}">
          <Setter Property="BorderBrush"
                  Value="Transparent" />
          <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,
                                           AncestorType={x:Type TreeViewItem}},
                                           Path=DataContext.Type}"
                          Value="True">
              <Setter Property="BorderBrush"
                      Value="Red" />
            </DataTrigger>
          </Style.Triggers>
        </Style>
      </Border.Style>
      <ItemsPresenter x:Name="ItemsHost"  />
    </Border>
    

    然后呈现以下内容

    您当然必须根据您自己的情况来更新上述绑定,即何时需要呈现 Border

    在我的例子中,我的 Type 变量被设置为 True,因为它是“1.1”的项目,因为它是标题内容。

    【讨论】:

    • 我将在周一返回工作岗位时尝试您的解决方案。感谢您的回答
    • 您的解决方案在每个单独的 TreeViewItem 周围放置一个边框。我需要的是整个 TreeviewItems 组的边框
    • @Kazuo ye 在您发布此图片之前,我了解您的问题,即每个项目都有边框。我已经更新了我的答案以复制您发布的图片。希望有帮助
    • 我很快就会试试这个。谢谢
    • 抱歉,我发现您的回答令人困惑。在查看最后一个代码 sn-p 时,我不知道边界在哪里。这是您的第一个代码 sn-p 中 HierarchicalDataTemplate 内的边框吗?我是否将您的新代码添加到 ItemContainerStyle?基本上我不知道写什么,写在哪里。
    【解决方案2】:

    看起来 WPF 团队认为没有人需要此功能,因此他们没有在 TreeViewItem 模板中包含任何围绕 ItemsPresenter 的边框,因此您将不得不更改 TreeViewItem 模板并在 @987654325 周围添加边框@。

    您可以通过下载 WPF 主题 XAML 字典来查看默认的 TreeViewItem 样式/模板定义。提供链接here

    这是一个完整的 XAML 工作解决方案:

    <Window x:Class="WpfApplication.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:model="clr-namespace:WpfApplication">
    
        <Window.DataContext>
            <x:ArrayExtension Type="{x:Type model:Node}">
                <model:Node Name="Root">
                    <model:Node.Children>
                        <model:Node Name="Child 1" HasChildrenBorder="True">
                            <model:Node.Children>
                                <model:Node Name="Child 1.1"/>
                                <model:Node Name="Child 1.2"/>
                                <model:Node Name="Child 1.3"/>
                            </model:Node.Children>
                        </model:Node>
                        <model:Node Name="Child 2"/>
                    </model:Node.Children>
                </model:Node>
            </x:ArrayExtension>
        </Window.DataContext>
    
        <TreeView ItemsSource="{Binding}">
    
            <TreeView.Resources>
    
                <!--This part is extracted from Areo.NormalColor.xaml WPF Theme which you can download from locations explained here: https://stackoverflow.com/questions/4158678/where-can-i-download-microsofts-standard-wpf-themes-from/4158681#4158681-->
                <PathGeometry x:Key="TreeArrow">
                    <PathGeometry.Figures>
                        <PathFigureCollection>
                            <PathFigure IsFilled="True"
                                        StartPoint="0 0"
                                        IsClosed="True">
                                <PathFigure.Segments>
                                    <PathSegmentCollection>
                                        <LineSegment Point="0 6"/>
                                        <LineSegment Point="6 0"/>
                                    </PathSegmentCollection>
                                </PathFigure.Segments>
                            </PathFigure>
                        </PathFigureCollection>
                    </PathGeometry.Figures>
                </PathGeometry>
    
                <Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
                    <Setter Property="Focusable" Value="False"/>
                    <Setter Property="Width" Value="16"/>
                    <Setter Property="Height" Value="16"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ToggleButton}">
                                <Border Width="16" 
                                        Height="16" 
                                        Background="Transparent" 
                                        Padding="5,5,5,5">
                                    <Path x:Name="ExpandPath" 
                                          Fill="Transparent" 
                                          Stroke="#FF989898" 
                                          Data="{StaticResource TreeArrow}">
                                        <Path.RenderTransform>
                                            <RotateTransform 
                                                Angle="135" 
                                                CenterX="3" 
                                                CenterY="3"/>
                                        </Path.RenderTransform>
                                    </Path>
                                </Border>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter TargetName="ExpandPath" Property="Stroke" Value="#FF1BBBFA"/>
                                        <Setter TargetName="ExpandPath" Property="Fill" Value="Transparent"/>
                                    </Trigger>
                                    <Trigger Property="IsChecked" Value="True">
                                        <Setter TargetName="ExpandPath" Property="RenderTransform">
                                            <Setter.Value>
                                                <RotateTransform 
                                                    Angle="180" 
                                                    CenterX="3" 
                                                    CenterY="3"/>
                                            </Setter.Value>
                                        </Setter>
                                        <Setter TargetName="ExpandPath" Property="Fill" Value="#FF595959"/>
                                        <Setter TargetName="ExpandPath" Property="Stroke" Value="#FF262626"/>
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
    
                <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type TreeViewItem}">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition MinWidth="19" Width="Auto"/>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition Width="Auto"/>
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition/>
                                    </Grid.RowDefinitions>
                                    <ToggleButton x:Name="Expander"
                                                  Style="{StaticResource ExpandCollapseToggleStyle}"
                                                  IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
                                                  ClickMode="Press"/>
                                    <Border Name="Bd"
                                            Grid.Column="1"
                                            Background="{TemplateBinding Background}"
                                            BorderBrush="{TemplateBinding BorderBrush}"
                                            BorderThickness="{TemplateBinding BorderThickness}"
                                            Padding="{TemplateBinding Padding}"
                                            SnapsToDevicePixels="True">
                                        <ContentPresenter x:Name="PART_Header"
                                                          ContentSource="Header"
                                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                    </Border>
                                    <Border Name="ItemsHostBd" 
                                            Grid.Row="1" 
                                            Grid.Column="1" 
                                            Grid.ColumnSpan="2">
                                        <ItemsPresenter x:Name="ItemsHost"/>
                                    </Border>
                                </Grid>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsExpanded" Value="False">
                                        <Setter TargetName="ItemsHostBd" Property="Visibility" Value="Collapsed"/>
                                    </Trigger>
                                    <Trigger Property="HasItems" Value="False">
                                        <Setter TargetName="Expander" Property="Visibility" Value="Hidden"/>
                                    </Trigger>
                                    <Trigger Property="IsSelected" Value="True">
                                        <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                                    </Trigger>
                                    <MultiTrigger>
                                        <MultiTrigger.Conditions>
                                            <Condition Property="IsSelected" Value="True"/>
                                            <Condition Property="IsSelectionActive" Value="False"/>
                                        </MultiTrigger.Conditions>
                                        <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                                    </MultiTrigger>
                                    <Trigger Property="IsEnabled" Value="False">
                                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                                    </Trigger>
    
                                    <!-- This part is customized to work with HasChildrenBorder property from data-bound object. -->
                                    <DataTrigger Binding="{Binding HasChildrenBorder}" Value="True">
                                        <Setter TargetName="ItemsHostBd" Property="BorderBrush" Value="Red"/>
                                        <Setter TargetName="ItemsHostBd" Property="BorderThickness" Value="1"/>
                                    </DataTrigger>
    
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
    
                <HierarchicalDataTemplate DataType="{x:Type model:Node}" ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Name}"/>
                </HierarchicalDataTemplate>
    
            </TreeView.Resources>
    
        </TreeView>
    </Window>
    

    Node 类的定义如下:

    using System.Collections.ObjectModel;
    
    namespace WpfApplication
    {
        public class Node
        {
            public string Name { get; set; }
            public ObservableCollection<Node> Children { get; set; }
    
            public bool HasChildrenBorder { get; set; }
    
            public Node()
            {
                this.Children = new ObservableCollection<Node>();
            }
        }
    }
    

    【讨论】:

    • 感谢您的回答,但我不希望我的课程包含与如何在 UI 中呈现相关的任何数据。在我的情况下,最好的解决方案是只有一个 xaml。
    • Property HasChildrenBorder 仅用作示例来说明该概念有效。您可以将 TreeViewItem 子项应为其加边框的任何其他属性放在那里。然后你应该在 TreeViewItem 的 ControlTemplate 中更改 DataTrigger.Binding。
    • 啊,我的错。谢谢你的回答。在另一位发帖人的帮助下,我找到了解决问题的方法。
    猜你喜欢
    • 2014-09-12
    • 2016-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多