WPF RichTextBox富文本通过MVVM模式绑定

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

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

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

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

  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 的子内容。 如果不希望图像缩放到自然图像大小,请设置图像的 “高度 ”和“ 宽度 ”。

官方也明确指出,InlineUiContainer是用来将图片引入文本内容,这就是我上面代码使用InlineUiContainer加载图片的原因。

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MVVM模式下,PassWordBox的密码不能直接绑定到ViewModel的属性,因为密码是敏感信息,不应该以明文形式存储在内存中。因此,我们需要使用PasswordBox的SecureString属性来存储密码,并在ViewModel中创建一个SecureString类型的属性来接收密码。 首先,在XAML中,我们需要将PassWordBox的PasswordChanged事件与Command绑定,以便在密码发生变化时触发Command执行。例如: ``` <PasswordBox PasswordChanged="{Binding PasswordChangedCommand}" /> ``` 然后,在ViewModel中,我们需要创建一个SecureString类型的属性来接收密码,并创建一个Command来处理密码变化事件,例如: ``` public class LoginViewModel : INotifyPropertyChanged { private SecureString _securePassword; public SecureString SecurePassword { get { return _securePassword; } set { _securePassword = value; OnPropertyChanged(nameof(SecurePassword)); } } public ICommand PasswordChangedCommand => new RelayCommand<PasswordBox>((pb) => { SecurePassword = pb.SecurePassword; }); // INotifyPropertyChanged implementation... } ``` 在这个示例中,我们创建了一个SecurePassword属性来接收密码,并使用PasswordBox的SecurePassword属性将密码赋值给SecurePassword。我们还创建了一个PasswordChangedCommand来处理密码变化事件,该Command使用RelayCommand实现,并将PasswordBox作为参数传递。当密码发生变化时,Command会将SecurePassword属性设置为新密码。 需要注意的是,由于SecureString无法直接转换为字符串,因此我们需要在处理密码时使用相应的方法来转换或处理SecureString。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值