1

我有TreeViewItems ,其中HierarchicalDataTemplateGrid 由具有以下定义的 3 列组成:

<Grid>    
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="1*" />
    <ColumnDefinition Width="Auto" />
...

我想设置网格的宽度,以便完全占用TreeViewItem内部的所有可用空间TreeView。因此,网格的第三列应该在TreeView.

如何获得网格宽度的正确值?

我知道对于ListBox ItemTemplate,我可以通过将其绑定到 来设置宽度ScrollContentPresenter

Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ScrollContentPresenter, AncestorLevel=1}, Path=ActualWidth}"

这个技巧在 中不起作用TreeView,因为孩子的可用空间比根树视图项目少。

有任何想法吗?

4

3 回答 3

7

经过几个小时的研究,我找到了一个使用Multibinding两个 Converters的工作解决方案。

一、HierarchicalDataTemplateXAML中的定义:

<HierarchicalDataTemplate>
<Grid>
   <Grid.Width>
      <MultiBinding Converter="{StaticResource SumConverterInstance}">
          <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=ScrollContentPresenter, AncestorLevel=1}" Path="ActualWidth" />
          <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=TreeViewItem, AncestorLevel=1}" Converter="{StaticResource ParentCountConverterInstance}" />
      </MultiBinding>
    </Grid.Width>   
   .... (content of the template) ....
</Grid>
</HierarchicalDataTemplate>

multibinding 中的第一个绑定获取 in 的宽度ScrollContentPresenterTreeView即 的总可见宽度TreeView。第二个绑定以 为参数调用转换器,并计算在到达根项之前有TreeViewItem多少父项。TreeViewItem使用这两个输入,我们使用 SumConverterInstanceMultibinding来计算给定的可用宽度TreeViewItem

以下是 XAML 中定义的转换器实例:

  <my:SumConverter x:Key="SumConverterInstance" />
  <my:ParentCountConverter x:Key="ParentCountConverterInstance" />

以及两个转换器的代码:

// combine the width of the TreeView control and the number of parent items to compute available width
public class SumConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double totalWidth = (double)values[0];
        double parentCount = (double)values[1];
        return totalWidth - parentCount * 20.0;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

// count the number of TreeViewItems before reaching ScrollContentPresenter
public class ParentCountConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        int parentCount = 1;
        DependencyObject o = VisualTreeHelper.GetParent(value as DependencyObject);
        while (o != null && o.GetType().FullName != "System.Windows.Controls.ScrollContentPresenter")
        {
            if (o.GetType().FullName == "System.Windows.Controls.TreeViewItem")
                parentCount += 1;
            o = VisualTreeHelper.GetParent(o);
        }
        return parentCount;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

现在是正确的外观:

替代文字

于 2010-07-15T13:38:29.703 回答
1

您应该让布局系统为您处理这个问题,而不是在ItemTemplate. 对于一个ListBox,你需要做的就是设置HorizontalContentAlignment="Stretch"。这也是 a 的第一步TreeView,但不幸的是,默认模板中还有一些其他布局需要额外更改。它使用 3 列 Grid 将内容放入第二列,只有子项扩展到第三 (*) 列。Grid.ColumnSpan="2"通过在 contains上添加 a ,内容将延伸到整个项目的区域ContentPresenterBorder

<PathGeometry x:Key="TreeArrow" Figures="M0,0 L0,6 L6,0 z"/>
<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="Transparent" Stroke="#FF989898">
                        <Path.RenderTransform>
                            <RotateTransform Angle="135" CenterY="3" CenterX="3"/>
                        </Path.RenderTransform>
                    </Path>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Stroke" TargetName="ExpandPath" Value="#FF1BBBFA"/>
                        <Setter Property="Fill" TargetName="ExpandPath" Value="Transparent"/>
                    </Trigger>
                    <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="#FF595959"/>
                        <Setter Property="Stroke" TargetName="ExpandPath" Value="#FF262626"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<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" 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" Grid.ColumnSpan="2" 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.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>
于 2010-07-13T21:20:37.303 回答
0

你描述的是TreeView'sItemContainerStyle和我上面描述的网格是HierarchicalDataTemplate.

在我的TreeView我显示电子邮件附件。TreeViewItems 包含一个图标(网格的第一列)、文件名和大小(第二列)和时间(第三列)。我希望看到基于TreeView.

下面是一个非工作示例。如您所见,文件名未包装,因此您看不到某些项目的日期。

替代文字

于 2010-07-15T06:05:25.900 回答