富文本编辑器,一般都是BS架构专利一般,好像百度有一个开源的比较出名,但无奈这些都只能用在JS上,在BS网页端开发上使用。像Winform开发的VSTO,只能羡慕的份。和一般Winform上用的RichText控件,别人BS的富文本编辑器就强大得多。

笔者找寻过程中,也总算找到一款很不错的开源控件,将它的dll编译后,还真能用了。

在Excel催化剂的批量邮件功能中, 为了得到最好的体验,不止是不用依赖OUTLOOK的组件来发邮件(好像VBA的方案只能用outlook组件,用户电脑没安装outlook就不能用),同时为了让用户可以在邮件正文编辑区的使用体验和outlookup或网页端的发邮件体验一样,用了一个第3方的富文本编辑器,不是RichText控件,所以对网页的支持特别友好,随便复杂网页上的内容,粘贴过来,渲染得非常出色。

 
邮件群发功能

这个第3方富文本编辑器控件,不单单可以在里面作一些格式的配置,还可以有打开html文件,直接从网页其他地方复杂内容直接粘贴和插入本地图片,有了这些能力,在发送邮件正文时,使用体验就非常棒,可以发送出去的邮件正文,不是纯文本的形式,毫无格式,同时可以发送本地图片,特别是有些时候,正文内容需要说明一切重要内容,无需点开附件查看,或者正文中有邮件签名时,签名位置有图片也是常有的事情,特别是放个二维码之类的。

同样地水平有限,具体技术细节也不懂,只是能用起来的程度。只需引用以下的dll即可。
有兴趣的可以看作者的github代码https://github.com/yahch/kwig

 
富文本控件dll

此控件是自定义控件,可以通过设计器拖拉出来。

群发邮件核心代码,用这个富文本控件,拿到其渲染后的html文件,发邮件当然有C#自己的轮子,也很好用。

string htmlBodyContent = this.kEditor1.Html;
        private async Task BatchSendingEmail()
{
SmtpClient client = GetSmtpClient();
//string[] lisColNames = { "邮件标题", "收件人邮箱", "抄送邮箱", "密件抄送邮箱", "优先级", "附件路径" };
int ColIndexOfsubject = this.SendInfoListObject.ListColumns["邮件标题"].Index;
int ColIndexOfTo = this.SendInfoListObject.ListColumns["收件人邮箱"].Index;
int ColIndexOfCC = this.SendInfoListObject.ListColumns["抄送邮箱"].Index;
int ColIndexOfBCC = this.SendInfoListObject.ListColumns["密件抄送邮箱"].Index;
int ColIndexOfPriority = this.SendInfoListObject.ListColumns["优先级"].Index;
int ColIndexOfAttachments = this.SendInfoListObject.ListColumns["附件路径"].Index;
int ColIndexOfAttachmentsSize = this.SendInfoListObject.ListColumns["附件最大限制(M)"].Index; int ColIndexOfStatus = this.SendInfoListObject.ListColumns["发送状态"].Index;
string htmlBodyContent = this.kEditor1.Html; foreach (Excel.ListRow row in this.SendInfoListObject.ListRows)
{
if (isCancelSending == false)
{
try
{
string subject = row.Range[ColIndexOfsubject].Value2 != null ? row.Range[ColIndexOfsubject].Value2.ToString() : string.Empty;
string to = row.Range[ColIndexOfTo].Value2 != null ? row.Range[ColIndexOfTo].Value2.ToString() : string.Empty;
string cc = row.Range[ColIndexOfCC].Value2 != null ? row.Range[ColIndexOfCC].Value2.ToString() : string.Empty;
string bcc = row.Range[ColIndexOfBCC].Value2 != null ? row.Range[ColIndexOfBCC].Value2.ToString() : string.Empty; string priority = row.Range[ColIndexOfPriority].Value2 != null ? row.Range[ColIndexOfPriority].Value2.ToString() : "正常";
MailPriority mailPriority = priority == "高" ? MailPriority.High : priority == "低" ? MailPriority.Low : MailPriority.Normal; string attachments = row.Range[ColIndexOfAttachments].Value2 != null ? row.Range[ColIndexOfAttachments].Value2.ToString() : string.Empty;
int attachmentsSize = int.Parse(row.Range[ColIndexOfAttachmentsSize].Value2 != null ? row.Range[ColIndexOfAttachmentsSize].Value2.ToString() : "0"); long totalLength = 0;
foreach (var filePath in attachments.Split(new char[] { ';', ';' }, StringSplitOptions.RemoveEmptyEntries))
{
FileInfo fileInfo = new FileInfo(filePath);
totalLength = totalLength + fileInfo.Length;
}
if (totalLength / 1024.0 / 1024.0 > attachmentsSize)
{
row.Range[ColIndexOfStatus].Value2 = "发送失败,附件大小超出最大限制";
continue;
} if (!string.IsNullOrEmpty(subject) && !string.IsNullOrEmpty(to))
{
MailMessage mailMessage = GetMailMessage(row, subject, to, cc, bcc, mailPriority, attachments, htmlBodyContent); try
{
await client.SendTaskAsync(mailMessage);
row.Range[ColIndexOfStatus].Value2 = "发送完成";
}
catch (Exception ex)
{
row.Range[ColIndexOfStatus].Value2 = "发送失败,原因为" + ex.Message;
}
}
}
catch (Exception ex)
{
row.Range[ColIndexOfStatus].Value2 = "发送失败,原因为" + ex.Message;
}
finally
{
await Task.Factory.StartNew(() => Thread.Sleep(int.Parse(Properties.Settings.Default.BatchMailSendStopSecond) * 1000));
} } }
//this.Close();
this.Invoke(new Action(() => this.Close())); }

此控件,需要重写的方法,具体原理自己去看作者示例文档解释

        public void OnEditorErrorOccured(Exception ex)
{
//throw new NotImplementedException();
} public void OnEditorLoadComplete()
{
//throw new NotImplementedException();
} public void OnInsertImageClicked()
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "图片|*.jpg;*.png;*.gif";
if (ofd.ShowDialog() == DialogResult.OK)
{
string n = "<img src=\"file://" + ofd.FileName + "\" />";
kEditor1.InsertNode(n);
//把图片放到字典中,供之后清洗时取出来
dicImageInfo.Add("t" + (dicImageInfo.Count + 1), "file://" + ofd.FileName);
} } public void OnOpenButtonClicked()
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "*.html|*.html";
if (ofd.ShowDialog() == DialogResult.OK)
{
string text = System.IO.File.ReadAllText(ofd.FileName);
kEditor1.InsertNode(text);
}
} public void OnSaveButtonClicked()
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "*.html|*.html";
if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
System.IO.File.WriteAllText(sfd.FileName, kEditor1.Html);
}
}

结语

接连的这几篇文章,大家都可以感受到,对于一个业务导向的业余开发者来说,如果找到好的轮子,也可以实现很多复杂场景,用户体验也可以做得很好。所以VSTO和VBA开发,真的有一个本质的区别,VBA大不了最多用下系统的API函数,OFFICE的对象模型,但在VSTO的世界里,只要用心找,可以尽性地用尽一切世界上优秀的代码轮子。

技术交流QQ群

QQ群名:Excel催化剂开源讨论群, QQ群号:788145319

 
Excel催化剂开源讨论群二维码

关于Excel催化剂

Excel催化剂先是一微信公众号的名称,后来顺其名称,正式推出了Excel插件,插件将持续性地更新,更新的周期视本人的时间而定争取一周能够上线一个大功能模块。Excel催化剂插件承诺个人用户永久性免费使用!

Excel催化剂插件使用最新的布署技术,实现一次安装,日后所有更新自动更新完成,无需重复关注更新动态,手动下载安装包重新安装,只需一次安装即可随时保持最新版本!

Excel催化剂插件下载链接:https://pan.baidu.com/s/1Iz2_NZJ8v7C9eqhNjdnP3Q

 
联系作者
 
公众号

取名催化剂,因Excel本身的强大,并非所有人能够立马享受到,大部分人还是在被Excel软件所虐的阶段,就是头脑里很清晰想达到的效果,而且高手们也已经实现出来,就是自己怎么弄都弄不出来,或者更糟的是还不知道Excel能够做什么而停留在不断地重复、机械、手工地在做着数据,耗费着无数的青春年华岁月。所以催生了是否可以作为一种媒介,让广大的Excel用户们可以瞬间点燃Excel的爆点,无需苦苦地挣扎地没日没夜的技巧学习、高级复杂函数的烧脑,最终走向了从入门到放弃的道路。

最后Excel功能强大,其实还需树立一个观点,不是所有事情都要交给Excel去完成,也不是所有事情Excel都是十分胜任的,外面的世界仍然是一个广阔的世界,Excel只是其中一枚耀眼的明星,还有其他更多同样精彩强大的技术、工具等。*Excel催化剂也将借力这些其他技术,让Excel能够发挥更强大的爆发!

关于Excel催化剂作者

姓名:李伟坚,从事数据分析工作多年(BI方向),一名同样在路上的学习者。
服务过行业:零售特别是鞋服类的零售行业,电商(淘宝、天猫、京东、唯品会)

技术路线从一名普通用户,通过Excel软件的学习,从此走向数据世界,非科班IT专业人士。
历经重重难关,终于在数据的道路上达到技术平原期,学习众多的知识不再太吃力,同时也形成了自己的一套数据解决方案(数据采集、数据加工清洗、数据多维建模、数据报表展示等)。

擅长技术领域:Excel等Office家族软件、VBA&VSTO的二次开发、Sqlserver数据库技术、Sqlserver的商业智能BI技术、Powerbi技术、云服务器布署技术等等。

2018年开始职业生涯作了重大调整,从原来的正职工作,转为自由职业者,暂无固定收入,暂对前面道路不太明朗,苦重新回到正职工作,对Excel催化剂的运营和开发必定受到很大的影响(正职工作时间内不可能维护也不可能随便把工作时间内的成果公布于外,工作外的时间也十分有限,因已而立之年,家庭责任重大)。

和广大拥护者一同期盼:Excel催化剂一直能运行下去,我所惠及的群体们能够给予支持(多留言鼓励下、转发下朋友圈推荐、小额打赏下和最重点的可以和所在公司及同行推荐推荐,让我的技术可以在贵司发挥价值,实现双赢(初步设想可以数据顾问的方式或一些小型项目开发的方式合作)。

Excel催化剂开源第29波-在Winform上使用富文本编辑器控件的更多相关文章

  1. Excel催化剂开源第23波-VSTO开发辅助录入功能关键技术

    Excel催化剂开源第23波-VSTO开发辅助录入功能关键技术 Excel催化剂   2019.01.12 14:10* 字数 2948 阅读 41评论 0喜欢 0 编辑文章 在Excel催化剂的几大 ...

  2. Excel催化剂开源第22波-VSTO的帮助文档在哪里?

    Excel催化剂开源第22波-VSTO的帮助文档在哪里? Excel催化剂   2019.01.12 14:10 字数 2930 阅读 55评论 0喜欢 0 编辑文章 对于专业程序猿来说,查找文档不是 ...

  3. Excel催化剂开源第12波-VSTO开发遍历功能区所有菜单按钮及自定义函数清单

    在插件开发过程中,随着功能越来越多,用户找寻功能入口将变得越来越困难,在Excel催化剂 ,将采用遍历所有功能的方式,让用户可以轻松使用简单的查找功能找到想要功能所在位置,查找的范围有:功能按钮的显示 ...

  4. Excel催化剂开源第51波-Excel催化剂遍历单元格操作性能保障

    在Excel催化剂推出的这一年多时间里,经常性听到一种声音,大概意思是真正会写代码的人,都不会看上Excel催化剂写出来的功能,自己造一个更舒服贴心,仿佛会一点VBA就可以天下无敌一般,也好像Exce ...

  5. Excel催化剂开源第50波-Excel与PowerBIDeskTop互通互联之第四篇

    答应过的全盘分享,也必承诺到底,此篇PowerBI功能分享的最后一篇,讲述如何导出数据模型的元数据,笔者定义其为模型的数据字典. 此篇对应功能实现出自:第6波-导出PowerbiDesktop模型数据 ...

  6. Excel催化剂开源第49波-Excel与PowerBIDeskTop互通互联之第三篇

    在PowerBIDeskTop开启的SSAS服务,和Sqlserver所开启的一个本质的区别是,前者其端口号是随机生成的,即上一次打开获得的端口号,下一次关闭后再打开,系统分配给它新的端口号,而后者因 ...

  7. Excel催化剂开源第47波-Excel与PowerBIDeskTop互通互联之第一篇

    当国外都在追求软件开源,并且在GitHub等平台上产生了大量优质的开源代码时,但在国内却在刮着一股收割小白智商税的知识付费热潮,实在可悲. 互联网的精神乃是分享,让分享带来更多人的受益. 在Power ...

  8. Excel催化剂开源第48波-Excel与PowerBIDeskTop互通互联之第二篇

    前一篇的分享中,主要谈到Excel透视表连接PowerBIDeskTop的技术,在访问SSAS模型时,不止可以使用透视表的方式访问,更可以发数据模型发起DAX或MDX查询,返回一个结果表数据,较透视表 ...

  9. Excel催化剂开源第46波-按行列排列多个图形技术要点

    此篇对应功能出自:第10波-快速排列工作表图形对象 - 简书 https://www.jianshu.com/p/eab71f2969a6 在Excel的对象模型中,列的宽度不是一般所期待的和行高一样 ...

随机推荐

  1. Win7和Vista的安全机制对于应用程序读取配置文件相关操作的影响(虚拟重定向技术)

    今天构造了一个新版本的XXXX软件,并且在纯净的系统下进行了较为全面的测试.测试中也发现了一些问题.其中包括在Win7测试时程序竟然在另一个目录中创建了文件夹和配置文件,并且进行相关读取操作,却并没有 ...

  2. Delphi中用MessageBox()API函数做倒计时对话框(使用Hook安装CBTHookCallback,计时器更改文字,SetWindowText API真正修改文字,引用未知函数)good

    API有隐藏的MessageBoxTimeOut函数可以做计时对话框,缺点是不能显示还剩下多少秒关闭. const IDTIMEDOUT = 32000; function MessageBoxTim ...

  3. SqlServer 动态SQL(存储过程)中Like 传入参数无正确返回值的问题

    最近在做项目时,以动态Sql进行Like语句查询时发现应该返回的结果却一直返回空,后来发现是写法错误: 错误SQL: DECLARE @0 varchar(20) SET @0 = 'XA-LZ' S ...

  4. java设计模式-单例(singleton)

    单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例.即一个类只有一个对象实例 如何保证对象唯一性呢? 思想: ...

  5. 为了考PMP,我做了一个刷题小程序

    一.背景 1.我是一名软件工程师,技术出身,担任开发组长,对项目管理不是很熟,所以决定系统学习下项目管理. 2.全球最适合的项目管理学习课程就是PMP,每年有4次PMP考试,证书还是很有含金量的. 3 ...

  6. 网站压力测试工具 Webbench简单介绍

    Webbech能测试处在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况.Webbench的标准测试可以向我们展示服务器的两项内容:每秒钟相应请求数和每秒钟传输数据量.Webbench不但 ...

  7. 丢给你一个txt并同时获取你shell

    丢给你一个txt并同时获取你shell 0x00:回顾 <文本编辑器Vim/Neovim被曝任意代码执行漏洞> 听闻很多人知道这个漏洞,但是有一部分人能复现成功,一部分人复现不出来.这里我 ...

  8. 简易数据分析 04 | Web Scraper 初尝--抓取豆瓣高分电影

    这是简易数据分析系列的第 4 篇文章. 今天我们开始数据抓取的第一课,完成我们的第一个爬虫.因为是刚刚开始,操作我会讲的非常详细,可能会有些啰嗦,希望各位不要嫌弃啊:) 有人之前可能学过一些爬虫知识, ...

  9. package.json 详解

    使用package.json  属性说明 name - 包名. version - 包的版本号. description - 包的描述. homepage - 包的官网 url . author - ...

  10. MySQL数据库修改字段的长度

    数据库版本:5.7.22 使用DDL语句:alter table 表名 modify 字段名 字符类型(长度) 例如: alter table db2.admin modify password );