由于公司涉及到聊天对话框的功能,就想到了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相关总结的更多相关文章

  1. WPF RichTextBox自动调整高度

    原文:WPF RichTextBox自动调整高度 大概两年前的这个时间段,当时做项目遇到了一个问题:环境VS2005.WinForm,需要RichTextBox根据内容自动调整高度.当时用了各种方法都 ...

  2. WPF RichTextBox 禁止换行

    原文:WPF RichTextBox 禁止换行 这个问题困扰了好久,进过不断的努力,终于解决了           <RichTextBox Margin="0,44,10,0&quo ...

  3. WPF RichTextBox 当前光标后一个字符是文档的第几个字符

    WPF RichTextBox 当前光标后一个字符是文档的第几个字符 运行环境:Win10 x64, NetFrameWork 4.8, 作者:乌龙哈里,日期:2019-05-05 参考: TextP ...

  4. WPF RichTextBox读取存储文本的方法和常用属性

    1. 取得已被选中的内容: (1)使用 RichTextBox.Document.Selection属性(2)访问RichTextBox.Document.Blocks属性的“blocks”中的Tex ...

  5. WPF RichTextBox 控件常用方法和属性

    以下内容转自 http://blog.csdn.net/yulongguiziyao/article/details/25330551. 1. 取得已被选中的内容: (1)使用 RichTextBox ...

  6. WPF-20:richtextbox相关操作(转)

    WPF中的richtextbox与winform中的richtextbox的使用不同,看看下面的基本操作: 一.取出richTextBox里面的内容  (1)将richTextBox的内容以字符串的形 ...

  7. WPF RichTextBox 做内容展示框 滚动条控制判定是否阅读完成

    一.项目背景: 最近,做项目,因为是金融项目,客户登录交易的时候,有一个提示框,就是告知客户要“入市需谨慎”等等,想必大家都遇到这样的场景,当然,这种提示是没人会看的,不过作为交易所,这样的提示又必不 ...

  8. WPF RichTextbox

    WPFTextBoxAutoComplete AvalonEdit WPF SyntaxHighlightBox   WinForm 下的 Fast Colored TextBox for Synta ...

  9. WPF RichTextBox,关键字搜索,样式改变,超链接替换,图文混排

    RichTextBox 只是一个控件,表示对 FlowDocument 对象执行操作的丰富编辑控件.它所承载的内容由其 Document 属性来呈现. Document 是一个 FlowDocumen ...

随机推荐

  1. Oracle 删除重复数据只留一条(转)

    转自:http://www.cnblogs.com/252e/archive/2012/09/13/2682817.html 查询及删除重复记录的SQL语句   1.查找表中多余的重复记录,重复记录是 ...

  2. spring源码分析系列 (8) FactoryBean工厂类机制

    更多文章点击--spring源码分析系列 1.FactoryBean设计目的以及使用 2.FactoryBean工厂类机制运行机制分析 1.FactoryBean设计目的以及使用 FactoryBea ...

  3. SpringMVC默认欢迎页面的问题

    使用SpringMVC很长时间,一直有个问题没有搞定,就是web.xml中默认欢迎页面转向控制器的问题. 由于答应朋友明天要交个网站,他们对默认页面有这样的要求,并且最好也别用js等等的跳转:所以今天 ...

  4. .Net Core AES加密解密

    一.AES说明 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替 ...

  5. UVa 902 - Password Search

    题目:给你一个小写字母组成大的串和一个整数n.找到里面长度为n出现最频繁的子串. 分析:字符串.hash表.字典树. 这里使用hash函数求解,仅仅做一次扫描就可以. 说明:假设频率同样输出字典序最小 ...

  6. JavaScript之Date日期对象扩展

    各种时间加减 收藏起来以备后用 //名称:日期加法函数 //参数:part(year.month.day.hour.minute.second.millisecond) //返回:Date对象 Dat ...

  7. ARP协议具体解释之Gratuitous ARP(免费ARP)

    ARP协议具体解释之Gratuitous ARP(免费ARP) Gratuitous ARP(免费ARP) Gratuitous ARP也称为免费ARP.无故ARP.Gratuitous ARP不同于 ...

  8. AutoMapperExtension

    using System; using System.Collections.Generic; using System.Linq; using AutoMapper; using System.Co ...

  9. PL/SQL学习笔记之函数

    一:函数 函数与过程的最大不同就是,函数有返回值.适用于需要返回结果的场景. 二:创建函数 CREATE [OR REPLACE] FUNCTION function_name [(parameter ...

  10. 分区工具parted的详解及常用分区使用方法【转】

    来源:http://blog.51cto.com/zhangmingqian/1068779 分区工具parted的详解及常用分区使用方法 一.         parted的用途及说明 概括使用说明 ...