【问题标题】:Highlight whole TreeViewItem line in WPF在 WPF 中突出显示整个 TreeViewItem 行
【发布时间】:2010-10-14 11:00:31
【问题描述】:

如果我设置 TreeViewItem 背景,它只会突出显示标题。如何突出显示整行?

我发现一个帖子几乎解决了一个问题http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/b04f73e2-0b10-4d97-a6da-64df2e30c21d/

但是有一些问题: 1.不突出整行 2. 树在 Vista 上具有 XP 风格。我希望它在 Vista 上看起来和原来一样,但是如果用户将主题更改为 XP - 它应该是 XP 方式。 3. 这么多 XAML...

任何想法,我应该寻找什么?

【问题讨论】:

    标签: wpf templates treeviewitem


    【解决方案1】:

    我们来了,第三次魅力。如果你想要这样的东西。

    这需要更多的工作。我确信有很多方法可以做到这一点,但是这种方法使用 Length Converter 和 TreeViewItem 扩展方法来获取深度。这两者都与 TreeViewItem 可视化树紧密耦合,因此如果您开始弄乱模板,那么您可能会遇到麻烦。同样,这里是重要的部分,下面是完整的代码。

    <ControlTemplate TargetType="{x:Type TreeViewItem}">
      <ControlTemplate.Resources>
          <local:LeftMarginMultiplierConverter Length="19" x:Key="lengthConverter" />
      </ControlTemplate.Resources>
      <StackPanel>
            <Border Name="Bd"
              Background="{TemplateBinding Background}"
              BorderBrush="{TemplateBinding BorderBrush}"
              BorderThickness="{TemplateBinding BorderThickness}"
              Padding="{TemplateBinding Padding}">
                <Grid Margin="{Binding Converter={StaticResource lengthConverter},
                        RelativeSource={RelativeSource TemplatedParent}}">
    
                    <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>
          <ItemsPresenter x:Name="ItemsHost" />
        </StackPanel>
        <!-- Triggers -->
    </ControlTemplate>
    

    TreeViewDepth 扩展

    public static class TreeViewItemExtensions
    {
        public static int GetDepth(this TreeViewItem item)
        {
            TreeViewItem parent;
            while ((parent = GetParent(item)) != null)
            {
                return GetDepth(parent) + 1;
            }
            return 0;
        }
    
        private static TreeViewItem GetParent(TreeViewItem item)
        {
            var parent = VisualTreeHelper.GetParent(item);
            while (!(parent is TreeViewItem || parent is TreeView))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
            return parent as TreeViewItem;
        }
    }
    

    LeftMarginMultiplierConverter

    public class LeftMarginMultiplierConverter : IValueConverter
    {
        public double Length { get; set; }
    
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var item = value as TreeViewItem;
            if (item == null)
                return new Thickness(0);
    
            return new Thickness(Length * item.GetDepth(), 0, 0, 0);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }
    

    控制

    <TreeView Margin="50" HorizontalContentAlignment="Stretch">
        <TreeViewItem Header="test2"/>
        <TreeViewItem Header="test2">
            <TreeViewItem Header="sub test">
                <TreeViewItem Header="sub test1-1"/>
                <TreeViewItem Header="sub test1-2"/>
            </TreeViewItem>
            <TreeViewItem Header="sub test2"/>
        </TreeViewItem>
        <TreeViewItem Header="test3"/>
    </TreeView>
    

    完整的 TreeViewItem 样式

    <SolidColorBrush x:Key="GlyphBrush" Color="#444" />
    
    <!--=================================================================
         TreeViewItem
      ==================================================================-->
    <Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
      <Setter Property="Focusable" Value="False"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="ToggleButton">
            <Grid
              Width="15"
              Height="13"
              Background="Transparent">
              <Path x:Name="ExpandPath"
                HorizontalAlignment="Left" 
                VerticalAlignment="Center" 
                Margin="1,1,1,1"
                Fill="{StaticResource GlyphBrush}"
                Data="M 4 0 L 8 4 L 4 8 Z"/>
            </Grid>
            <ControlTemplate.Triggers>
              <Trigger Property="IsChecked"
                   Value="True">
                <Setter Property="Data"
                    TargetName="ExpandPath"
                    Value="M 0 4 L 8 4 L 4 8 Z"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    <Style x:Key="TreeViewItemFocusVisual">
      <Setter Property="Control.Template">
        <Setter.Value>
          <ControlTemplate>
            <Border>
              <Rectangle Margin="0,0,0,0"
                     StrokeThickness="5"
                     Stroke="Black"
                     StrokeDashArray="1 2"
                     Opacity="0"/>
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    
    
    <Style x:Key="{x:Type TreeViewItem}"
         TargetType="{x:Type TreeViewItem}">
      <Setter Property="Background"
          Value="Transparent"/>
      <Setter Property="HorizontalContentAlignment"
          Value="{Binding Path=HorizontalContentAlignment,
                  RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
      <Setter Property="VerticalContentAlignment"
          Value="{Binding Path=VerticalContentAlignment,
                  RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
      <Setter Property="Padding"
          Value="1,0,0,0"/>
      <Setter Property="Foreground"
          Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
      <Setter Property="FocusVisualStyle"
          Value="{StaticResource TreeViewItemFocusVisual}"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type TreeViewItem}">
            <ControlTemplate.Resources>
                <local:LeftMarginMultiplierConverter Length="19" x:Key="lengthConverter" />
            </ControlTemplate.Resources>
            <StackPanel>
            <Border Name="Bd"
                  Background="{TemplateBinding Background}"
                  BorderBrush="{TemplateBinding BorderBrush}"
                  BorderThickness="{TemplateBinding BorderThickness}"
                  Padding="{TemplateBinding Padding}">
                <Grid Margin="{Binding Converter={StaticResource lengthConverter},
                                  RelativeSource={RelativeSource TemplatedParent}}">
                <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>
              <ItemsPresenter x:Name="ItemsHost" />
            </StackPanel>
            <ControlTemplate.Triggers>
              <Trigger Property="IsExpanded"
                   Value="false">
                <Setter TargetName="ItemsHost"
                    Property="Visibility"
                    Value="Collapsed"/>
              </Trigger>
              <Trigger Property="HasItems"
                   Value="false">
                <Setter TargetName="Expander"
                    Property="Visibility"
                    Value="Hidden"/>
              </Trigger>
              <MultiTrigger>
                <MultiTrigger.Conditions>
                  <Condition Property="HasHeader"
                         Value="false"/>
                  <Condition Property="Width"
                         Value="Auto"/>
                </MultiTrigger.Conditions>
                <Setter TargetName="PART_Header"
                    Property="MinWidth"
                    Value="75"/>
              </MultiTrigger>
              <MultiTrigger>
                <MultiTrigger.Conditions>
                  <Condition Property="HasHeader"
                         Value="false"/>
                  <Condition Property="Height"
                         Value="Auto"/>
                </MultiTrigger.Conditions>
                <Setter TargetName="PART_Header"
                    Property="MinHeight"
                    Value="19"/>
              </MultiTrigger>
              <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>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    

    【讨论】:

    • 就是这样!非常感谢您的所有帖子!
    • 很好的答案。 +1 非常感谢。
    • 太棒了!然而,我确实注意到了一个问题,如果树视图是使用分层模板创建的,其中Parent 属性未在TreeViewItem 上设置,则深度计算不正确。我已经编辑了答案,改为使用可视化树来找出解决问题的父级(至少对我而言),如果您有任何异议,请随时回滚。
    • 如何更改页边距?
    • 无论出于何种原因,我的编辑被拒绝了,但在 GetParent 方法中,还需要检查 parent == null 是否因为 TreeViewItem 的父级有时在适当的 TreeView 中可能为 null,但在窗口范围之外不可见时,因此此编辑可防止 ArgumentNullException: ... while (!(parent == null || parent is TreeViewItem || parent is TreeView)) ...
    【解决方案2】:

    TreeViewItem Header 不会拉伸?

    出现此问题的原因是 WPF 的 TreeViewItem 的默认模板设置为 2 行 Grid 的 3 列。第一行是“标题”(实际上是Border),第二行是ItemsPresenter。这两行根据需要变为可见或隐藏,以便在单击小三角形时完成树扩展 - 它占据了 Grid 的第 0 列。

    这两行实际上只需要额外的一列。例如,在第二行中,我们必须在 col-0、row-1 处没有任何内容,因为当IsExpanded 为真时,该空白部分应该缩进。但是,当我们注意到位于 col-1, row-1 中的 ItemsPresenter 指定 Grid.ColumnSpan=2 时,谜团就开始了。

    不幸的是,在第一行,保存标题的Border 设置为Grid.Column=1...但没有ColumnSpan。由于Grid 的col-2 有Width=*,这意味着标题/边框不会水平拉伸。

    换句话说,我认为 3 列网格设计除了专门防止标题拉伸之外没有其他目的。据我所知,一个简单的 2x2 排列会更灵活 [编辑:参见脚注 #2],并通过常规支持完全拉伸 '锯齿状' 标题非拉伸WPF 对齐机制。

    理想情况下,我们会将 Grid 更改为只有 2 列而不是 3 列。因为这并不容易,所以我们将 使标题跨 2 列,就像ItemsPresenter 一样。

    好的,这是一个小型、完整、独立(仅 XAML)的工作程序,它演示并修复了问题:

    <Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/netfx/2007/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:r="clr-namespace:System.Reflection;assembly=mscorlib"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Width="800" SizeToContent="Manual">
    
      <TreeView ItemsSource="{Binding Source={StaticResource data}}"
                VirtualizingStackPanel.VirtualizationMode="Recycling"
                VirtualizingStackPanel.IsVirtualizing="True"
                VirtualizingPanel.ScrollUnit="Item">
    
        <TreeView.Resources>
            <ObjectDataProvider x:Key="data" ObjectInstance="{x:Static sys:AppDomain.CurrentDomain}" MethodName="GetAssemblies" />
    
            <HierarchicalDataTemplate DataType="{x:Type r:Assembly}" ItemsSource="{Binding Path=DefinedTypes}" >
                <TextBlock Text="{Binding Path=Location}" />
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type sys:Type}" ItemsSource="{Binding Path=CustomAttributes}">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type r:CustomAttributeData}" ItemsSource="{Binding Path=ConstructorArguments}">
                <TextBlock Text="{Binding Path=AttributeType.Name}" />
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
    
                <!-- == == BEGIN HERE == == -->
                <Style.Resources>
                    <Style TargetType="{x:Type Border}">
                        <Setter Property="Grid.ColumnSpan" Value="2" />
                    </Style>
                </Style.Resources>
                <!-- == == == END == == == -->
    
                <Setter Property="Background" Value="LightBlue" />
    
            </Style>
        </TreeView.ItemContainerStyle>
      </TreeView>
    </Window>
    

    如果您如图所示运行此程序,您将看到类似这样的内容。这是改变(修改)的行为,它允许您重新完全控制TreeViewItem 标头的拉伸行为:

    请注意 XAML 源代码中带有虚线的 BEGIN/END 部分。基本上,我只是在有问题的Border 上设置了Grid.ColumnSpan=2,这样它就会填充Grid 的拉伸宽度。该元素由TreeViewItem 模板发出,因此我发现更改其属性的有效方法是通过TreeViewItemStyle资源字典 中的目标Style .是的,令人困惑。通过TreeViewItem.ItemContainerStyle 访问Style

    要查看(现有)损坏的行为,您可以注释掉虚线之间的部分:

    您也可以在一些资源字典中设置这些样式,而不是像我在这里那样使用ItemContainerStyle 属性。我这样做是因为它最小化了修复的范围,因此不相关的Border 控件不会受到影响。如果您确实需要一种更具辨别力的方法来仅针对此控件,则可以利用它具有 Name='Bd' 的事实。


    [edit:] 这个解决方案使用反射! 不要被无意义的演示数据吓到——它与这个问题无关;这只是为了演示目的而获取一些分层数据的最简单方法,同时保持整个程序很小。


    [edit #2:] 我刚刚意识到设计师试图通过 3x2 网格排列来避免以下难看的效果(此处通过放大的屏幕截图夸大了)。因此,如果您采用此页面中的一种解决方案,请注意您可能不希望这样:

    【讨论】:

    • 如果不需要选区扩展到左边距,这是一个很好的轻量级解决方案。
    • 很好的答案。你节省了我的时间。
    【解决方案3】:

    如果你的意思是这样的截图


    (来源:bendewey.com

    更新 如前所述,此示例的缺点是在子项上缩进


    (来源:bendewey.com

    那么这应该对您有所帮助。它还基于http://msdn.microsoft.com/en-us/library/ms788727.aspx,您可以将 TreeViewItem 的模板更改为 StackPanel,并将 ItemsPanel 的左边距设置为 19。然后在 TreeView 中设置 Horizo​​ntalContentAlignment="Stretch"。我在下面附上了整个资源,但这是重要的部分。

    <ControlTemplate TargetType="{x:Type TreeViewItem}">
    <StackPanel>
        <Border Name="Bd"
          Background="{TemplateBinding Background}"
          BorderBrush="{TemplateBinding BorderBrush}"
          BorderThickness="{TemplateBinding BorderThickness}"
          Padding="{TemplateBinding Padding}">
            <Grid>
            <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>
      <ItemsPresenter x:Name="ItemsHost" Margin="19,0,0,0" />
    </StackPanel>
    <!-- Triggers -->
    </ControlTemplate>
    

    控制

    <TreeView Margin="50" HorizontalContentAlignment="Stretch">
        <TreeViewItem Header="test2"/>
        <TreeViewItem Header="test2">
            <TreeViewItem Header="sub test"/>
            <TreeViewItem Header="sub test2"/>
        </TreeViewItem>
        <TreeViewItem Header="test3"/>
    </TreeView>
    

    资源

    <SolidColorBrush x:Key="GlyphBrush" Color="#444" />
    
    <!--=================================================================
          TreeViewItem
      ==================================================================-->
    <Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
      <Setter Property="Focusable" Value="False"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="ToggleButton">
            <Grid
              Width="15"
              Height="13"
              Background="Transparent">
              <Path x:Name="ExpandPath"
                HorizontalAlignment="Left" 
                VerticalAlignment="Center" 
                Margin="1,1,1,1"
                Fill="{StaticResource GlyphBrush}"
                Data="M 4 0 L 8 4 L 4 8 Z"/>
            </Grid>
            <ControlTemplate.Triggers>
              <Trigger Property="IsChecked"
                   Value="True">
                <Setter Property="Data"
                    TargetName="ExpandPath"
                    Value="M 0 4 L 8 4 L 4 8 Z"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    <Style x:Key="TreeViewItemFocusVisual">
      <Setter Property="Control.Template">
        <Setter.Value>
          <ControlTemplate>
            <Border>
              <Rectangle Margin="0,0,0,0"
                     StrokeThickness="5"
                     Stroke="Black"
                     StrokeDashArray="1 2"
                     Opacity="0"/>
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    
    
    <Style x:Key="{x:Type TreeViewItem}"
         TargetType="{x:Type TreeViewItem}">
      <Setter Property="Background"
          Value="Transparent"/>
      <Setter Property="HorizontalContentAlignment"
          Value="{Binding Path=HorizontalContentAlignment,
                  RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
      <Setter Property="VerticalContentAlignment"
          Value="{Binding Path=VerticalContentAlignment,
                  RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
      <Setter Property="Padding"
          Value="1,0,0,0"/>
      <Setter Property="Foreground"
          Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
      <Setter Property="FocusVisualStyle"
          Value="{StaticResource TreeViewItemFocusVisual}"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type TreeViewItem}">
            <StackPanel>
                <Border Name="Bd"
                  Background="{TemplateBinding Background}"
                  BorderBrush="{TemplateBinding BorderBrush}"
                  BorderThickness="{TemplateBinding BorderThickness}"
                  Padding="{TemplateBinding Padding}">
                <Grid>
                    <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>
              <ItemsPresenter x:Name="ItemsHost" Margin="19,0,0,0" />
            </StackPanel>
            <ControlTemplate.Triggers>
              <Trigger Property="IsExpanded"
                   Value="false">
                <Setter TargetName="ItemsHost"
                    Property="Visibility"
                    Value="Collapsed"/>
              </Trigger>
              <Trigger Property="HasItems"
                   Value="false">
                <Setter TargetName="Expander"
                    Property="Visibility"
                    Value="Hidden"/>
              </Trigger>
              <MultiTrigger>
                <MultiTrigger.Conditions>
                  <Condition Property="HasHeader"
                         Value="false"/>
                  <Condition Property="Width"
                         Value="Auto"/>
                </MultiTrigger.Conditions>
                <Setter TargetName="PART_Header"
                    Property="MinWidth"
                    Value="75"/>
              </MultiTrigger>
              <MultiTrigger>
                <MultiTrigger.Conditions>
                  <Condition Property="HasHeader"
                         Value="false"/>
                  <Condition Property="Height"
                         Value="Auto"/>
                </MultiTrigger.Conditions>
                <Setter TargetName="PART_Header"
                    Property="MinHeight"
                    Value="19"/>
              </MultiTrigger>
              <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>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    

    【讨论】:

    • 谢谢!但是,如果您转到子节点,您会注意到切换左侧的空白。我想选择FULL line。伪解是:ItemsPresenter.margin="0",ColumnDefinition Width="19 * Level"。我尝试使用 MarkupExension 来计算 Level - 没有运气。有什么想法吗?
    【解决方案4】:

    这是迄今为止最简单的解决方案。只需创建一个矩形,将其命名为 Hb,并将其边距设置为 -100 像素且不可见。仅当您选择它或将鼠标悬停时才将其设置为可见。这是一个 hack,但您最多可以使用 5 层嵌套的 TreeViewItems (100 > 19*5)

         <ControlTemplate TargetType="{x:Type TreeViewItem}">
      <Grid>
       <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="19" Width="Auto"/>
        <ColumnDefinition Width="*"/>
       </Grid.ColumnDefinitions>
       <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
       </Grid.RowDefinitions>
                            <ToggleButton x:Name="Expander" Style="{StaticResource ExpandCollapseToggleStyle}" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press" VerticalAlignment="Top" Panel.ZIndex="1"/>
       <Rectangle x:Name="Hb" Width="Auto" Height="Auto" Grid.ColumnSpan="2" Margin="-100,0,0,0" Panel.ZIndex="-1" Visibility="Hidden" />
                            <Border x:Name="Bd" SnapsToDevicePixels="true" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Grid.Column="1" Panel.ZIndex="0">
        <ContentPresenter x:Name="PART_Header" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header" HorizontalAlignment="Stretch"/>
       </Border>
       <ItemsPresenter x:Name="ItemsHost" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Margin="19,0,0,0"/>
      </Grid>
    

    【讨论】:

      【解决方案5】:

      如果你的意思是这样的截图


      (来源:bendewey.com

      那么这应该对您有所帮助。它基于http://msdn.microsoft.com/en-us/library/ms788727.aspx,您可以对 TreeViewItem 的网格布局进行一些更改。基本上你删除第三列。然后在 TreeView 中设置 Horizo​​ntalContentAlignment="Stretch"。我在下面附上了整个资源,但这是重要的部分。

      <!-- ... -->
      <ControlTemplate TargetType="{x:Type TreeViewItem}">
        <Grid>
          <Grid.ColumnDefinitions>
            <ColumnDefinition MinWidth="19"
                      Width="Auto"/>
            <ColumnDefinition Width="*"/>
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <!-- ... -->
      

      控制

      <TreeView Margin="50" HorizontalContentAlignment="Stretch">
          <TreeViewItem Header="test2"/>
          <TreeViewItem Header="test2">
              <TreeViewItem Header="sub test"/>
              <TreeViewItem Header="sub test2"/>
          </TreeViewItem>
          <TreeViewItem Header="test3"/>
      </TreeView>
      

      资源

      <SolidColorBrush x:Key="GlyphBrush" Color="#444" />
      
      <!--=================================================================
         TreeViewItem
      ==================================================================-->
      <Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
        <Setter Property="Focusable" Value="False"/>
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="ToggleButton">
              <Grid
                Width="15"
                Height="13"
                Background="Transparent">
                <Path x:Name="ExpandPath"
                  HorizontalAlignment="Left" 
                  VerticalAlignment="Center" 
                  Margin="1,1,1,1"
                  Fill="{StaticResource GlyphBrush}"
                  Data="M 4 0 L 8 4 L 4 8 Z"/>
              </Grid>
              <ControlTemplate.Triggers>
                <Trigger Property="IsChecked"
                     Value="True">
                  <Setter Property="Data"
                      TargetName="ExpandPath"
                      Value="M 0 4 L 8 4 L 4 8 Z"/>
                </Trigger>
              </ControlTemplate.Triggers>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
      <Style x:Key="TreeViewItemFocusVisual">
        <Setter Property="Control.Template">
          <Setter.Value>
            <ControlTemplate>
              <Border>
                <Rectangle Margin="0,0,0,0"
                       StrokeThickness="5"
                       Stroke="Black"
                       StrokeDashArray="1 2"
                       Opacity="0"/>
              </Border>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
      
      
      <Style x:Key="{x:Type TreeViewItem}"
           TargetType="{x:Type TreeViewItem}">
        <Setter Property="Background"
            Value="Transparent"/>
        <Setter Property="HorizontalContentAlignment"
            Value="{Binding Path=HorizontalContentAlignment,
                    RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="VerticalContentAlignment"
            Value="{Binding Path=VerticalContentAlignment,
                    RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="Padding"
            Value="1,0,0,0"/>
        <Setter Property="Foreground"
            Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="FocusVisualStyle"
            Value="{StaticResource TreeViewItemFocusVisual}"/>
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="{x:Type TreeViewItem}">
              <Grid>
                <Grid.ColumnDefinitions>
                  <ColumnDefinition MinWidth="19"
                            Width="Auto"/>
                  <ColumnDefinition Width="*"/>
                </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}">
                  <ContentPresenter x:Name="PART_Header"
                            ContentSource="Header"
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
                </Border>
                <ItemsPresenter x:Name="ItemsHost"
                        Grid.Row="1"
                        Grid.Column="1"/>
              </Grid>
              <ControlTemplate.Triggers>
                <Trigger Property="IsExpanded" Value="false">
                  <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/>
                </Trigger>
                <Trigger Property="HasItems" Value="false">
                  <Setter TargetName="Expander" Property="Visibility" Value="Hidden"/>
                </Trigger>
                <MultiTrigger>
                  <MultiTrigger.Conditions>
                    <Condition Property="HasHeader" Value="false"/>
                    <Condition Property="Width" Value="Auto"/>
                  </MultiTrigger.Conditions>
                  <Setter TargetName="PART_Header" Property="MinWidth" Value="75"/>
                </MultiTrigger>
                <MultiTrigger>
                  <MultiTrigger.Conditions>
                    <Condition Property="HasHeader" Value="false"/>
                    <Condition Property="Height" Value="Auto"/>
                  </MultiTrigger.Conditions>
                  <Setter TargetName="PART_Header" Property="MinHeight" Value="19"/>
                </MultiTrigger>
                <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>
              </ControlTemplate.Triggers>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
      

      【讨论】:

      • 谢谢你,本德威。但是您的解决方案在切换后突出显示了行。我希望它突出整条线。似乎模板中的 Grid 不允许这样做,您不知道任何其他解决方案吗?
      • 绝对有可能。今晚晚些时候我可以为你重写一些东西。但基本上你会想要将其从网格更改为堆栈面板,然后将扩展器图标放在边框内。您还必须更改触发器。
      • 那太好了!由于我不清楚,如果使用 StackPanel 之类的东西,我们如何在没有 c# 的情况下缩进节点。
      • 使用堆栈面板缩进节点我会使用左边距
      【解决方案6】:

      TreeView 与 ItemsSource 一起使用时问题的根源是,引用自 link text,我更改了 TreeViewItemExtensions 类的一些代码:

      public static class TreeViewItemExtensions
      {
          public static int GetDepth(this TreeViewItem item)
          {
              while (GetSelectedTreeViewItemParent(item) != null)
              {
                  var parent = GetSelectedTreeViewItemParent(item);
                  if (parent != null)
                      return parent.GetDepth() + 1;
      
                  item = parent;
              }
              return 0;
       }
      
       public static TreeViewItem GetSelectedTreeViewItemParent(this TreeViewItem item)
       {
              DependencyObject parent = VisualTreeHelper.GetParent(item);
              while (!(parent is TreeViewItem || parent is TreeView))
              {
                  parent = VisualTreeHelper.GetParent(parent);
              }
      
              return parent as TreeViewItem;
        }
      }
      

      【讨论】:

      • 这是一个嵌套循环吗?似乎没有必要
      【解决方案7】:

      使用了 theseven7 之类的东西来促进将 Bendewey 的代码与模板化的 TreeViewItems 一起使用...

          public static int GetDepth(this TreeViewItem item)
          {
              FrameworkElement elem = item;
              var parent = VisualTreeHelper.GetParent(item);
              var count = 0;
              while (parent != null && !(parent is TreeView))
              {
                  var tvi = parent as TreeViewItem;
                  if (parent is TreeViewItem)
                      count++;
                  parent = VisualTreeHelper.GetParent(parent);
              }
              return count;
          }
      

      【讨论】:

        【解决方案8】:

        对于仅 XAML 的方法,我采用了 Bendewey 的一种解决方案并将其分解为更基本的解决方案:

        下面的样式应该允许 Treeview 项目跨越:

        <Style TargetType="{x:Type TreeViewItem}">           
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TreeViewItem}">                    
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition MinWidth="19"
                          Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>
                            <ToggleButton x:Name="Expander"
                      Content="..." 
                      IsChecked="{Binding Path=IsExpanded,
                                  RelativeSource={RelativeSource TemplatedParent}}"
                      ClickMode="Press"/>
                            <Border Name="Bd" Grid.Column="1" Background="Red" Padding="3">
                                <ContentPresenter x:Name="PART_Header"   ContentSource="Header"
                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
                            </Border>
                            <ItemsPresenter x:Name="ItemsHost"  Grid.Row="1"   Grid.Column="1"/>
                        </Grid>  
              <!-- ADD TRIGGERS HERE -->                                  
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        

        为了让它像正确的 Treeview 一样操作和折叠,下面的触发器应该允许这样做:

        <ControlTemplate.Triggers>                                          
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="HasHeader" Value="false"/>
                                    <Condition Property="Width" Value="Auto"/>
                                </MultiTrigger.Conditions>                            
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="HasHeader" Value="false"/>
                                    <Condition Property="Height" Value="Auto"/>
                                </MultiTrigger.Conditions>                          
                            </MultiTrigger>                        
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected" Value="true"/>
                                    <Condition Property="IsSelectionActive" Value="false"/>
                                </MultiTrigger.Conditions>                                             
                            </MultiTrigger>
                            <Trigger Property="IsSelected" Value="true">
                                <Setter TargetName="Bd" Property="Background" Value="Blue"/>                           
                            </Trigger>
                            <Trigger Property="HasItems" Value="false">
                                <Setter TargetName="Expander" Property="Visibility" Value="Hidden"/>
                            </Trigger>
                            <Trigger Property="IsExpanded"   Value="false">
                                <Setter TargetName="ItemsHost"
                                        Property="Visibility"
                                        Value="Collapsed"/>
                            </Trigger>
        </ControlTemplate.Triggers> 
        

        只需将触发器嵌套在控制模板中。颜色/填充/设计需要根据您自己的需要进行调整,但以上内容应该是仅基于 XAML 的一个非常基本的想法。

        【讨论】:

          【解决方案9】:

          我通过使用 blend 复制 ItemContainerStyle 来管理这个,为放置项目的网格命名,然后设置网格的背景。

          【讨论】:

          • 马克,你能举个例子吗?那将非常有帮助。这些其他答案看起来过于复杂。
          • 这不会像 OP 要求的那样将网格扩展到 TreeView 控件的左侧。
          猜你喜欢
          • 1970-01-01
          • 2013-09-24
          • 1970-01-01
          • 2011-03-03
          • 2014-08-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多