【问题标题】:Adjust dropdown arrow margin of WPF TreeView调整 WPF TreeView 的下拉箭头边距
【发布时间】:2017-09-28 03:03:28
【问题描述】:

我有一个TreeView,它的简化定义为

<TreeView ItemsSource="{Binding TreeItems}">
    <TreeView.Resources>
        <DataTemplate DataType="{x:Type models:MyModel}">
            <Border Margin="{Binding Margin}" >
                 <Grid>
                     <TextBlock Text="{Binding Path=Name}" Margin="3,3,3,3" />
                 </Grid>
            </Border>
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

看起来像这样

正如您所见,由于 Margin 是可变的,因此项目之间存在空间。问题是下拉箭头。它不以元素为中心。好吧,它以忽略边距的元素为中心。如何调整箭头?

【问题讨论】:

  • 箭头的位置在 TreeViewItem 模板中设置。尝试为 TreeViewItem 制作自定义控件模板example here
  • 能否请您提供一些可用于重现您的问题的示例数据?你说边距“是可变的”是什么意思?
  • 边距是呈现为 TreeViewItem 的对象的属性。在图片中,您可以看到所有项目的 Margin 并不总是相同。有时项目之间的差距更大。
  • 添加示例数据并不容易,因为它都来自数据库。
  • 创建您自己的不来自数据库的示例数据:stackoverflow.com/help/mcve

标签: c# wpf xaml treeview


【解决方案1】:

您的 XAML 标记既不完整也不正确:DataTemplate 应该是 HierarchicalDataTemplate 并且应该放在 &lt;TreeView.ItemTemplate&gt; 标记中。 这在您的编辑后不适用。

您可以将边距应用于完整的TreeViewItem 内容,包括下拉箭头:

<TreeView ItemsSource="{Binding Items}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="Margin" Value="{Binding Margin}"/>
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding SubItems}">
            <Border>
                <Grid>
                    <TextBlock Margin="3,3,3,3"/>
                </Grid>
            </Border>    
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

【讨论】:

  • 由于所有项目的边距不同,我怀疑这会起作用。边距是呈现为树视图项目的对象的属性,每个项目都可以不同。
  • 我试过了。所有项目的边距都消失了。
  • 我更新了问题并添加了缺失的代码。我没有添加触发器 - 这些无关紧要。
  • 你是说没有 HierarchicalDataTemplate 我不能调整箭头?因为没有 HierarchicalDataTemplate,它们就在那里并且可见。
  • 那么你必须发布一个例子。你听说过minimal reproducible example吗? 完整可验证很重要。您发布的小 XAML sn-p 不会产生您在屏幕截图中显示的输出。没有人想猜测它是如何在您的代码中完成的。
【解决方案2】:

是的,我知道下面的样式太长了,但是试试看。 只需将其放在单独的资源字典中并合并即可。

<TreeView ItemsSource="{Binding TreeItems}" ItemContainerStyle="{StaticResource CenteredExpanderTreeViewItemStyle}">
    <TreeView.Resources>
        <DataTemplate DataType="{x:Type models:MyModel}">
            <Border Margin="{Binding Margin}" >
                 <Grid>
                     <TextBlock Text="{Binding Path=Name}" Margin="3,3,3,3" />
                 </Grid>
            </Border>
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

CenteredExpanderTreeViewItemStyle.xaml

<Style x:Key="TreeViewItemFocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <Rectangle/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Fill" Color="#FF595959"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Stroke" Color="#FF262626"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Stroke" Color="#FF27C7F7"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Fill" Color="#FFCCEEFB"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Stroke" Color="#FF1CC4F7"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Fill" Color="#FF82DFFB"/>
<PathGeometry x:Key="TreeArrow" Figures="M0,0 L0,6 L6,0 z"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Fill" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Stroke" Color="#FF818181"/>
<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 Background="Transparent" Height="16" Padding="5,5,5,5" Width="16">
                    <Path x:Name="ExpandPath" Data="{StaticResource TreeArrow}" Fill="{StaticResource TreeViewItem.TreeArrow.Static.Fill}" Stroke="{StaticResource TreeViewItem.TreeArrow.Static.Stroke}">
                        <Path.RenderTransform>
                            <RotateTransform Angle="135" CenterY="3" CenterX="3"/>
                        </Path.RenderTransform>
                    </Path>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsChecked" Value="True">
                        <Setter Property="RenderTransform" TargetName="ExpandPath">
                            <Setter.Value>
                                <RotateTransform Angle="180" CenterY="3" CenterX="3"/>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Fill}"/>
                        <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Stroke}"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Stroke}"/>
                        <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Fill}"/>
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsMouseOver" Value="True"/>
                            <Condition Property="IsChecked" Value="True"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Stroke}"/>
                        <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Fill}"/>
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="CenteredExpanderTreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
    <Setter Property="VerticalContentAlignment" Value="{Binding 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="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <ToggleButton x:Name="Expander" VerticalAlignment="Center" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                        <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </Border>
                    <ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsExpanded" Value="false">
                        <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
                    </Trigger>
                    <Trigger Property="HasItems" Value="false">
                        <Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
                    </Trigger>
                    <Trigger Property="IsSelected" Value="true">
                        <Setter Property="Background" TargetName="Bd" 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 Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
                    </MultiTrigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
            <Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <VirtualizingStackPanel/>
                    </ItemsPanelTemplate>
                </Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>
</Style>

【讨论】:

    【解决方案3】:

    为 TreeViewItem 使用给定的样式,如下所示

    <Style TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
                <Setter Property="Margin" Value="3,3,3,3"></Setter>
            </Style>
    

    希望对您有所帮助。

    【讨论】:

      【解决方案4】:

      要在TreeView 中为ToggleButton 添加边距,您必须添加自定义ControlTemplate。 MSDN上有几个不错的教程,例如这里:https://msdn.microsoft.com/de-de/library/ms788727(v=vs.85).aspx

      我将一个示例简化为满足您要求的必要元素。请注意,ToggleButton 是这个示例根本没有样式,所以看起来普通的Button 就可以了。但我敢肯定,您会找到几个很好的示例,说明如何以最适合您的方式设置此 Button 的样式。

      代码:

      <Window.Resources>
              <Style x:Key="TreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
                  <Setter Property="Template">
                      <Setter.Value>
                          <ControlTemplate TargetType="{x:Type TreeViewItem}">
                              <Grid Margin="{Binding Margin}">
                                  <Grid.ColumnDefinitions>
                                      <ColumnDefinition MinWidth="20" Width="Auto"/>
                                      <ColumnDefinition Width="Auto"/>
                                      <ColumnDefinition Width="*"/>
                                  </Grid.ColumnDefinitions>
                                  <Grid.RowDefinitions>
                                      <RowDefinition Height="Auto"/>
                                      <RowDefinition Height="*"></RowDefinition>
                                  </Grid.RowDefinitions>
                                  <ToggleButton Grid.Column="0" x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" />
                                  <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Row="0" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                                      <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                  </Border>
                                  <ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1" Margin="-10,0,0,0"/>
                              </Grid>
                              <ControlTemplate.Triggers>
                                  <Trigger Property="IsExpanded" Value="false">
                                      <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
                                  </Trigger>
                                  <Trigger Property="HasItems" Value="false">
                                      <Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
                                  </Trigger>
                                  <Trigger Property="IsSelected" Value="true">
                                      <Setter Property="Background" TargetName="Bd" 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 Property="Background" TargetName="Bd" 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.Triggers>
                      <Trigger Property="VirtualizingStackPanel.IsVirtualizing" Value="true">
                          <Setter Property="ItemsPanel">
                              <Setter.Value>
                                  <ItemsPanelTemplate>
                                      <VirtualizingStackPanel/>
                                  </ItemsPanelTemplate>
                              </Setter.Value>
                          </Setter>
                      </Trigger>
                  </Style.Triggers>
              </Style>
          </Window.Resources>
      
          <TreeView ItemsSource="{Binding TreeItems}" ItemContainerStyle="{StaticResource TreeViewItemStyle}">
              <TreeView.Resources>
                  <HierarchicalDataTemplate DataType="{x:Type library:MyModel}" ItemsSource="{Binding Children}" >
                      <TextBlock Text="{Binding Name}"></TextBlock>
                  </HierarchicalDataTemplate>
              </TreeView.Resources>
          </TreeView>
      

      【讨论】:

        【解决方案5】:

        您应该能够做到这一点:

        <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
            <Setter Property="Margin" Value="0,0,0,0" />
            <!--Or edit Padding if Margin doesn't work-->
        </Style>
        

        它将使用TreeViewItem 的默认样式并仅编辑已定义的属性。如果您为 TreeViewItem 使用明确定义的样式,请使用 BaseOn="{StaticResource [YourStyleKey]}"(不带 [ ])。

        如果您需要一些更高级的样式,我建议您使用 Blend 来获得 TreeViewItemControlTemplate,然后根据您的需要对其进行编辑,而无需进行太多更改(请记住控件的名称用作模板可能具有至关重要的意义,因此请小心您正在编辑的内容)。

        如果您不知道如何使用 Blend 来获取控件的模板,这里有一个 Telerik 控件文档中描述的简单教程(不用担心,它对所有控件都适用)。您只需创建TreeViewItemControlTemplate 的副本,将其粘贴到您的应用程序中,您就可以开始了(编辑)。

        通过使用 Blend,您可以获得 TreeView 控件的所有构建块的模板,并使它们看起来像您想要的那样。你只需要做一些挖掘。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-01-27
          • 1970-01-01
          • 1970-01-01
          • 2013-01-13
          • 2011-01-07
          • 1970-01-01
          • 2019-01-21
          • 2013-07-18
          相关资源
          最近更新 更多