新时尚Windows8开发(16):如何处理溢出文本
老周的博客http://blog.csdn.net/tcjiaan,转载请注明原作者和出处。
准确地说,本文是与各位分享一下小技巧。也不知道各位喜不喜欢。
嗯,废话就不说了,先看看我要实现什么样的运行结果。
是的,很像报纸的排版效果,那么,怎么做到的呢?
这就要提到一个类——RichTextBlockOverflow。他的用途就是,当RichTextBlock中的文本溢出后(就是当前RichTextBlock显示不完比较长的文本),可以在RichTextBlockOverflow上接着显示。
RichTextBlock的OverflowContentTarget属性设置为要接着显示文本的RichTextBlockOverflow,如果第一个RichTextBlockOverflow仍然不够用,则可以添加更多的RichTextBlockOverflow,只要把前一个的RichTextBlockOverflow的OverflowContentTarget属性设置为新的RichTextBlockOverflow,以此类推。
要判断文本是否溢出,可以通过HasOverflowContent属性获得。
好了,大概原理说了,下面就是动手实现了。
1、启动Visual Studio for Win 8 ,新建一个项目。
2、MainPage.xaml比较简单,按钮是为了选取一个较长的文本文件,文本框用于输入字体大小。用于排列文本的是一个StackPanel。
<Page x:Class="App1.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:App1" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="25"> <Button Content="打开文件" Click="onClick"/> <TextBlock Text="字体大小" Margin="37,0,0,0" FontSize="24" VerticalAlignment="Center"/> <TextBox Name="txtSize" VerticalAlignment="Center" Margin="8,0,0,0" Width="130" Text="16"> <TextBox.InputScope> <InputScope> <InputScope.Names> <InputScopeName NameValue="Number"/> </InputScope.Names> </InputScope> </TextBox.InputScope> </TextBox> </StackPanel> <ScrollViewer Margin="15" Grid.Row="1" HorizontalScrollBarVisibility="Auto" HorizontalScrollMode="Auto"> <StackPanel Name="stPanel" Orientation="Horizontal" /> </ScrollViewer> </Grid></Page>
3、对于后台的代码,先贴出完整的吧。
using System;using System.Collections.Generic;using System.IO;using System.Linq;using Windows.Foundation;using Windows.Foundation.Collections;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Controls.Primitives;using Windows.UI.Xaml.Data;using Windows.UI.Xaml.Input;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Navigation;using Windows.Storage;using Windows.Storage.Streams;using Windows.Storage.Pickers;using Windows.UI.Xaml.Documents;namespace App1{ public sealed partial class MainPage : Page { const double CT_WIDTH = 400d; //文本块的宽度 const double CT_HEIGHT = 500d; //文本块的高度 const double CT_MARGIN = 25d; //文本块的边距 public MainPage() { this.InitializeComponent(); } private async void onClick(object sender, RoutedEventArgs e) { // 从文本文件中读取内容 FileOpenPicker opPicker = new FileOpenPicker(); opPicker.FileTypeFilter.Add(".txt"); opPicker.CommitButtonText = "打开"; opPicker.SuggestedStartLocation = PickerLocationId.Desktop; StorageFile file = await opPicker.PickSingleFileAsync(); if (file != null) { using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read)) { // 从流中读取文本,考虑utf-8读出来的是乱码, // 改用Stream类来读取 // 使用gb2312编码格式 string msg = string.Empty; using (Stream strm = stream.AsStream()) { StreamReader render = new StreamReader(strm, System.Text.Encoding.GetEncoding("gb2312")); msg = render.ReadToEnd(); } // 去掉特殊的换行符 msg = msg.Replace(" ", "").Replace("\n", "").Replace("\r","\n").Replace("\t",""); stPanel.Children.Clear(); // 为了支持文本分块,使用RichTextBlock RichTextBlock tbContent = new RichTextBlock(); tbContent.Width = CT_WIDTH; tbContent.Height = CT_HEIGHT; tbContent.TextWrapping = TextWrapping.Wrap; tbContent.Margin = new Thickness(CT_MARGIN); Paragraph ph = new Paragraph(); ph.TextIndent = 33; Run txtRun = new Run(); txtRun.Text = msg; ph.Inlines.Add(txtRun); tbContent.Blocks.Add(ph); tbContent.FontSize = Convert.ToDouble(txtSize.Text); stPanel.Children.Add(tbContent); // 更新一下状态,方便获取是否有溢出的文本 tbContent.UpdateLayout(); bool isflow = tbContent.HasOverflowContent; // 因为除了第一个文本块是RichTextBlock, // 后面的都是RichTextBlockOverflow一个一个接起来的 // 所以我们需要两个变量 RichTextBlockOverflow oldFlow = null, newFlow = null; if (isflow) { oldFlow = new RichTextBlockOverflow(); oldFlow.Width = CT_WIDTH; oldFlow.Height = CT_HEIGHT; oldFlow.Margin = new Thickness(CT_MARGIN); tbContent.OverflowContentTarget = oldFlow; stPanel.Children.Add(oldFlow); oldFlow.UpdateLayout(); // 继续判断是否还有溢出 isflow = oldFlow.HasOverflowContent; } while (isflow) { newFlow = new RichTextBlockOverflow(); newFlow.Height = CT_HEIGHT; newFlow.Width = CT_WIDTH; newFlow.Margin = new Thickness(CT_MARGIN); oldFlow.OverflowContentTarget = newFlow; stPanel.Children.Add(newFlow); newFlow.UpdateLayout(); // 继续判断是否还有溢出的文本 isflow = newFlow.HasOverflowContent; // 当枪一个变量填充了文本后, // 把第一个变量的引用指向当前RichTextBlockOverflow // 确保OverflowContentTarget属性可以前后相接 oldFlow = newFlow; } } } } }}
其实,重点就是循环加入文本块的地方,代码中我也做了注释。