14

I have a TextBlock with a long line of text which I want to wrap. I've placed the TextBlock within a ViewBox expecting the text size to change while still wrapping, however this doesn't seem to happen. The ViewBox just resizes the TextBox so that all the text fits on one line making the text really small.

How can I use the ViewBox to resize the text while still using TextWrapping.

Here is my code:

<Viewbox>
    <TextBlock Text="The Option text can also dynamically grow/shrink to fit more content. More text to go here....................." TextWrapping="Wrap"/>
</Viewbox>

This is part of a Windows 8 store application so is WinRT Xaml.

Sun
  • 4,458
  • 14
  • 66
  • 108
  • Might be helpful [WPF: can we make a two line in the ViewBox?](http://social.msdn.microsoft.com/Forums/vstudio/en-US/9dc8a7e3-e068-44e5-a363-85e8314f075d/wpf-can-we-make-a-two-line-in-the-viewbox) – Farhan Ghumra Jul 18 '13 at 08:52
  • No, that doesn't work but thanks for trying – Sun Jul 18 '13 at 09:54
  • 1
    @Xyroid's linked post is correct though, you need to somehow give the `TextBlock` a `MaxWidth` so that it will determine that it needs to `TextWrap`. You can do this manually in the XAML or you can do something like on `Viewbox` `Loaded`, find out the rendered size and set the `Child`'s `MaxWidth` to that. – Nate Diamond Jul 18 '13 at 18:25

3 Answers3

31

Just set a width on the TextBlock.

        <Viewbox Width="500">
            <TextBlock Width="100" TextWrapping="Wrap">This is the text that's long and on two lines.</TextBlock>
        </Viewbox>

TextBlock with width 100 in ViewBox with width 500

So the ViewBox will zoom in/out its entire contents. If you don't restrict its contents by either setting a width on the TextBlock, the ViewBox will give it infinite space to expand into. You can also add a root Grid with a width and height within the ViewBox and lay your elements out in that, then the whole lot will get zoomed according to the width of the ViewBox.

In the image, the width of the TextBlock 100 is zoomed to be the width of the ViewBox which is 500. So to get the wrapping you want, just tweak the TextBlock width until it looks nice.

(Obviously it should say three lines but I'm not re-uploading just for that)

Luke Puplett
  • 42,091
  • 47
  • 181
  • 266
  • OK, that works but I'm using the textblock within a DataTemplate the text is different for each item so I can't really "tweak" the width of the textbox. – Sun Sep 06 '13 at 09:07
  • Of course you can. Just set a width that gives the right look for a sample of text. The `Viewbox` will be sized to the template item container and the `TextBlock` will scale with the wrapping. I don't know what you're trying to achieve but maybe the `Viewbox` is a red-herring. Take it out. – Luke Puplett Sep 06 '13 at 19:43
  • 1
    Hmm, then what is the entire purpose of viewbox? The original intent is to adjust content to differing screen sizes/resolutions. If the screen real estate was static, then there is no need for viewboxes. Hence, I don't consider setting width a workable solution. It messes up the presentation badly on smaller resolution screens. – Matt Dec 07 '18 at 04:57
  • @Matt - I think you downvoted. Read it again, I say to add a width to the content _inside_ the Viewbox. The Viewbox can be fixed or not, that's up to you. – Luke Puplett Dec 07 '18 at 11:10
  • 1
    Exactly, and how do you know the size of the content inside the viewbox?most of the time you don't know. I think it's a super safe assumption that OP used a static text as example – Matt Dec 08 '18 at 12:18
  • I don't follow. You adjust the size of the content in the ViewBox until it looks right, by eye. For example, I want "This is the text that's" on the top line so I adjust the width of the TextBlock until it wraps at that point. Now it will always look like that even as the whole ViewBox gets bigger or smaller; it'll always be wrapped like that even when stretched across a bus. – Luke Puplett Dec 13 '18 at 21:42
  • Could you bind to the width of the ViewBox? – Chuck Savage Oct 28 '20 at 23:12
2

I had the same issue where I had a lot of buttons where I needed a ViewBox to be able to handle localization. The reason for this is that Width is set to Infinity, because the button or control width is determined by the parent control. Fortunately, controls have a property the is called ActualWidth. This property holds a rendered width and I can use this in a binding:

<Button>
    <Button.Content>
        <Viewbox StretchDirection="DownOnly">
            <TextBlock Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Button}}" TextWrapping="Wrap" TextAlignment="Center" Text="{Binding }" />
        </Viewbox>
    </Button.Content>
</Button>

So the textblock gets the width the Button button currently have. If the button changes width, it is automatically updated. The Textblock will wrap according to the width given and viewbox will only shink when nessesary (providing StretchDirection="DownOnly" is applied).

https://learn.microsoft.com/en-us/dotnet/api/system.windows.frameworkelement.actualwidth?view=netframework-4.8

evilfish
  • 661
  • 8
  • 30
0

You don't have to fix width or maximum of any control. Use a dummy grid and bind to its ActualWidth. See code https://github.com/omeraziz/NoTextOverflowWPF

<Window Title="NoTextOverflow"
    x:Class="NoTextOverflow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="Auto" Height="Auto"
    ResizeMode="CanResize" SizeToContent="WidthAndHeight">

<!--
    There is no fixed width in any of the UI elements including window, Label, TextBlock, TextBox etc.
    Window's SizeToContent grows and shrinks with the contents.
-->

<Grid Margin="10" ShowGridLines="True">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>

    <Label VerticalAlignment="Center" Content="Type Here:" />
    <TextBox x:Name="LongText"
             Grid.Column="1" Grid.ColumnSpan="2"
             Width="{Binding ElementName=WidthRestrictorGrid, Path=ActualWidth, Mode=OneWay}"
             MinWidth="100"
             Margin="5" HorizontalAlignment="Left" VerticalAlignment="Center"
             Text="Type here a long message and resize this window" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" />

    <!--
        This grid is used to calculate width of middle two columns.
        Remove this and its references to see the effect without this grid.
        Since this is not parent of TextBox and TextBlock so it must have a Name to bind with its Actualwidth
    -->

    <Grid x:Name="WidthRestrictorGrid"
          Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"
          Margin="10,1" HorizontalAlignment="Stretch" />

    <TextBlock Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"
               Width="{Binding ElementName=WidthRestrictorGrid, Path=ActualWidth, Mode=OneWay}"
               MinWidth="50"
               Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top"
               Background="LightGray"
               Text="{Binding ElementName=LongText, Path=Text}"
               TextWrapping="Wrap" />

    <Button Grid.Row="2" Grid.Column="3"
            Margin="5" HorizontalAlignment="Right" VerticalAlignment="Bottom"
            Content="Dummy" />

</Grid>
Omer
  • 109
  • 2
  • 6