如何拉伸 TreeViewItem 宽度以填充父项?

Posted

技术标签:

【中文标题】如何拉伸 TreeViewItem 宽度以填充父项?【英文标题】:How to stretch TreeViewItem width to fill parent? 【发布时间】:2018-04-25 19:37:58 【问题描述】:

我有一个 WPF TreeView,我想像它的父级一样将 TreeViewItem 拉伸到整个空间。

<TreeView Name="treeFamilies" AllowDrop="True" >
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="x:Type local:MyNode" ItemsSource="Binding Members">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Binding Name" Background="LightGray"/>
                <TextBlock Text=" [" Foreground="Blue" Background="LightGray"/>
                <TextBlock Text="Binding Members.Count" Foreground="Blue" Background="LightGray"/>
                <TextBlock Text="]" Foreground="Blue" Background="LightGray" />
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
    <TreeView.ItemContainerStyle>
        <Style TargetType="x:Type TreeViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

看来我错误地使用了 ItemContainer 样式 &lt;Setter Property="HorizontalContentAlignment" Value="Stretch"/&gt;。我现在的树看起来像这张照片:

我希望拉伸灰色背景以填充树视图控件的整个末端。 我怎样才能做到这一点?

【问题讨论】:

看看here 不确定,但我认为使用 StackPanel 会给您带来一些问题。我经常无法按照我想要的方式使用它。您还可以考虑将树项的宽度、RelativeSource 绑定到父元素。 @Il Vic 您的链接非常有用。 【参考方案1】:

Form Il Vic 的评论,this msdn blog 显示了一种 hack-like 方法来删​​除 TreeViewItem 的最后一列。

如果博客关闭,我会在此处复制我的工作代码。加载TreeViewItem 后,我从网格中删除第三个ColumnDefinition,并将第二个ColumnDefinition 宽度设置为*

public class StretchingTreeViewItem : TreeViewItem

    public StretchingTreeViewItem()
    
        this.Loaded += new RoutedEventHandler(StretchingTreeViewItem_Loaded);
    

    private void StretchingTreeViewItem_Loaded(object sender, RoutedEventArgs e)
    
        if (this.VisualChildrenCount > 0)
        
            Grid grid = this.GetVisualChild(0) as Grid;
            if (grid != null && grid.ColumnDefinitions.Count == 3)
            
                grid.ColumnDefinitions.RemoveAt(2);
                grid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star);
            
        
    

    protected override DependencyObject GetContainerForItemOverride()
    
        return new StretchingTreeViewItem();
    

    protected override bool IsItemItsOwnContainerOverride(object item)
    
        return item is StretchingTreeViewItem;
    

然后我覆盖TreeView 以获取自定义项。

public class StretchingTreeView : TreeView

    protected override DependencyObject GetContainerForItemOverride()
    
        return new StretchingTreeViewItem();
    

    protected override bool IsItemItsOwnContainerOverride(object item)
    
        return item is StretchingTreeViewItem;
            

【讨论】:

【参考方案2】:

您必须覆盖树视图 itemcontainerstyle 的模板,这对微软来说有点奇怪,但您必须将整个模板写成新的。所以不会有扩展器或类似的东西,但是使用此代码,您的树视图项目将延伸到整个父级。我将 IsExpanded 设置为 true,因此您的孩子仍会显示。

<TreeView Margin="10"
              ItemsSource="Binding ChainedCommandVMs">
        <TreeView.ItemContainerStyle>
            <Style TargetType="x:Type TreeViewItem">
                <Setter Property="IsExpanded"
                        Value="True" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="TreeViewItem">
                            <StackPanel>
                                <ContentPresenter ContentSource="Header" />
                                <ItemsPresenter Name="ItemsHost" />
                            </StackPanel>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </TreeView.ItemContainerStyle>...

如果您想保持正常行为,例如查看本教程的展开按钮,它将帮助您重写整个模板: https://wpf.2000things.com/2017/09/23/1218-stretching-items-in-treeview-across-entire-control/

【讨论】:

【参考方案3】:

我想出了一个非常简单的方法来实现这个(虽然也不完美):绑定到树视图的ActualWidth 属性

<TreeView x:Name="ListUI">
  <TreeView.Resources>
    <DataTemplate>
      <Grid HorizontalAlignment="Stretch"
        Width="Binding ActualWidth,
          ElementName=ListUI,
          Converter=StaticResource MinusFortyFiveConverter">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="Auto" />
          <ColumnDefinition Width="*" />
          <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" Text="Left Side" />
        <!-- Will gap in the middle -->
        <TextBlock Grid.Column="2" Text="Right Side" />
      </Grid>
    </DataTemplate>
  </TreeView.Resources>
</TreeView>

您可能需要一个值转换器,将数字减少 10 左右,否则会太宽,请根据您的皮肤需要进行调整。我对默认皮肤的初始测试是负 45 是一个很好的起点。

public class MinusFortyFiveConverter : IValueConverter

    /// <inheritdoc/>
    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    
        return (double)value - 45;
    

    /// <inheritdoc/>
    public object ConvertBack(
        object value, Type targetType, object parameter, CultureInfo culture)
    
        throw new NotSupportedException("Cannot convert back");
    

【讨论】:

以上是关于如何拉伸 TreeViewItem 宽度以填充父项?的主要内容,如果未能解决你的问题,请参考以下文章

将视图添加到将拉伸以填充可用宽度的滚动视图

为啥图像视图会拉伸以填充 UIStackView 中宽度的一半?

根据最小尺寸包装小部件,然后拉伸它们以填充可用宽度

如何拉伸顶部导航以适应页面容器宽度

将按钮高度和宽度设置为包装内容并填充父项

如何在某个浏览器大小后停止拉伸标签的视口宽度