【问题标题】:How to wrap TextBlock content in TreeView?如何在 TreeView 中包装 TextBlock 内容?
【发布时间】:2012-06-26 14:23:40
【问题描述】:

我有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>

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

【问题讨论】:

    标签: c# wpf xaml treeview


    【解决方案1】:

    我相信TextBlock 没有换行,因为它没有定义宽度。 TextBlock 所在的网格列具有 * 宽度,该宽度将随着 TextBlock 宽度的增长而增长。尝试在TextBlock 或列上设置宽度,看看更改是否会导致TextBlock 换行。

    更新:

    更具体地说,问题在于TreeViewItem 将自己调整到其内容的大小,ColumnDefinition 将填充(无限)可用空间,TextBlock,没有宽度限制,将从不包装。 This post 很好地描述了 TreeViewItem 的行为方式。总结一下:TreeViewItem 的内容区域设置为“自动”,因此它会增长以适应内容。要显式设置TreeViewItem 的宽度,请尝试将ColumnDefinition 宽度绑定到TreeViewActualWidth

    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>
    

    【讨论】:

    • 我认为,您混淆了“”和“Auto”。 “”表示“填充所有可用空间”,“Auto”表示“尽可能多地获取空间”。在我的标记示例中,“所有可用空间”必须是呈现我的数据项的 TreeViewItem 的宽度。反过来,TVI 的宽度必须受 TreeView 宽度的限制(这是我的假设),但这不会发生。
    • 感谢您的链接,它很好地解释了问题来源。关于绑定到 TreeView 的实际宽度 - 请参阅下面的答案。
    【解决方案2】:

    我做到了。 :)

    根据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

    【讨论】:

      【解决方案3】:

      试试这个

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

      【讨论】:

      • 不幸的是,它不起作用。看起来这个绑定被忽略了。同时,恒定宽度值正常工作。 :(
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 2017-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-14
      相关资源
      最近更新 更多