WPF RichTextBox相关总结

由于公司涉及到聊天对话框的功能,就想到了RichTextBox,查阅相关资料,总结下:

一、RichTextBox的内容相关的类

1.1RichTextBox的内容结构

RichTexBox是个可编辑控件,可编辑我们很容易想到word的可编辑,在word里面我们经常会新建一个Document,然后一段一段的编写,有的时间会插入图片,或者是特殊的文本。同样RichTextBox也是一个以Document为主体的一个控件,Document也有段落(Paragraph),不过段落中是分为小片小片(Inline),我们可以理解为这些Inline被一条线串在段落(Paragragh)中。除此之外,还有些段落(BlockUIContainer)是只含有一个UI元素的,也即独立成段。下面给出其大致的内容结构。

1.2RichTextBox内容相关的类

FlowDocument中有个BlockCollection类型的Blocks属性,也就是“文档”包括的段落。主要有两种类型的Paragraph和BlockUIContainer两种类型的段落,其都继承自Block抽象类。下面介绍一下Paragraph的小弟们,从上图可以看出来小弟很多,其实都是和InLine有关,通常使用Run类表示文本,我们可以通过其属性类控制他的背景色,字体颜色,字体大小等。Hyperlink可以用来指定超链接。。。其中InlineContainer是有些不一样,其有个儿子是UIElement。看后缀名就知道BlockUIContainer和InlineContainer一定有些相似之处,相似的地方是BlockUIContainer也是有个儿子UIElement。当然一个是Inline类型,一个是Block类型。

光说不练,不是好汉,接下来就举几个例子来说明上面的类的特点:

1.3RichTextBox内容相关类的演示

下面我们就用wpf实现与RichtextBox内容相关的类的操作。先说一下需求,在“文档”上面写两端文字,一个是Paragraph类型的段落,一个是BlockContainer类型的段落。其中Paragraph中包括一个红色的文本Run、一个超链接Hyperlink,一个InlineContainer的内含有个TextBlock;BlockUIContainer含有一个图片以及图片说明。

//定义一个段落Paragraph
            Paragraph paragraph = new Paragraph();
            //run
            Run run = new Run() { Text = "我是红色的Run", Background = new SolidColorBrush(Color.FromRgb(255, 0, 0)) };
            paragraph.Inlines.Add(run);
            //Hyperlink
            Hyperlink hyperlink = new Hyperlink();
            hyperlink.Inlines.Add("我是博客园主页的链接");
            hyperlink.MouseLeftButtonDown += ((s, arg) =>
            {
                Process proc = new Process();
                proc.StartInfo.FileName = "http://www.cnblogs.com";
                proc.Start();
            });
            paragraph.Inlines.Add(hyperlink);
            //InlineUIContainer
            InlineUIContainer inlineUIContainer = new InlineUIContainer() { Child = new TextBlock() { Text = "我是的TextBlock,哈哈" } };
            paragraph.Inlines.Add(inlineUIContainer);
            rtb.Document.Blocks.Add(paragraph);

            //下面是BlockUIContainer部分
            Grid grid = new Grid();
            RowDefinition row1 = new RowDefinition();
            grid.RowDefinitions.Add(row1);

            RowDefinition row2 = new RowDefinition();
            grid.RowDefinitions.Add(row2);
            row2.Height = new GridLength(100);
            //定义图片,注意设置资源的类型,始终复制和嵌入
            Image image = new Image() { Source = new BitmapImage(new Uri(("Images/vs.png"), UriKind.Relative)) };
            image.Height = 30;
            image.SetValue(Grid.RowProperty, 0);
            grid.Children.Add(image);
            image.Visibility = Visibility.Visible;
            row2.SetBinding(RowDefinition.HeightProperty, new Binding("Height") { Source = image });
            //定义说明
            TextBlock block = new TextBlock();
            block.Text = "我是图片说明";
            block.SetValue(Grid.RowProperty, 1);
            grid.Children.Add(block);

            BlockUIContainer blockUIContainer = new BlockUIContainer(grid) ;
            rtb.Document.Blocks.Add(blockUIContainer);

show一下结果

二、RichTextBox的定位操作

首先给出定位操作的意思,就是在光标闪烁的地方操作。在看下面的文章时,我希望在我们心中有个word软件。下面主要介绍关于光标的位置和在光标的位置插入相应的元素。

2.1光标的位置

无论光标是否选中一段文字,都有可以获取rtb.Selection的开始位置(Start)和结束位置(End)。可以通过开始位置和结束位置来获取光标位置所在的段落(Paragraph)和父对象(Parent)。父对象其实也就是如果光标在run中间,获取到的就是Run,当选中的是TextBlock时,父对象就是Paragraph。这两个属性各有优略,段落可能获得空值,在操作的时间抛出空指针异常,但得到的类型确定(是属于Block类),父对象不会抛出空指针异常,但是其类型不确定。

2.2在光标处插入对象和替换对象

下面来看看相关内容类的构造函数:

Run:

public Run(string text, TextPointer insertionPosition)

Span:

public Span(Inline childInline, TextPointer insertionPosition);
public Span(TextPointer start, TextPointer end);

Hypelink:
public Hyperlink(Inline childInline, TextPointer insertionPosition);
public Hyperlink(TextPointer start, TextPointer end);
InlineContainer
public InlineUIContainer(UIElement childUIElement, TextPointer insertionPosition); 

……以上我列出了几个非默认的构造类,其他的相关类,就不一一列出。从参数可以看出我们很容易的可以在光标处插入对象。下面只给出其代码片段:

TextPointer textPointer = rtb.Selection.Start;

Run run = new Run("测试", textPointer);

接着是替换对象,我们想把选中的内容替换成指定的内容。下面我给出其实例:

//获取选中部分的开始位置
TextPointer textPointer = rtb.Selection.Start;
//在开始位置插入内容
Run run = new Run("测试", textPointer);
//在插入内容的结尾到原来选中部分的结尾——原来选中部分的文字 清除掉
TextPointer pointer = run.ContentEnd;
TextRange textRange = new TextRange(pointer, rtb.Selection.End);
textRange.Text = "";
//如果使用下面的会把刚刚插入的内容一并删除
//rtb.Selection.Text = "";

对于有开始位置和结束位置的构造函数,可以使用相同的位置来构造,如下:

Hyperlink hypelink = new Hyperlink(textPointer, textPointer);

三、WPF中RichTextBox和工具栏的协同工作

WPF中RichTextBox可以与工具栏协同的命令:ApplicationCommandsEditingCommands,在默认只有一个RichTextBox时,工具栏中的按钮的命令设置为系统命令时就会自动的把命令的目标设置为RichTextBox。下面给出一个实例:

<Grid>
       <Grid.RowDefinitions>
           <RowDefinition Height="1*"/>
           <RowDefinition Height="5*"/>
       </Grid.RowDefinitions>
       <ToolBarTray>
           <ToolBar>
               <Button Command="Undo">撤销</Button>
               <Button  Command="EditingCommands.ToggleBold" ToolTip="Bold">B</Button>
           </ToolBar>
       </ToolBarTray>
       <RichTextBox Name="rtb"  AcceptsTab="True" Grid.Row="1" Grid.ColumnSpan="4"></RichTextBox>
       <!--<Button x:Name="btnAddElement" Content="添加元素" Grid.Row="1" Click="btnAddElement_Click_1" Grid.Column="0" Margin="5"></Button>-->

   </Grid>

当点击撤销按钮时,RichTextBox会撤销操作,同样Bold会黑体操作。当然也可使用下面代码来显式指定按钮的命令目标。

<Style TargetType="{x:Type Button}" x:Key="ImageButtonStyle">
            <Setter Property="CommandTarget" Value="{Binding ElementName=rtb}"></Setter>
 </Style>

四、RichTextBox的XAML转化成HTML以及HTML转化成XAML

在使用RichTextBox时,可能会遇到存储和显示不一致的问题,如在数据库里面是使用fck编辑的html格式,显示的时间要使用RichTextBox显示。或者是使用RichTextBox编辑的内容,要使用html显示。那么这样就会遇到转化问题,微软在这方面已经有为我们做好的类。下面给出链接:

https://github.com/stimulant/SocialStream/tree/master/XAMLConverter

以上转化针对简单的转化,或者是提供了思路,如果遇到特殊的自定义容器,还需要自己去添加。除上面的链接之外,很有必要给出下面两个方法。

//把richtextBox内容转成字符串形式            string strDoc=System.Windows.Markup.XamlWriter.Save(rtb.Document);              //上面的逆操作               StringReader stringReader = new StringReader(strDoc);               XmlReader xmlReader = XmlReader.Create(stringReader);               FlowDocument flowDocument = XamlReader.Load(xmlReader) as FlowDocument;

五、零碎知识点总结

1. 取得已被选中的内容:

(1)使用 RichTextBox.Document.Selection属性

(2)访问RichTextBox.Document.Blocks属性的“blocks”中的Text

2. 在XAML中增加内容给RichTextBox:

<RichTextBox IsSpellCheckEnabled="True">

<FlowDocument>

<Paragraph> <!-- 这里加上你的内容 -->

This is a richTextBox. I can <Bold>Bold</Bold>,

<Italic>Italicize</Italic>,

<Hyperlink>Hyperlink stuff</Hyperlink>

right in my document.

</Paragraph>

</FlowDocument>

</RichTextBox>

3. 缩短段间距,类似<BR>,而不是<P>

方法是使用Style定义段间距:

<RichTextBox>

<RichTextBox.Resources>

<Style TargetType="{x:Type Paragraph}">     

        <Setter Property="Margin" Value="0"/>   

        </Style>

</RichTextBox.Resources>

<FlowDocument>

<Paragraph>

This is my first paragraph... see how there is...

</Paragraph>

<Paragraph>

a no space anymore between it and the second paragraph?

</Paragraph>

</FlowDocument>

</RichTextBox>

4. 从文件中读出纯文本文件后放进RichTextBox或直接将文本放进RichTextBox中:

private void LoadTextFile(RichTextBox richTextBox, string filename)

{     richTextBox.Document.Blocks.Clear();

using (StreamReader streamReader = File.OpenText(filename))

{

Paragraph paragraph = new Paragraph();

paragraph.Text = streamReader.ReadToEnd();

richTextBox.Document.Blocks.Add(paragraph);

}

}
private void LoadText(RichTextBox richTextBox, string txtContent)

{

richTextBox.Document.Blocks.Clear();

Paragraph paragraph = new Paragraph();

paragraph.Text = txtContent;

richTextBox.Document.Blocks.Add(paragraph);

}

5. 取得指定RichTextBox的内容:

private string GetText(RichTextBox richTextBox)

{

TextRange textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);

return textRange.Text;

}

6. 将RTF (rich text format)放到RichTextBox中:

private static void LoadRTF(string rtf, RichTextBox richTextBox)

{

if (string.IsNullOrEmpty(rtf))

{

throw new ArgumentNullException();

}

TextRange textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);

using (MemoryStream rtfMemoryStream = new MemoryStream())

{

using (StreamWriter rtfStreamWriter = new StreamWriter(rtfMemoryStream))

{                     rtfStreamWriter.Write(rtf);

rtfStreamWriter.Flush();

rtfMemoryStream.Seek(0, SeekOrigin.Begin);

//Load the MemoryStream into TextRange ranging from start to end of RichTextBox.

textRange.Load(rtfMemoryStream, DataFormats.Rtf);

}

}

}

7. 将文件中的内容加载为RichTextBox的内容

private static void LoadFile(string filename, RichTextBox richTextBox)

{

if (string.IsNullOrEmpty(filename))

{

throw new ArgumentNullException();

}

if (!File.Exists(filename))

{

throw new FileNotFoundException();

}

using (FileStream stream = File.OpenRead(filename))

{

TextRange documentTextRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);

string dataFormat = DataFormats.Text;

string ext = System.IO.Path.GetExtension(filename);

if (String.Compare(ext, ".xaml",true) == 0)

{

dataFormat = DataFormats.Xaml;

}

else if (String.Compare(ext, ".rtf", true) == 0)

{

dataFormat = DataFormats.Rtf;

}

documentTextRange.Load(stream, dataFormat);

}

}

8. 将RichTextBox的内容保存为文件:

private static void SaveFile(string filename, RichTextBox richTextBox)

{

if (string.IsNullOrEmpty(filename))

{

throw new ArgumentNullException();

}

using (FileStream stream = File.OpenWrite(filename))

{

TextRange documentTextRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);

string dataFormat = DataFormats.Text;

string ext = System.IO.Path.GetExtension(filename);

if (String.Compare(ext, ".xaml", true) == 0)

{

dataFormat = DataFormats.Xaml;

}

else if (String.Compare(ext, ".rtf", true) == 0)

{

dataFormat = DataFormats.Rtf;

}                 documentTextRange.Save(stream, dataFormat);

}

}

WPF RichTextBox相关总结

时间: 2024-10-19 04:18:24

WPF RichTextBox相关总结的相关文章

WPF RichTextBox Flowdocment如何实现自动分页?

需求说明:在不需要Office组件的前提下,利用WPF展现技术.OpenXMLSDK实现Word文档的新建.编辑,只保留基本功能即可,最重要的是要能够根据内容实现自动分页,也要支持手动分页; 最开始,从实现角度考虑,WPF+RichTextBox展现,然后内容通过FlowDocment.Load来加载Word文档,先来看下效果: 那么问题来了,界面中只有一个RichTextBox控件,展示的时候怎么进行分页显示,类似Office Word窗口效果一样呢?怎么实现? 我们都知道Office2007

WPF RichTextBox Flowdocment如何实现自动分页?(二)

使用OpenXML SDK实现按页读取内容: 以下内容采用WPF+RichTextBox+FlowDocment展示,测试文档共3页内容,图中展示的是获取第一页内容,效果图后附上代码:效果图如下: 1 /// <summary> 2 /// 按页加载Word 3 /// </summary> 4 /// <param name="flowDoc"></param> 5 /// <param name="filename&q

WPF RichTextBox的使用总结

RichTextBox内容模型 RichTextBox 支持基于块的内容模型. RichTextBox   的内容属性为 Blocks,这是 Paragraph 元素的集合Paragraph元素可包含从 Inline 派生的元素.上图总结了 RichTextBox 的内容模型,并且显示从 Block 和 Inline 派生的元素是如何适应此模型的. 简单介绍 1.RichTextBox    是一个可支持您显示或编辑丰富内容(包括段落.超链接和内联图像)的控件.本主题介绍 RichTextBox

wpf richtextbox

[转载]WPF操作RichTextBox(转) (2013-03-26 21:59:48) 转载▼ 标签: 转载   原文地址:WPF操作RichTextBox(转)作者: 笨笨发 取出richTextBox里面的内容第一种方法:将richTextBox的内容以字符串的形式取出string xw = System.Windows.Markup.XamlWriter.Save(richTextBox.Document);第二种方法:将richTextBox的类容以二进制数据的方法取出FlowDoc

WPF RichTextBox 禁止换行

原文:WPF RichTextBox 禁止换行 这个问题困扰了好久,进过不断的努力,终于解决了 ? ??????? <RichTextBox Margin="0,44,10,0" Name="codeText" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" HorizontalAlignment="Right&qu

WPF RichTextBox 插入换行 移动光标

原文:WPF RichTextBox 插入换行 移动光标 第一次使用的方法是: richTextBox1.CaretPosition.InsertLineBreak(); richTextBox1.CaretPosition = richTextBox1.CaretPosition.GetNextInsertionPosition(LogicalDirection.Forward); richTextBox1.Focus(); 改方法在win7下正常.但是在win10下,当输入汉字的时候,虽然光

WPF RichTextBox 控件常用方法和属性

以下内容转自 http://blog.csdn.net/yulongguiziyao/article/details/25330551. 1. 取得已被选中的内容: (1)使用 RichTextBox.Document.Selection属性(2)访问RichTextBox.Document.Blocks属性的“blocks”中的Text2. 在XAML中增加内容给RichTextBox:<RichTextBox IsSpellCheckEnabled="True">  

WPF RichTextBox滚动条自动滚动实例、文本自动滚动实例

说明:1.后台代码添加测试 数据 2.使用 richTextBox.ScrollToVerticalOffset()方法,滚动竖直方向滚动条位置 3.使用定时器DispatcherTimer,修改页面显示数据 4.自己计算处理,已经滚动的高度位置 Xaml代码: <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="205*"/> <ColumnDefinition Width=&qu

WPF RichTextBox 如何滚动到光标所在位置、滚动条操作

1.获取当前滚动条位置 //获取当前滚动条位置 richTextBox.VerticalOffset; richTextBox.HorizontalOffset; //获取当前光标位置 richTextBox.CaretPosition 2.滚动到开始,结束,指定位置 // // 摘要: // 将编辑控件的视图设置为内容的末尾. public void ScrollToEnd(); // // 摘要: // 将编辑控件的 " 视图到视区的开头. public void ScrollToHome(