PS:本文使用RichTextBox仅基于MVVM模式。

  1. RichTextBox富文本框,主要应用场景考虑需要多行内容以及其他类型的内容如图片等,WPF提供的富文本框是基于FlowDocument(流文档),接下来会先解释一下什么是流文档。
  2. FlowDocument,先给大家看看官方的定义:

流文档旨在根据窗口大小、设备分辨率和其他环境变量来“重排内容”。 此外,流文档还具有很多内置功能,包括搜索、能够优化可读性的查看模式以及更改字体大小和外观的功能。 当易读性是文档的主要使用要求时,最适合使用流文档。

我个人理解的流文档主要是为了解决那些需要对文本内容排列布局、添加图片、放大缩小等使用场景。因此需要先了解流文档的内容格式。先来看看官方给出的模型:

wpf combobox selecteditem 绑定设置 wpf richtextbox绑定数据_Windows

  1. 蓝色背景为Block(块级元素)就是FlowDocument内的主要元素,一篇文章的主要构成为一个个的段落,我个人的理解是Block级别元素就是段落,FlowDocument主要包括Paragarph(章节)、Section(区域)、List(列表)、Table(表格)、BolckUIContainer(块级别UI容器)。
  2. 绿色背景的Inline(内联元素)是Block里的主力,用于承载需要输入的内容。这里就不再展开了,大家可以自己去动手试试。
  3. 黄色背景的UIElement对应的是具体的UI控件。

FlowDocument结构应该清晰了吧,FlowDocment可以包含多个Block,Block里面可以包含多个Inline。这很显然是一个的盒子结构(一层套着一层)。

  1. 介绍完流文档之后,我们重新回到RichTextBox,内部是由FlowDocument构成的,当我们使用MVVM模式时,我们需要将流文档的内容与具体的变量做绑定,以达到实时读取和修改的能力。因为RichTextBox控件中Document属性是不支持绑定的,所以需要对控件重写。通过添加附加属性的方式为Document添加绑定。

后端代码:

public partial class BindableRichTextBox : RichTextBox
    {
        public new FlowDocument Document
        {
            get { return (FlowDocument)GetValue(DocumentProperty); }
            set { SetValue(DocumentProperty, value); }
        }
        // Using a DependencyProperty as the backing store for Document.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DocumentProperty =
            DependencyProperty.Register("Document", typeof(FlowDocument), typeof(BindableRichTextBox), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnDucumentChanged)));
        private static void OnDucumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RichTextBox rtb = (RichTextBox)d;
            rtb.Document = (FlowDocument)e.NewValue;
        }
    }

前端代码只要把根标签改为RichTextBox即可

<RichTextBox
    x:Class="CutScreenPictureApp.BindableRichTextBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:CutScreenPictureApp"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d" />

这样就可以使用绑定了,绑定的类型要求为FlowDocument。一定要初始化!!!
可以利用绑定后的FlowDocument对象动态添加图片,这里展示我的代码:

_CheckFullTextBoxCommand = new RelayCommand<string>((data) =>
            {
                TextRange textRange = new TextRange(
                   // TextPointer to the start of content in the RichTextBox.
                   _FlowDocument.ContentStart,
                   // TextPointer to the end of content in the RichTextBox.
                   _FlowDocument.ContentEnd
                );

                try
                {
                    if (!string.IsNullOrEmpty(fileName) && File.Exists(fileName))
                    {
                        // 添加图片控件
                        System.Windows.Controls.Image image = new System.Windows.Controls.Image()
                        {
                            Source = new BitmapImage(new Uri(fileName)),
                            Width = 60,
                            Height = 60,
                        };

                        InlineUIContainer inlineUIContainer = new InlineUIContainer(image);

                        Paragraph paragraph = _FlowDocument.Blocks.Last() as Paragraph;

                        paragraph.Inlines.Add(inlineUIContainer);
                    }
                }
                catch ( Exception ex )
                {
                    Debug.WriteLine( ex );
                }
                

                System.Windows.MessageBox.Show(_FlowDocument == null ? "" : textRange.Text);
            });

TextRange是用来展示内容的,主要是通过InlineUIContainer绑定控件。


接下来讲讲InlineUIContainer,我写到这里也很好奇,InlineUIContainer是干嘛的?于是我去查阅了官方文档,先给出官方的定义

提供一个内联内容元素,该元素使 UIElement 类型能够嵌入 到 RichTextBlock 的内容中。

[Microsoft.UI.Xaml.Markup.ContentProperty(Name="Child")]
[Windows.Foundation.Metadata.Activatable(65536, "Microsoft.UI.Xaml.WinUIContract")]
[Windows.Foundation.Metadata.ContractVersion(typeof(Microsoft.UI.Xaml.WinUIContract), 65536)]
[Windows.Foundation.Metadata.MarshalingBehavior(Windows.Foundation.Metadata.MarshalingType.Agile)]
[Windows.Foundation.Metadata.Threading(Windows.Foundation.Metadata.ThreadingModel.Both)]
public sealed class InlineUIContainer : Inline

显然可以看到它是继承自Inline的,Inline(内联)是流文档的主要内容区域,通俗来说这玩意主要用来展示图片的,给出官方的举例代码:

<RichTextBlock>
    <Paragraph>
        <Italic>This is an inline image.</Italic>

        <InlineUIContainer>
            <Image Source="Assets/SmallLogo.png" Height="30" Width="30"/>
        </InlineUIContainer>

        Mauris auctor tincidunt auctor.
    </Paragraph>
</RichTextBlock>

使用 InlineUIContainer 对象的最常见方案是将图像引入文本内容。 使用图像的新 Image 对象作为 InlineUIContainer 的子内容。 如果不希望图像缩放到自然图像大小,请设置图像的 “高度 ”和“ 宽度 ”。