本文内容适用于Runtime App框架
在用户界面上显示文本,用得严重多的是TextBlock,凡是轻量级的东西都会很常用,TextBlock对于显示简单、少量的文本内容相当适合,不过,在我们考虑要在用户界面上显示格式较为复杂,并且内容相当长的文本时,就得使用RichTextBlock了。
多了一个Rich在前面就不得了,Rich原义为丰富的意思,所以该控件既能显示较长的文本,而且还能支持更多的文档格式。在RichTextBlock中,能过Blocks集合来设置内容,而Block类是抽象的,不能直接用,然它只有一个子类——Paragraph。
如其名,Paragraph表示一个段落。也就是说,在RichTextBlock控件中,文本内容可以由N个段落组成,关于什么叫段落,不要问我,如果你不知道段落是啥,请买上一壶好酒,一只肥鸭去回访你的小学语文老师。
好了,既然要显示大量文本,而我们手机的屏幕大小是有限的,如果屏幕空间不足够用来显示文本内容,该怎么办呢? 有朋友马上想到,啊,用ScrollViewr就可以滚动了。对,这也是一种方法,而且是一种相当简单的方法,把RichTextBlock直接用ScrollViewer包裹起来就可以了,不错的方案。
不过,有时候我们会想,滚动一般是保留垂直滚动,同时开启水平和垂直滚动不好,用户操作起来麻烦,又要左右滑,又要上下滑动,多么痛苦啊。而且,光是滚动好像还不够“新意”,现在的人很幽默,做什么事情都要“新”,好像不新就不行似的,都是被某些反面思想给害了。
好,P话不说,咱们说重点。RichTextBlock类有两个好玩的属性,大家要注意一下的。
HasOverflowContent:如果分配的空间不够用,文本内容显示不全,有溢出现象,该属性就会为true。
OverflowContentTarget:设置一个RichTextBlockOverflow对象,溢出来的文本会自动转到这个RichTextBlockOverflow对象上显示。为什么可以在界面上显示?因为RichTextBlockOverflow类继承了FrameworkElement,当然可以在界面上使用了。
别兴奋,还没完,你再看看RichTextBlockOverflow类,看清楚,是不是看到它也有HasOverflowContent和OverflowContentTarget属性? 看到了吗?
这就是说,如果这个RichTextBlockOverflow还不够用,文本太长,仍然溢出来了,这时候它的HasOverflowContent属性也为true,这时候,可以将RichTextBlockOverflow的OverflowContentTarget属性也赋值一个新的RichTextBlockOverflow对象。不断循环,直到文本不再溢出为止。
这好比一条锁链,每一节环环相扣。
现在,大家知道原理了,我们可以开工了,试试吧。
<FlipView x:Name="flpview">
<RichTextBlock x:Name="rtBlock" FontSize="20" TextIndent="38" Loaded="OnRichtextblockLoaded">
<Paragraph TextAlignment="Center" TextIndent="0" Margin="0,7,0,21">
<Bold FontSize="36" >关于二胡</Bold>
</Paragraph>
……
</RichTextBlock>
</FlipView>
假设这个RichTextBlock中有很多文本(这里我省略了,没必要贴出来)。
把RichTextBlock作为FlipView的项放进去,FlipView也是一个列表控件,但它每次只显示一个项,可以通过左右滑动来查看其他项,有点像翻页效果。假如RichTextBlock的文本很长,没法显示完全,接下来我们通过代码来动态添加N个RichTextBlockOverflow对象,直到文本被完全显示为止。
这些代码最好写在RichTextBlock控件的Loaded事件处理方法中,可确保文本已经被加载。
private void OnRichtextblockLoaded ( object sender, RoutedEventArgs e )
{
if (this.rtBlock.HasOverflowContent)
{
RichTextBlockOverflow flow = new RichTextBlockOverflow();
rtBlock.OverflowContentTarget = flow;
flpview.Items.Add(flow);
flow.UpdateLayout(); //刷新布局
bool hasFlow = flow.HasOverflowContent;
while (hasFlow)
{
RichTextBlockOverflow tmp = flow;
flow = new RichTextBlockOverflow();
tmp.OverflowContentTarget = flow;
this.flpview.Items.Add(flow);
flow.UpdateLayout();
hasFlow = flow.HasOverflowContent;
}
}
}
利用循环不断地向FlipView中添加RichTextBlockOverflow对象,不过一定得注意,每添加一个RichTextBlockOverflow对象都要调用它的UpdateLayout方法,目的是让它进行布局计算,并且放置好文本,最终才能决定内容是否溢出,HasOverflowContent属性的值才会准确。
运行应用程序后,可能有些朋友发现问题了,为什么后面的内容没了? 当滑到后面时,前面的内容又没了? 这是怎么回事? 老周在骗人吗?
是啊,我是在骗你呢,造成这个问题是因为FlipView也是ItemsControl,列表控件默认是使用虚拟化的,当某些项不在屏幕上呈现时,这些项会被XX,所以导致后面的内容空白,而前面的文本会丢失的原因,因为我们并不是通过数据绑定设置的项列表,故无法被正确还原。
解决这个问题也不难,只要为FlipView指定一个非虚拟化的面板就可,这里我选用StackPanel,也只有它最合理。把XAML代码改为:
<FlipView x:Name="flpview">
<FlipView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</FlipView.ItemsPanel>
……
这样一来,就不会出现文本丢失的问题了。
看看效果吧,还不错的。
示例源代码下载:http://files.cnblogs.com/tcjiaan/%E5%A4%84%E7%90%86%E6%BA%A2%E5%87%BA%E6%96%87%E6%9C%AC.zip
好了,吃饭去。