Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scrollable TextBlock Sized EXACTLY 2 Lines High

I need the text to display - at most -2 lines - with no vert scroll visible, then show the scroll when greater than 2 lines:

<Border BorderBrush="Black" BorderThickness="1" Grid.Row="1" Grid.ColumnSpan="2">
    <ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="40">
        <TextBlock Text="{Binding RoadsString}" Style="{StaticResource WrapTextStyle}"/>
    </ScrollViewer>
</Border>

I can experiment with the MaxHeight value until it's looks right - but I'd prefer that it accommodate whatever font is specified and ... precise. Preferably in XAML.

Can I bind MaxHeight to the font size? Or perhaps there a TextBlock property I haven't found.

Thanks, Dan

like image 279
HoltDan Avatar asked May 11 '11 22:05

HoltDan


2 Answers

Would a readonly borderless TextBox work for you as a TextBlock?

<TextBox MinLines="2" MaxLines="2" IsReadOnly="True" BorderThickness="0"
VerticalScrollBarVisibility="Auto" Width="200" VerticalAlignment="Top" />

MinLines and MaxLines would restrict textbox to always have exactly two lines (except if you set Height explicitly - If the Height property is explicitly set on a TextBox, the MaxLines and MinLines property values are ignored).

One problem I see with this approach is that the TextBox's text won't be left aligned with other textblocks (if you have placed them in same column of a grid).

EDIT: Just noticed that you actually want a border for your textblock. For that you can get rid of BorderThickness="0" part.

like image 116
publicgk Avatar answered Nov 03 '22 00:11

publicgk


One of the simpler solutions (without getting into measuring strings and calculating margins, padding, etc. in a value converter) is to make a hidden (not collapsed) TextBlock that only has however many lines you want and bind its ActualHeight to the visible TextBlock's MaxHeight. The invisible TextBlock used as the measure must have its Visibility set to Hidden so that it is still part of layout calculations even if it isn't shown (Collapsed will cause it to disappear altogether).

Here's a demonstration you can throw into a new project to see it work (I use 4 lines to make the scrollbar easier to use).

This part replaces the default Grid inside the Window:

<Grid TextElement.FontSize="12">
    <TextBlock Name="limiter"
               HorizontalAlignment="Left"
               VerticalAlignment="Top"
               Width="100"
               Visibility="Hidden"
               Background="Gray">
    </TextBlock>
    <ScrollViewer MaxHeight="{Binding ElementName=limiter, Path=ActualHeight}"
                  Margin="40,0"
                  VerticalAlignment="Top"
                  HorizontalAlignment="Stretch"
                  Background="LightGray"
                  VerticalScrollBarVisibility="Auto">
        <TextBlock Name="vis" />
    </ScrollViewer>
    <Button Name="AddLine"
            Padding="8"
            VerticalAlignment="Bottom"
            HorizontalAlignment="Center"
            Click="AddLine_Click">Add A Line</Button>
</Grid>

In the Window's constructor I add the however many lines I want to the hidden TextBlock (you could also use Run and LineBreak elements in the XAML):

var limitString = "AgjZ";
limitString = limitString + Environment.NewLine + limitString + Environment.NewLine + limitString + Environment.NewLine + limitString;
limiter.Text = limitString;

The Button's AddLine_Click handler looks like this, so you can see the effect with different numbers of lines:

private int counter = 0;
private void AddLine_Click( object sender, RoutedEventArgs e ) {
    var newline = string.Empty;
    if ( !string.IsNullOrWhiteSpace( vis.Text ) )
        newline = Environment.NewLine;
    vis.Text += string.Format( newline + "This is line #{0}.", ++counter );
}

Remember that the hidden TextBlock needs to be in pretty much the same scope as the one you want to show so that it inherits FontSize and other font-related values. If anything is set on the ScrollViewer or visible TextBlock, it needs to go on the hidden TextBlock, too. You could also use binding to make sure the hidden one has the same style as the visible one.

like image 44
Joel B Fant Avatar answered Nov 03 '22 01:11

Joel B Fant