发布时间:2026/8/26 13:38:01
「干货分享」DevExpress常用控件——RichEditControl使用指南 做WinForms的一般都知道传统.NET界面有一个RichTextBox控件这个是一个富文本控件可以存储图片文字等内容它有自己的文件格式RTF在DevExpress控件组里面也有一个同等的控件他的名字是RichEditControl这个控件功能很强大它可以做邮件编辑器实现图文并茂的邮件的功能如下所示。本文主要介绍如何一步步使用这个控件实现自己需要的功能和界面。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序无论是Office风格的界面还是分析处理大批量的业务数据它都能轻松胜任DevExpress新旧版本帮助文档获取可点击这篇文章查看——《界面控件DevExpress v26.1帮助文档大全CHM版本》但是默认它没有任何工具栏全部是需要自己添加上去。如何创建带工具栏的RichEditControl控件为了使得控件更加通用我做了一个自定义控件用来实现通用文本编辑器的功能首先我们创建一个自定义控件如下所示。这样我们会看到一个空白的自定义控件界面然后再往里面添加一个RichEditControl进去设置DockFill,让RichEditControl控件铺满整个自定义控件界面如下所示。设置器ActiveViewTypeSimple让控件显示的更紧凑一些。如下所示。从上面我们看到它默认是没有任何工具栏的比较简单那么我们要添加向上面邮件界面的功能如何实现呢很简单选中RichEditControl,然后再右上角的三角符号上单击可以看到有一些功能菜单如下所示。单击Create BarManager然后可以进一步看到更多的工具栏菜单了如下所示。你可以悬着Create All Bar来创建所有工具栏然后删除多余的就可以了。这样就可以把所有的工具栏全部列出来了很多很多。但是一般我们不需要那么多精简一些重要的功能即可这些多余的最好删除否则很凌乱。这些功能按钮默认都已经带有事件的处理就是不需要额外的代码就可以实现各种标准的功能了这些很方便类似​​​​​​​DevExpress这方面做得很好如打印预览控件也是一样基本上不需要编写代码了选择需要的功能多余的删除即可这样就可以精简到我本文开头的那个邮件编辑器界面了。如何实现自定义的按钮功能刚才说到里面的按钮可以随意删除也可以随意组合到一个工具栏里面当然这个控件的工具栏除了内置的按钮外还可以增加自己的按钮和事件相应这样就更加完美和强大了。如上面的按钮就是我用来截图的一个功能自定义的内置的没有这样的功能这样添加按钮及图片后实现按钮的事件就可以了和自己创建的按钮一样。这个截图的功能利用了我的共用类库里面的一个截图类实现代码如下所示。ScreenCaptureWindow captureWindow null; private void barCapture_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { if (this.ParentForm.Owner ! null) { this.ParentForm.Owner.Hide(); } this.ParentForm.Hide(); if (captureWindow ! null) { captureWindow.BitmapCropped - new EventHandler(captureWindow_BitmapCropped); captureWindow.Dispose(); captureWindow null; } if (captureWindow null) { captureWindow new ScreenCaptureWindow(); captureWindow.BitmapCropped new EventHandler(captureWindow_BitmapCropped); } captureWindow.Show(); captureWindow.TopMost true; captureWindow.TopMost false; } void captureWindow_BitmapCropped(object sender, EventArgs e) { try { if (captureWindow.DragStop ! captureWindow.DragStart) { RichEditControl control this.richEditControl1; control.Document.InsertImage(control.Document.CaretPosition, DocumentImageSource.FromImage(captureWindow.BitmapCache)); } } finally { if (this.ParentForm.Owner ! null) { this.ParentForm.Owner.Show(); } this.ParentForm.Show(); } }这个截图直接就是把Image插入到RichEditControl里面不需要另外存储图片到文件里的这就是RichEditControl控件方便之处如果我们要实现插入图片和加载文档的方法除了使用内置按钮推荐外其实自己也可以写事件来实现的如下代码就是实现这两个简单的功能一般不需要。private void barInsertImg_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { string selectImage FileDialogHelper.OpenImage(true, ); if (!string.IsNullOrEmpty(selectImage)) { foreach (string file in selectImage.Split(new char[] { ,, ;, , })) { if (File.Exists(file)) { try { RichEditControl control this.richEditControl1; control.Document.InsertImage(control.Document.CaretPosition, DocumentImageSource.FromFile(file)); } catch { } } } } } private void barLoadFile_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { string filter Word2003(*.doc)|*.doc|Word2007(*.docx)|*.docx|RTF(*.rtf)|*.rtf|HTM(*.htm)|*.htm|HTML(*.html)|*.html|All File(*.*)|*.*; string file FileDialogHelper.Open(打开文件, filter); if (!string.IsNullOrEmpty(file)) { //string htmlContent File.ReadAllText(file, Encoding.Default); //this.richEditControl1.HtmlText htmlContent; string path Path.GetFullPath(file); string extension Path.GetExtension(file); switch (extension.ToLower()) { case .htm: case .html: this.richEditControl1.Document.LoadDocument(file, DocumentFormat.Html, path); break; case .doc: this.richEditControl1.Document.LoadDocument(file, DocumentFormat.Doc, path); break; case .docx: this.richEditControl1.Document.LoadDocument(file, DocumentFormat.OpenXml, path); break; case .rtf: this.richEditControl1.Document.LoadDocument(file, DocumentFormat.Rtf, path); break; default: this.richEditControl1.Document.LoadDocument(file, DocumentFormat.PlainText, path); break; } //DocumentRange range richEditControl1.Document.Range; //CharacterProperties cp this.richEditControl1.Document.BeginUpdateCharacters(range); //cp.FontName 新宋体; //cp.FontSize 12; //this.richEditControl1.Document.EndUpdateCharacters(cp); } }RichEditControl的特殊操作1. 文档字体修正RichEditControl控件功能是强大不过一般也需要处理一些特殊的情况由于该控件加载的时候默认好像字体都是方正姚体的字体因此感觉很不好看那么我们就要在文档加载的时候把它的字体修改下操作如下所示修改为新宋体的字体比方正姚体的好看很多。public MyRichEdit() { InitializeComponent(); this.richEditControl1.DocumentLoaded new EventHandler(richEditControl1_DocumentLoaded); } void richEditControl1_DocumentLoaded(object sender, EventArgs e) { DocumentRange range richEditControl1.Document.Range; CharacterProperties cp this.richEditControl1.Document.BeginUpdateCharacters(range); cp.FontName 新宋体; //cp.FontSize 12; this.richEditControl1.Document.EndUpdateCharacters(cp); }2. RichEditControl内置图片资源的解析RichEditControl控件支持把图片作为内嵌资源存储在里面如果我们要把他作为邮件发送我们知道邮件内容虽然是HTML的但是图片资源需要独立取出来放到LinkedResource对象作为邮件发送才能显示否则不能显示图片的。而RichEditControl默认转换出来的HTML内容是把图片作为Base64码写到文档里面文档比较大的。为了实现把图片独立提取出来我们需要一个该控件的解析类RichMailExporter代码如下所示。/// summary /// 把RichEditControl里面的内容导出为HTML和嵌入图片资源的辅助函数 /// /summary public class RichMailExporter : IUriProvider { int imageId; readonly RichEditControl control; ListLinkedAttachementInfo attachments; public RichMailExporter(RichEditControl control) { Guard.ArgumentNotNull(control, control); this.control control; } /// summary /// 导出内容和嵌入资源 /// /summary /// param namehtmlBodyHTML内容/param /// param nameattach附件资源/param public virtual void Export(out string htmlBody, out ListLinkedAttachementInfo attach) { this.attachments new ListLinkedAttachementInfo(); control.BeforeExport OnBeforeExport; htmlBody control.Document.GetHtmlText(control.Document.Range, this); control.BeforeExport - OnBeforeExport; attach this.attachments; } void OnBeforeExport(object sender, BeforeExportEventArgs e) { HtmlDocumentExporterOptions options e.Options as HtmlDocumentExporterOptions; if (options ! null) { options.Encoding Encoding.UTF8; } } #region IUriProvider Members public string CreateCssUri(string rootUri, string styleText, string relativeUri) { return String.Empty; } public string CreateImageUri(string rootUri, RichEditImage image, string relativeUri) { string imageName String.Format(image{0}, imageId); imageId; RichEditImageFormat imageFormat GetActualImageFormat(image.RawFormat); Stream stream new MemoryStream(image.GetImageBytes(imageFormat)); string mediaContentType RichEditImage.GetContentType(imageFormat); LinkedAttachementInfo info new LinkedAttachementInfo(stream, mediaContentType, imageName); attachments.Add(info); return cid: imageName; } private RichEditImageFormat GetActualImageFormat(RichEditImageFormat _RichEditImageFormat) { if (_RichEditImageFormat RichEditImageFormat.Exif || _RichEditImageFormat RichEditImageFormat.MemoryBmp) return RichEditImageFormat.Png; else return _RichEditImageFormat; } #endregion }/// summary /// 用来传递附件信息 /// /summary [Serializable] public class LinkedAttachementInfo { private Stream stream; private string mimeType; private string contentId; /// summary /// 参数构造函数 /// /summary /// param namestream附件流内容/param /// param namemimeType附件类型/param /// param namecontentId内容ID/param public LinkedAttachementInfo(Stream stream, string mimeType, string contentId) { this.stream stream; this.mimeType mimeType; this.contentId contentId; } /// summary /// 附件流内容 /// /summarypublic Stream Stream { get { return stream; } } /// summary /// 附件类型 /// /summarypublic string MimeType { get { return mimeType; } } /// summary /// 内容ID /// /summarypublic string ContentId { get { return contentId; } } }这样我们在获取编辑控件里面的HTML的同时也把里面的附件提取出来了方便我们发送邮件使用如下代码就是获取HTML内容和附件列表的其中LinkedAttachementInfo是以Stream和相关信息存在的一个实体类。string html ; ListLinkedAttachementInfo linkList new ListLinkedAttachementInfo(); RichMailExporter exporter new RichMailExporter(this.txtBody.richEditControl1); exporter.Export(out html, out linkList); MailInfo info new MailInfo(); info.Subject this.txtSubject.Text; info.Body html; info.IsBodyHtml true; info.EmbedObjects.AddRange(linkList);//添加嵌入资源 info.ToEmail this.txtRecipient.Text;//收件人这样我们发送邮件的时候写入附件数据就可以了如下代码所示。//嵌入资源的发送操作 AlternateView view AlternateView.CreateAlternateViewFromString(mailInfo.Body, Encoding.UTF8, MediaTypeNames.Text.Html); foreach (LinkedAttachementInfo link in mailInfo.EmbedObjects) { LinkedResource resource new LinkedResource(link.Stream, link.MimeType); resource.ContentId link.ContentId; view.LinkedResources.Add(resource); } mail.AlternateViews.Add(view);发送成功后我们就会看到图文并茂的邮件了。3. 内容支持搜索的操作邮件保存的时候我们可以把RichEditControl的内容作为RTF格式进行保存这样图片的资源就作为代码进行保存了这样恢复显示也很方便唯一不好的就是这些内容不好搜索建议如果要支持搜索可以通过增加另外一个文本字段把内容转换为纯文本进行保存这样加载就以RTF内容加载搜索的时候就搜索纯文本就可以了。以上就是我在使用​​​​​​​DevExpress的RichEditControl过程中碰到和解决问题的过程希望对大家有帮助共同提高。本文转载自博客园 - 伍华聪

相关新闻

2026/8/26 13:33:00

shell编程---替换运算符

替换运算符1、{: }运算符规则:1、若未定义该变量或者该变量值为空,则将用运算符后面的值赋值给该变量2、变量值不为空,不更新变量值。#! /bin/bash PRINT"Remind some import things" echo $PRINTecho ${STRING1:hello}…

2026/8/26 13:33:00

CH9102与CP2102应用注意事项

文章目录概述应用差异说明驱动说明GPIO使用说明硬件差异说明CH9102F VS CP2102N-GQFN24CH9102X VS CP2102CH9102X VS CP2102N-GQFN28其他说明CH9102资料链接概述 CH9102(WCH)与CP2102的不同子型号之间可实现pintopin兼容,可以在不更改硬件设…

2026/8/26 14:23:37

如何把历史pprof数据导入profefe?pprof_import.sh实战指南

如何把历史pprof数据导入profefe?pprof_import.sh实战指南 【免费下载链接】profefe Continuous profiling for long-term postmortem analysis 项目地址: https://gitcode.com/gh_mirrors/pr/profefe profefe 是面向长期事后分析的持续剖析(Cont…

2026/8/26 14:18:35

ICSHM2021 P2结构健康监测图像分割建模

图像分割已成为结构健康监测中不可或缺的技术手段,广泛应用于桥梁、建筑等工程设施的损伤识别中。高效、精准的分割模型对提升结构安全判断具有深远意义。 本文基于ICSHM2021 P2损伤状态分割任务,系统介绍数据结构、建模流程与关键算法思路,聚焦深度学习在工程图像分割中的…

2026/8/26 9:13:28

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/25 11:48:27

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/25 16:56:43

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/26 0:04:32

Python random 模块常用函数详解:从入门到实战

目录 1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结 1. 引言 摘要: 本文系统介绍 Python 标准库 random 模块中最常用的随机数生成函数。内容涵盖基础随机函数(random()、unifor…

2026/8/26 1:19:35

JSON总结

JSON概念 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,主要用于跟服务器进行交换数据。它基于ECMAScript的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C、C、C#、Java、JavaScr…

2026/8/26 1:19:35

保存连接sse 是什么原理,为什么不会一直请求

“保持连接”用的是 SSE(Server-Sent Events),本质是一个没有马上结束的 HTTP 请求。 过程是: 拷贝机发送一次请求: GET /api/code-sync/events服务器返回: Content-Type: text/event-stream但不关闭响应&…

2026/8/24 13:42:17

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/24 18:13:48

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/25 1:08:14

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…