Creating Scrollable TextBlock for WP7.

There could be many scenarios when you'd need to be able to dipslay a text in your WP7 application which doesn't fit on the screen. The easiest way to approach to solve this would be to utilize the ScrollViewer control as a host for a TextBlock. Something like that:

 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
      <ScrollViewer>
            <TextBlock x:Name="textBlock" TextWrapping="Wrap" />
      </ScrollViewer>
 </Grid>

You would think that we're done but as usual the "devil is in the details". If you assign a long text to the TextBlock you will see that part of this text could be truncated and an empty space would be displayed when scrolling to the end:

 The reason for this behavior is that any element that must be displayed beyond the area which is larger than 2048x2048 pixels would be clipped by the platform. I was told that this limitation had been dictated by a combination of hardware limitation and performance considerations. To workaround this limitation we'd need to break out the text into a separate blocks and create a TextBlock for each of this text blocks. So to make the life easier for myself and for you I created a custom control which I called ScrollableTextBlock which wraps this logic. So I created a custom control which derives from Control and implements Text property:

     public class ScrollableTextBlock : Control
    {
        private StackPanel stackPanel;
        
        public ScrollableTextBlock()
        {
            // Get the style from generic.xaml
            this.DefaultStyleKey = typeof(ScrollableTextBlock);           
        }
 
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register(
                "Text",
                typeof(string),
                typeof(ScrollableTextBlock),
                new PropertyMetadata("ScrollableTextBlock", OnTextPropertyChanged));        
 
        public string Text
        {
            get
            {
                return (string)GetValue(TextProperty);
            }
            set
            {
                SetValue(TextProperty, value);
            }
        }
 
        private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ScrollableTextBlock source = (ScrollableTextBlock)d;
            string value = (string)e.NewValue;
            source.ParseText(value);
        }

            }

And here's the ParseText method which is also a part of this control:

     private void ParseText(string value)
    {
         if (this.stackPanel == null)
         {
             return;
         }
         // Clear previous TextBlocks
         this.stackPanel.Children.Clear();
         // Calculate max char count
         int maxTexCount = this.GetMaxTextSize();
 
         if (value.Length < maxTexCount)
         {
             TextBlock textBlock = this.GetTextBlock();
             textBlock.Text = value;
             this.stackPanel.Children.Add(textBlock);
         }
         else
         {
             int n = value.Length / maxTexCount;
             int start = 0;
             // Add textblocks
             for (int i = 0; i < n; i++)
             {                    
                 TextBlock textBlock = this.GetTextBlock();
                 textBlock.Text = value.Substring(start, maxTexCount);
                 this.stackPanel.Children.Add(textBlock);
                 start = maxTexCount;
             }
 
             // Pickup the leftover text
             if (value.Length % maxTexCount > 0)
             {
                 TextBlock textBlock = this.GetTextBlock();
                 textBlock.Text = value.Substring(maxTexCount * n, value.Length - maxTexCount * n);
                 this.stackPanel.Children.Add(textBlock);                   
             }
         }
     }

In the code above I measure the text length and if it's greater that maxTextCount I break the text into a separate blocks and create a new TextBlock with this text. After the TextBlock is created I add it to the StackPanel. To make a picture complete here's how the control's style looks like:

    <Style TargetType="local:ScrollableTextBlock" >
        <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMedium}"/>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="Width" Value="200" />
        <Setter Property="Height" Value="70" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ScrollableTextBlock">
                    <ScrollViewer x:Name="ScrollViewer" Foreground="{TemplateBinding Foreground}" 
                                  Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" 
                                  BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
                        <StackPanel Orientation="Vertical" x:Name="StackPanel" />
                    </ScrollViewer>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

As you can see, the StackPanel is located inside of the ScrollViewer control which provides the scrolling functionality.  And after we execute the test project the result is that the text is not truncated:

 

The test project and the ScrollableTextBlock control is available for your peruse.

Comments

  • Anonymous
    September 20, 2010
    Nice, Very useful, and the article too. about Google Instant, lol Thumbs way up!.

  • Anonymous
    September 20, 2010
    Just a heads up, it looks like that if their is a newline (e.g. multiple newlines) in the string it won't showup correctly.

  • Anonymous
    September 24, 2010
    Haha, I was wondering why my TextBlock I put in a ScrollViewer was being trucated a couple weeks ago! :)

  • Anonymous
    September 29, 2010
    Awesome thanks a lot for this very useful! (Not sure why it isn't an official default control!)

  • Anonymous
    November 27, 2010
    Hi all, I download the source code, it is working fine, but when i want to bind data it is not working, here is my source code :            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">            <my:ScrollableTextBlock  Text="{Binding LineOne}"                        HorizontalAlignment="Left"  Name="scrollableTextBlock1"                  VerticalAlignment="Top" Height="618" Width="427" Margin="12,-11,0,0" />            </Grid> Could you help me ?? Thanks Best regards

  • Anonymous
    December 07, 2010
    Bro, legend! Wasn't aware of the 2048x2048 thingy...it was killing me.  Your control is working sweet. Thanks

  • Anonymous
    December 07, 2010
    start = maxTexCount should probably start += maxTexCount; else it wont work for more then one page.

  • Anonymous
    January 06, 2011
    Hi, really great control! Unfortunately it doesn't work if there are newlines (n) or if the fontsize is larger than normal. A patch would be nice. Greetings, Andreas Balzer Microsoft Student Partners

  • Anonymous
    January 06, 2011
    Hi, really great control! Unfortunately it doesn't work if there are newlines (n) or if the fontsize is larger than normal. A patch would be nice. Greetings, Andreas Balzer Microsoft Student Partners

  • Anonymous
    January 16, 2011
    if I wanted to place the long textblock inside a scoller with other elements, how should I modify it? thank you in advance

  • Anonymous
    January 30, 2011
    The comment has been removed

  • Anonymous
    February 16, 2011
    Anyone knows how to make this work with databinding?

  • Anonymous
    April 07, 2011
    Hey, as the others have mentioned, this is nice but has some problems if there are multiple sequential newlines. The measuring part calculates the height as too short and text is truncated. I've tried to take a look at the code and will keep doing it, but in the meantime, anybody found a fix for this ?

  • Anonymous
    April 07, 2011
    quick follow up: it appears the problem is solved by linking the release dll to a release project and debug dll to a debug project. Or at least it seems so...

  • Anonymous
    April 27, 2011
    I have a fix for the sequential newline issue. I also fixed another problem I came across. ScrollableTextBlock tries to do some optimization, so that if the input text is below a certain character count, it will use it directly instead of parsing and splitting the text. However the formula doesn't work when the lines of text are very short. I posted the fixes in the developer forum: forums.create.msdn.com/.../482173.aspx

  • Anonymous
    June 06, 2011
    I am having issues while aligning text. how do i center align the text.

  • Anonymous
    June 07, 2011
    The comment has been removed

  • Anonymous
    July 21, 2011
    How to use this controller if I want scroll textblock horizzontally?

  • Anonymous
    November 06, 2011
    could anybody tell me how to link ScrollableTextblock project to my project. I added a reference Phone.control.dll to my project. but I still cannot add the toolbox into my xaml page ie <my:ScrollableTextblock..............> thanks a lot

  • Anonymous
    November 07, 2011
    to use the Phone.Control 1, add reference to your project

  1. add shell:SystemTray.IsVisible="True" xmlns:my="clr-namespace:Phone.Controls;assembly=Phone.Controls"> to your xaml file. I want to point two things here. one when the context is too long the GUI will stuck. I think a thread may be used to push content to the stack and another will show on the screen. this is good generally.
  • Anonymous
    November 15, 2011
    An easier way for me has been to set the TextBlock Height property to Auto: For instance:        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">            <ScrollViewer>                <TextBlock Height="Auto" HorizontalAlignment="Left" Margin="12,6,0,0" Name="tbScroll" VerticalAlignment="Top" Width="438" TextWrapping="Wrap" TextAlignment="Center" />            </ScrollViewer>        </Grid>

  • Anonymous
    December 08, 2011
    Is it possible to set the ScrollToVerticalOffset using the above control. I want to scroll the text automatically without any user input. Please let me know

  • Anonymous
    March 05, 2012
    this.GetTextBlock() doesn't seem to work. is there a full working sample that I can copy from?

  • Anonymous
    March 12, 2012
    The comment has been removed

  • Anonymous
    July 03, 2012
    How can I implkement this logic for RichTextBox?

  • Anonymous
    November 07, 2012
    useful control and good contribution ( Cojocaru ) to solve the newline issue.

  • Anonymous
    November 13, 2012
    Where I can find the fix of of the newline issue? :(

  • Anonymous
    December 06, 2012
    How to use RichTechBox in place of TextBlock in That ScrollableTextBlock.cs . I try to use but its not supporting here any one please help?..me

  • Anonymous
    March 25, 2013
    The workaround proposed in the article works fine if you only need to display long content of text. Take a look at the following workaround if you need to edit long content of text in Windows Phone: daniloercoli.wordpress.com/.../edit-long-content-of-text-in-win-phone-7

  • Anonymous
    August 27, 2013
    Here is yet another implementation of the ScrollableTextBlock that focuses on performance optimization. blogs.msdn.com/.../yet-another-scrollable-textblock-for-windows-phone.aspx

  • Anonymous
    October 30, 2013
    It's takes lots of time to load content, How can I implement a loading indicator for this textblock control ?

  • Anonymous
    November 04, 2013
    when it comes to this scenario how can you increase the font size by giving it to a button click private void ApplicationBarIconButton_Click_3(object sender, EventArgs e)        {            if (ScrollableTextBlock.FontSize < 21.5)            {                ScrollableTextBlock.FontSize += 1;            }         } this does not increase the text size  i'm using the same data template

  • Anonymous
    November 24, 2013
    agreed with naveen neither font size changing or text alignment works with it.

  • Anonymous
    November 25, 2013
    Another problem that i am facing is that if we use two scrolltextblock first update correctly but second stuck to previous value

  • Anonymous
    February 14, 2014
    We got the solution for Textblock control but we have problem using long HTML content to be displayed in the Windows Phone application. We have used richtextbox and displaying HTML content in it by generating multiple richtextbox. But it has very poor performance and not loading HTML content till 8-10 seconds. We are splitting content in small blocks and storing it in phone isolated storage and loading those content dynamically by generating richtextbox. But it has very poor and bad performance. If you have any better suggestion, please mail it to tanmay@innodel.com

  • Tanmay.
  • Anonymous
    May 29, 2014
    can you please upload this solution once again!!!!

  • Anonymous
    June 26, 2014
    The odd thing: Works well on the 256MB emulator ("the small one") but on a real device (e.g. Lumia 920) I get that issue. Deploying the same XAP ....

  • Anonymous
    July 14, 2014
    Just for information: MessageBox seems not having such a (small) limitation.

  • Anonymous
    November 24, 2014
    i read website here blogs.msdn.com/.../creating-scrollable-textblock-for-wp7.aspx and social.msdn.microsoft.com/.../create but I can not find the function GetTextBlock GetTextBlock function, anyone can help me

  • Anonymous
    November 24, 2014
    i read website here blogs.msdn.com/.../creating-scrollable-textblock-for-wp7.aspx and social.msdn.microsoft.com/.../create but I can not find the function GetTextBlock GetTextBlock function, anyone can help me

  • Anonymous
    March 17, 2015
    Where is the function GetTextBlock? Also the hyperlink in "is available for your peruse" isn't working. Please help.

  • Anonymous
    July 02, 2015
    My textblock text is static....(I mean I will put there) and it must be scrollable.... Is it possible ??

  • Anonymous
    July 24, 2015
    The comment has been removed