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 regardsAnonymous
December 07, 2010
Bro, legend! Wasn't aware of the 2048x2048 thingy...it was killing me. Your control is working sweet. ThanksAnonymous
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 PartnersAnonymous
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 PartnersAnonymous
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 advanceAnonymous
January 30, 2011
The comment has been removedAnonymous
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.aspxAnonymous
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 removedAnonymous
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 lotAnonymous
November 07, 2011
to use the Phone.Control 1, add reference to your project
- 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 knowAnonymous
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 removedAnonymous
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?..meAnonymous
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-7Anonymous
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.aspxAnonymous
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 templateAnonymous
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 valueAnonymous
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 meAnonymous
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 meAnonymous
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