Question

As you can see from stackoverflow post, this code doesn't trim the text of the TextBlock's when the size of the ListBox becames small.

 <ListBox ItemsSource="{Binding}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" TextTrimming="CharacterEllipsis"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

The ListBox shows the HorizontalScrollBar - in other words the room for TextBlock is large enough and there is no need in text trimming. This can be solved using the next line of code:

<ListBox ...
         ScrollViewer.HorizontalScrollBarVisibility="Disabled"
         ... />

So now the text will be trimmed. But if I wouldn't want to trim the whole text till the only ... would stay? Let say, I have set the MinWidth of the TextBlock property, and when the width of the ListBox becames less than that MinWidth, I want HorizontalScrollBar becames visible.

I have tried to handle SizeChanged event, and according the condition, set the ScrollViewer.HorizontalScrollBarVisibility attached property. But the text becames not trimmed just when I change the latter from Disabled to Visible - so it jumps somehow - from trimmed to the full, which is not the best UI practice.

Q: So, how to achive the behavior mentioned above?

Was it helpful?

Solution

The TextBlock in WPF really doesn't want to trim its text. It will do so when there isn't enough space, but as soon as the ScrollViewer can scroll, the TextBlock thinks it has infinite space available, so it won't trim.

I think the easiest way to do this is to set the MaxWidth on the TextBlock to the ActualWidth of the ListBox:

<DataTemplate>
    <TextBlock Text="{Binding}" 
               TextTrimming="CharacterEllipsis"
               MaxWidth="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"/>
</DataTemplate>

This is going to be ever slightly too big with the default WPF ListBox Style (which causes the scrollbar to still appear). I would write a custom converter to subtract about 8 from this value:

public FudgeFactorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return Binding.DoNothing;

        return (double)value - 8;  // you will probably need to tweak this
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

And then use it to convert the MaxWidth:

<DataTemplate>
    <DataTemplate.Resources>
        <my:FudgeFactorConverter x:Key="fudgeFactorConverter" />
    </DataTemplate.Resources>
    <TextBlock Text="{Binding}" 
               TextTrimming="CharacterEllipsis"
               MaxWidth="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}, Converter={StaticResource fudgeFactorConverter}}"/>
</DataTemplate>

As a bonus, if you set ListBox.MinWidth, you won't have to enable/disable the horizontal scrollbar.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top