views:

802

answers:

2

I have a TextBlock within a ScrollViewer that aligns with stretch to its window. I need the TextBlock to behave as the following:

  • Resizes with window, no scrollbars
  • When resized below a certain width the TextBlock needs to keep a MinWidth and scrollbars should appear
  • TextWrapping or TextTrimming should work appropriately

How can I get this functionality?

I have tried several ways, involving bindings to ActualWidth & ActualHeight, but can't get it to work.

This can't be that difficult, what am I missing?

Here is a code sample to put in XamlPad (no MinWidth is set yet):

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
            <TextBlock TextWrapping="Wrap" Text="Some really long text that should probably wordwrap when you resize the window." />
    </ScrollViewer>
</Window>
+1  A: 

Without more detail, the best I can do is provide the standard way of doing this. Basically, host your element (which has a minimum size) in a scroll viewer; when the scrollviewer is resized small enough such that the element cannot wholly fit inside it, it will automatically display scroll bars. Example:

<ScrollViewer>
    <Button MinWidth="100" MinHeight="50"/>
</ScrollViewer>
Aviad P.
Hmm, this works in XamlPad, but not in my application. I will have to do some digging to figure out why.
Jonathan.Peppers
It's because my control is a TextBlock. See my edit above.
Jonathan.Peppers
What exactly is the behavior you are trying to achieve? It should work when you set `MinWidth` and `MinHeight` on the `TextBlock` as well.
Aviad P.
The TextBlock never resizes when you resize the window if you try the above in XamlPad.
Jonathan.Peppers
Oh I see what you mean, it's because of text wrapping. Working on it :)
Aviad P.
My example below does not work 100%. When a vertical scrollbar appears, there is always a horizontal scrollbar visible even when there shouldn't be. Did you ever find another way? Otherwise I'll have to also bind to the ComputedScrollBarVisibility and subtract the SystemParameters.ScrollBarWidth (or whatever it's called).
Jonathan.Peppers
I haven't found another way, and TBH it's much more complex that I first imagined. The scrollviewer measure and arrange logic is not trivial (to say the least) and to mimic that is a lot of work and trying to figure out using reflector what is happening behind the scenes.
Aviad P.
I've actually found that binding to the ViewportWidth of my ScrollViewer fixes my issue more elegantly. Not sure if that is any better than binding to ActualWidth--I updated my other answer to reflect this.
Jonathan.Peppers
+4  A: 

This works:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Name="Scroller">
            <TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="100" Width="{Binding ElementName=Scroller, Path=ViewportWidth}"
            TextWrapping="Wrap" Text="Some really long text that should probably wordwrap when you resize the window." />
    </ScrollViewer>
</Window>
Jonathan.Peppers
Yes, that's one way, although it can cause the layout engine to loop several times on the visual tree because the width binding happens after the rendering, which forces another layout pass.
Aviad P.
Is there another way?
Jonathan.Peppers
Yes the proper way would be to modify the measure and arrange logic for either the scroll viewer, the textblock, or some custom element in between. I've been wracking my brain trying to figure it out since I wrote that comment 'I'm working on it' :)
Aviad P.
I certainly notice it seems a little laggy on my machine (in my full app with complicated layout) when resizing the window, if you figure out a way to prevent the extra layout pass--that would be great.
Jonathan.Peppers
+1 - Thanks for taking the time to research this. This might be as good as it gets without a massive code rewrite :)
Aviad P.
THANK YOU! THANK YOU! THANK YOU! OMG I just spent 2 hours looking for the solution and Binding to ViewportWidth did the trick! Thank you ever so much.
Kirill Osenkov