8

我有一个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>

我需要添加什么才能以我想要的方式实现我的边框?

4

2 回答 2

12

Border围绕 a 的子集合渲染 aTreeViewItem我们需要修改StyleforItemContainerStyleTreeView

TreeViewItem Style默认情况下使用 a<ItemsPresenter x:Name="ItemsHost" />来呈现它的子内容。

默认的儿童内容ItemContainerStyle

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

现在为了测试这个,我有一个名为 bool 的集合,Type并试图Border在这个 bool 为 True 时渲染一个

所以我更新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”的项目,因为它是标题内容。

于 2013-05-10T17:57:56.250 回答
2

看起来 WPF 团队认为没有人需要这个功能,所以他们没有ItemsPresenterTreeViewItem模板中包含任何边框,所以你将不得不更改TreeViewItem模板并在ItemsPresenter.

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

这是工作解决方案的完整 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>();
        }
    }
}
于 2013-05-19T23:00:18.380 回答