How to make text wrap in a WPF TreeViewItem?

2019-02-26 07:10发布

问题:

This time, my question is as simple as it sounds... how do you get text to wrap in a WPF TreeViewItem?

I have a simple HierarchicalDataTemplate with just one TextBlock in it.

<TextBlock Text="{Binding Value}" TextWrapping="Wrap" />

The text does not wrap.

I tried binding the Width of the TextBlock to the ActualWidth of the TreeView, but although that makes the text wrap, the Width of the TreeViewItem does not fit in the TreeView because the TreeView has Padding. Binding to the ActualWidth of the TreeViewItem has (unsurprisingly) the same effect. Another downside to this is that even the items with little text stretch outside the TreeView bounds.

<TextBlock Text="{Binding Value}" TextWrapping="Wrap" Width="{Binding ActualWidth, 
ElementName=TreeView}" />

Surely there must be a better way, like somehow informing the TreeViewItem of the TreeView's bounds... I can't believe it doesn't know automatically. But how can I do this?

UPDATE >>>

Thanks to H.B.'s answer, I managed to change the Grid.ColumnSpan to 2 on the Bd Border he mentioned in the ControlTemplate and it set the width so that the text now wraps nicely. The problem is that I am using this ControlTemplate for other TreeViewItems in other TreeViews where I don't want full width items.

The solution I came up with is simple. I have bound the TreeViewItem.Tag value to the Grid.ColumnSpan property in the ControlTemplate like so:

<Border Grid.ColumnSpan="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}" 
Name="Bd" Grid.Column="1" ... />

This allows me to change the Grid.ColumnSpan and therefore the full width or ordinary width behaviour of the TreeViewItem by setting the TreeViewItem.Tag value to either 2 or 1 respectively.

回答1:

If you look at the default template of TreeViewItems you will see a Grid like this:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="19"
                          Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <!-- ... -->

As you can see the third column takes all available space while the others are on Auto, the header is placed in the second column inside a border:

<Border Name="Bd"
        Grid.Column="1"
        ...

This means that the column will become as large as the header, there is no restriction on it. Thus the header just gets bigger than the TreeView itself.

If you add Grid.ColumnSpan="2" to this Border it will occupy the third column as well, which is restricted by how much space is left, hence the text will wrap; this will however extend the header across the whole width which might look a bit odd when selecting it.

Of course you will also need to disable horizontal scrolling:

<TreeView ScrollViewer.HorizontalScrollBarVisibility="Disabled" ...