תשובה Wrapping TextBlock in ScrollViewer - any elegant solution?

  • יום רביעי 03 ינואר 2007 10:36
     
     
    Hi all,

    Is anybody here aware of any elegant solution to make TextBlock nested in ScrollViewer properly wrap to available width in parent container instead of displaying the text on single line and enlarging the width of parent container? I'll elaborate...

    Intuitively, I'd suppose this XAML should accomplish the task:

    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <Grid Name="Grid">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0">
                This text should be on one line and never wrap. This text should be on one line and never wrap.
            </TextBlock>
            <TextBlock TextWrapping="Wrap" Grid.Row="1">
                I want this text to wrap properly to width of the parent. I want this text to wrap properly to width of the parent. I want this text to wrap properly to width of the parent.
            </TextBlock>
        </Grid>
    </ScrollViewer>

    Unfortunately it doesn't. The second TextBlock, even though the TextWrapping property is set properly, does not wrap the text. Quick and dirty solution is to limit maximum width of the second TextBlock by binding its MaxWidth to ActualWidth of the parent grid:

    ... Grid.Row="1" MaxWidth="{Binding ElementName=Grid, Path=ActualWidth}">...

    This is not very elegant solution though, because there are scenarios where it's not easy to bind to container's ActualWidth. In my case I've got an application which displays arbitrary content - it provides view models for different types of content and allows users to provide styles and templates to use to render the content in the container created by this application. This container incorporates ScrollViewer because some content may require Width/Height larger than what's available. Now, the styles/templates provided by users are not aware of environment they are embedded in, so they cannot use the MaxWidth trick above, and even if they could, it would not be a correct solution, because it would create an undesirable dependency on the surrounding environment which would mean that some changes to this environment (container) might require changes to styles/templates.

    So the simple question is - is there a way to make TextBlock wrap even though it is nested in ScrollViewer without creating dependency on parent visual elements?

    Thanks very much for suggestions.

    Martin

כל התגובות

  • יום רביעי 03 ינואר 2007 11:08
     
     

    Is this a trick question?  If you just place the first textblock inside a Scrollviewer, the second textblock will wrap. Well, you do get the scrollbar inbetween the textblocks visually, which might be what you're trying to avoid... ? If you do like you did before, the parent of the second textbox is the scrollviewer which expands to the size of the first textblock. The only way to avoid that is just like you mentioned yourself, databind the width of the second textblock to something, or set it fixed.

        <Grid Name="Grid">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
                <TextBlock Grid.Row="0">
                    This text should be on one line and never wrap. This text should be on one line and never wrap.
                </TextBlock>
            </ScrollViewer>
            <TextBlock TextWrapping="Wrap" Grid.Row="1">
                I want this text to wrap properly to width of the parent. I want this text to wrap properly to width of the parent. I want this text to wrap properly to width of the parent.
            </TextBlock>
        </Grid>

  • יום רביעי 03 ינואר 2007 11:46
     
     
    You're right - I want only one scrollbar at the bottom. I'll try to make up some better example to illustrate my problem...

    Let's say I've got an usual form - like the form we see on many web pages. This form contains many elements - some wrappable (like TextBlocks and TextBoxes), some not wrappable (like Images etc.). I want to display this form in a container unknown to this form and I want wrappable elements to wrap to available width and non-wrappable elements to display in width/height they need. The container in which the form is contained incorporates ScrollViewer to display scrollbars in case there are non-wrappable elements which do not fit to available space.

    I see no way how to do this in XAML. Even the MaxWidth trick above is not the correct solution - if the parent container is resizable and you resize it to larger width and then back, it never wraps back.

    All the XAML gurus, please, what's correct solution for this use case?
    I'll be glad to elaborate if the description is not clear enough.

    Thanks.

    Martin
  • יום שישי 09 פברואר 2007 05:53
     
     תשובה

    Cant be done, not with ScrollViewer *and* TextBlock.

    ScrollViewer first asks its content how large it would like to be in the absence of constraints, if the content requires more space than the Viewer has then its time to kick in some ScrollBars

    In the absence of constraints TextBlock will always opt to return a size where all text fits on a single line.

    A ScrollViewer with ScrollBars will never get a TextBlock to wrap.

    However you may be able to come up with a Measure\Arrange combination for a panel of your own that is almost like ScrollViewer but I cant think of any logic that can satify both constraints without explicit knowlege of the behaviour of said children

    --Ifeanyi Echeruo [MSFT]

  • יום שני 16 אפריל 2012 13:05
     
      קוד כלול

    I know it has been years and nobody cares anymore, but this is the solution I have used:

    <ScrollViewer VerticalScrollBarVisibility="Auto">
    	<ContentControl Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ScrollContentPresenter}}}" Content="..."/>
    </ScrollViewer>

    I bind the ActualWidth of the internal  ScrollContentPresenter to the Width of the scroll content (can be anything, not just the ContentControl).  It is important to bind to the "ScrollContentPresenter" as you content will accommodate the vertical scrollbar that may automatically be displayed.

    For the purpose of the original post, only bind the Width of the second TextBlock to wrap to the ActualWidth of the ScrollContentPresenter, this will allow the first text block to stretch the ScrollViewer to fill a single line but the second TextBlock will be constrained to the calculated width of the ScrollContentPresenter.


    • נערך על-ידי Chris_Ottawa יום שני 16 אפריל 2012 13:06
    •