2010-07-13 56 views
1

我有TreeViewItem为什么会产生HierarchicalDataTemplate由3列,分别定义一个网格内:如何获得树型视图的可用(可视)的宽度一个TreeView

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

我想设置的宽度的网格,因此它将占用TreeView内的TreeViewItem的所有可用空间。网格的第三列因此应该在TreeView内右对齐。

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

我知道,对于ListBoxItemTemplate,我可以通过它绑定到ScrollContentPresenter设置宽度:

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

这招不TreeView工作,因为孩子有十几根树视图可用空间少项目。

任何想法?

回答

6

它的工作了几个小时后,我发现使用Multibinding两个转换器一个可行的解决方案。

首先,在XAML中的HierarchicalDataTemplate定义:

<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结合获取ScrollContentPresenterTreeView宽度,这是TreeView的总可见光宽度。第二个绑定使用TreeViewItem作为参数调用转换器,并计算TreeViewItem在到达根项目之前有多少个父项。使用这两个输入,我们使用Multibinding中的SumConverterInstance来计算给定的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(); 
    } 
} 

现在,这是正确的样子:

alt text http://img249.imageshack.us/img249/6889/atts2.png

+0

感谢此代码。这适用于我! 干杯! – klaydze 2015-09-28 00:37:21

+0

完美适合我:) – 2015-10-25 11:40:05

1

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

<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> 
+0

谢谢你的回答约翰,但不幸的是这不是我的问题的答案。我正在描述为什么在底部帖子中,因为评论的大小是有限的...... – 2010-07-15 06:06:29

+0

您正在使用的DataTemplate用于填充TreeViewItem模板中的ContentPresenter,因此您可以在DataTemplate内部执行的操作受限于布局ControlTemplate中的ContentPresenter和ItemsPresenter。例如,如果ControlTemplate为其根网格指定宽度为0,则无论您在DataTemplate中做什么,都不会显示出来。尝试在Snoop中检查您的布局(宽度,高度和路线)以更好地理解问题。 – 2010-07-15 12:41:16

0

你所描述的是TreeViewItemContainerStyle,我上面描述的网格是HierarchicalDataTemplate

在我的TreeView中显示电子邮件附件。其中包含一个图标(网格的第一列),文件名和大小(第二列)和时间(第三列)。我希望根据TreeView的宽度看到项目被拉伸或挤压(通过包装网格的中间列)。

下面是一个不起作用的例子。正如你所看到的文件名不被包装,所以你不能看到一些项目的日期。

alt text http://img638.imageshack.us/img638/1743/attsv.png

相关问题