如何在TreeView中包装TextBlock内容?

时间:2012-06-26 14:23:41

标签: c# wpf xaml treeview

我有TreeView,它使用数据模板显示一些数据。这是XAML:

<TreeView Grid.Row="0" ItemsSource="{Binding Railways}" x:Name="tvDatawareObjects"
          ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.Resources>
        <!-- other templates here... -->
        <HierarchicalDataTemplate DataType="{x:Type viewModels:ProjectViewModel}" ItemsSource="{Binding Phases}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding Model.Code}" FontWeight="DemiBold" />
                <TextBlock Text="{Binding Model.Title}" TextWrapping="Wrap" Foreground="Gray" Grid.Row="1" />
            </Grid>
        </HierarchicalDataTemplate>

        <HierarchicalDataTemplate DataType="{x:Type viewModels:CollectionViewModel}" ItemsSource="{Binding Items}">
            <TextBlock Text="{Binding CollectionName}" />
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

<TextBlock Text="{Binding Model.Title}" TextWrapping="Wrap" Foreground="Gray" Grid.Row="1" />的文字换行不起作用。我做错了什么?

3 个答案:

答案 0 :(得分:2)

我认为TextBlock不会包装,因为它没有定义的宽度。 TextBlock所在的网格列的宽度随着TextBlock宽度的增加而增长。尝试在TextBlock或列上设置宽度,看看更改是否导致TextBlock换行。

<强>更新

更具体地说,问题是TreeViewItem会将自身调整为其内容的大小,ColumnDefinition将填充(无限)可用空间和TextBlock,没有宽度限制,永远不会包装。 This post很好地描述了TreeViewItem的行为方式。总结一下:TreeViewItem的内容区域设置为&#39;自动&#39;所以它会增长以适应内容。要明确设置TreeViewItem尝试的宽度,将ColumnDefinition宽度绑定到TreeView&#39; ActualWidth

XAML:

<TreeView Width="100">
    <TreeViewItem>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType=TreeView}, Path=ActualWidth}"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <TextBlock Text="Lorem Ipsum" />
            <TextBlock Text="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book." 
                       TextWrapping="Wrap" Grid.Row="1"/>
            </Grid>
        </TreeViewItem>
    </TreeView>

答案 1 :(得分:0)

我做到了。 :)

Accordind在Dan的回答中提供的链接,原因在于默认的TreeViewItemTemplate。

不幸的是,与TreeView.ActualWidth的简单绑定无济于事。这是因为每个项目的宽度根据定义小于TreeView.ActualWidth - 项目使用一些水平偏移进行渲染,具体取决于它们的级别。

因此,要解决这个问题,我需要像这样计算项目的宽度:

width = actual_width_of_tree_view - relative_horizontal_offset_of_item

更准确地说,我需要ScrollViewer.ViewportWidth,因为TreeViewContent可能会垂直滚动,在这种情况下,TreeView的可见区域将小于TreeView.ActualWidth

这是附属物:

    public static Double GetProjectTitleWidth(DependencyObject obj)
    {
        return (Double)obj.GetValue(ProjectTitleWidthProperty);
    }

    public static void SetProjectTitleWidth(DependencyObject obj, Double value)
    {
        obj.SetValue(ProjectTitleWidthProperty, value);
    }

    public static readonly DependencyProperty ProjectTitleWidthProperty = DependencyProperty.RegisterAttached(
        "ProjectTitleWidth", 
        typeof(Double), 
        typeof(DatawareSearchView),
        new UIPropertyMetadata(0.0, ProjectTitleWidthChanged));

    private static void ProjectTitleWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var targetElement = d as FrameworkElement;
        if (targetElement != null)
        {
            var bindingExpr = targetElement.GetBindingExpression(ProjectTitleWidthProperty);
            var sourceElement = bindingExpr.DataItem as FrameworkElement;
            if (sourceElement != null)
            {
                // calculating relative offset
                var leftTop = targetElement.TranslatePoint(new Point(0.0, 0.0), sourceElement);

                // trying to find ScrollViewer
                var border = VisualTreeHelper.GetChild(sourceElement, 0);
                if (border != null)
                {
                    var scrollViewer = VisualTreeHelper.GetChild(border, 0) as ScrollViewer;
                    if (scrollViewer != null)
                    {
                        // setting width of target element
                        targetElement.Width = scrollViewer.ViewportWidth - leftTop.X;
                    }
                }
            }
        }
    }

...和标记:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <TextBlock Text="{Binding Model.Code}" FontWeight="DemiBold" />
    <TextBlock Text="{Binding Model.Title}" TextWrapping="Wrap" Foreground="Gray" x:Name="tbTitle" Grid.Row="1"
               localviews:DatawareSearchView.ProjectTitleWidth="{Binding RelativeSource={RelativeSource AncestorType=TreeView}, Path=ActualWidth}"/>
</Grid>

当然,如果提供的解决方案不是通用的 - 它假定TreeView具有BorderScrollViewer

答案 2 :(得分:-1)

试试这个

<TextBlock Text="{Binding Model.Title}" Width="{Binding ActualWidth,
      ElementName=tvDatawareObjects}" TextWrapping="Wrap" Foreground="Gray" Grid.Row="1"/>