【问题标题】:Indenting top hierarchical items in a wpf treeview在 wpf 树视图中缩进顶级分层项目
【发布时间】:2017-01-10 09:38:12
【问题描述】:

我试图在 WPF TreeView 中的顶级分层项目之间提供分隔(边距)。问题是我无法弄清楚如何编写 Style 以使其仅适用于顶部项目而不是每个项目。

我的TreeView 的代码如下所示:

<TreeView ItemContainerStyle="{StaticResource treeViewItemStyle}"
          ItemsSource="{Binding Container.RootRules}"
          KeyUp="treeView_KeyUp"
          SelectedItemChanged="TreeView_SelectedItemChanged">
  <TreeView.Resources>
    <HierarchicalDataTemplate DataType="{x:Type me:HybridForecastRulesViewModel}"
                              ItemsSource="{Binding Children}">
      <Border Name="bd"
        ...
      </Border>
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="{x:Type me:RootRulesViewModel}"
                              ItemsSource="{Binding Rules}">
      <Grid>
        ...
      </Grid>
    </HierarchicalDataTemplate>
  </TreeView.Resources>
</TreeView>

我有这样的 treeViewItems 样式:

<Style x:Key="treeViewItemStyle"
       BasedOn="{StaticResource {x:Type TreeViewItem}}"
       TargetType="{x:Type TreeViewItem}">

  <Setter Property="Margin" Value="0,10,0,0" />

  <Style.Triggers>
    <DataTrigger Binding="{Binding IsVisible}" Value="False">
      <Setter Property="Visibility" Value="Collapsed" />
    </DataTrigger>
  </Style.Triggers>

</Style>

但是这种风格适用于两种类型的项目(RootRulesViewModelHybridForecastRulesViewModel),而我希望它只适用于 RootRulesViewModel 类型的项目。如何才能做到这一点?

锦上添花的是所有RootRulesViewModel 项目的顶部Margin 为10,第一个除外。

【问题讨论】:

  • 你不能在 RootRulesViewModel 的 HierarchicalDataTemplate 中的网格上设置适当的边距吗?
  • 我试过了,但它只会将边距添加到项目本身,因此项目会向下移动,但左侧的箭头仍保留在原处。那样真的不好看。
  • 您可以使用 0,5 的边距(即底部和顶部值 5)而不是 0,10,0,0
  • 嗯,这解决了标题和标记之间的对齐问题,但它也增加了顶部节点和以下子节点之间的间隙,这不是我想要的。看似如此简单的事情怎么会如此难以实现?

标签: c# wpf treeview


【解决方案1】:

TreeViewItem 没有要使用的 Level 属性。

所以你有两个选择:

1)this。看看TreeLevelConverter,很有意思。他们绑定控件本身并使用转换器检索Level。在您的情况下,您可以扩展转换器,以便在检索到 Level 后,将其转换为 Thickness 实例以用作 Margin

2) 您可以在您的ViewModels 上创建一个Level 属性(可能在它们的基类中以避免代码重复)。然后,每次将子节点添加到 ViewModel 节点时,都会在该子节点上设置 Level。在 xaml 中,您将Margin 属性绑定到ViewModel 上的Level,使用返回不同Thickness 的转换器,具体取决于Level 是否为1。

编辑:

这就是您为所有TreeViewItem 设置公共Style 的方式:

<TreeView>
  <TreeView.ItemContainerStyle>
    <Style TargetType="{x:Type TreeViewItem}">
      <Setter 1 .../>
      <Setter 2 .../>
      <Setter Property="Margin"
              Value="{Binding Level, Converter={StaticResource LevelToMarginConverter}}"/>
    </Style>
  </TreeView.ItemContainerStyle>
  <TreeView.Resources>
    <!-- here your hierarchical DataTemplate... -->
    <HierarchicalDataTemplate ... />
  </TreeView.Resources>
</TreeView>

【讨论】:

  • 感谢您的回答。对我来说这里的问题是:如何访问我的 TreeViewItem 样式上的该属性?
  • 谢谢,现在很清楚了。看起来它比我已经基于标头类型实现的解决方案稍微多一些工作,但是当只有一个分层模板时它会非常有用。我会将此标记为答案,因为它可以解决问题。感谢您的帮助。
【解决方案2】:

我实际上已经为此找到了解决方案。我不确定它有多好,因此欢迎提出改进建议。

我从this answer 编写了一个对象转换器,用于获取TreeViewItemHeader 中的对象类型。 代码如下所示:

            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=Header, Converter={StaticResource ObjectTypeConverter}}"
                             Value="RootRulesViewModel">
                    <Setter Property="Margin"
                            Value="0,0,0,10" />
                </DataTrigger>
                <DataTrigger Binding="{Binding IsVisible}"
                             Value="False">
                    <Setter Property="Visibility"
                            Value="Collapsed" />
                </DataTrigger>
            </Style.Triggers>
        </Style>

ObjectTypeConverter 是我的自定义转换器,它将对象类型转换为字符串值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-24
    • 1970-01-01
    • 2011-03-16
    相关资源
    最近更新 更多