因为前一段时间看到 NetAnalyzer 在Windows10系统下UI表现惨不忍睹,所以利用一段时间为了学习一下WPF相关的内容,于是停停写写,用了WPF相关的技术,两个星期做了一个Markdown编辑器,并且集成了:编辑时与网页同步,博客发布,PDF导出等功能。也主要是不忿某款外国软件收费,故有此作。

代码下载地址

https://github.com/Twzy/MarkWord

展示与说明

代码同步编辑

博客发布

代码说明

博客发布

MarkWord支持博客园和CSDN博客发布,并且可以进行图片同步(无论是本地图片还是网上的图片,都可以同步到博客服务器)。 该功能使用了MetaWeblog技术。使用方法如下,其中图片上传为newMediaObject 接口

 /// <summary>
/// 文档上传,包括新增与更新
/// </summary>
public static string UploadBlogs(string apiUrl, string BlogId, string userId, string password, string
BlogsModel, string postId, string title, string Markdown, bool publish)
{ int procIndex = ; SendMsg(, procIndex, "准备数据中……");
//转换为html
string Blogs = string.Format("<!-- edit by MarkWord 墨云软件 -->\r\n{0}",
CommonMark.CommonMarkConverter.Convert(Markdown));
metaTools.Url = apiUrl; Post blogsPost = new Post(); //分类
List<string> tmpCategories = new List<string>();
tmpCategories.Add("");//添加空分类,是因为部分博客(如csdn)字段这部分为必填字段不添加会产生异常
blogsPost.categories = tmpCategories.ToArray(); //添加时间
blogsPost.dateCreated = DateTime.Now.ToLocalTime(); //添加标题
blogsPost.title = title; //指定文章编号
blogsPost.postid = postId; //内容
blogsPost.description = BlogsModel.Contains("{0}") ?//必须使用{0}占位符
string.Format(BlogsModel, Blogs) : //根据模板生成数据 主要是为了制定Markdown模板
BlogsModel + Blogs; //通过前缀方式添加 //开始查找图片并更新到服务器
HtmlDocument htmlDoc = new HtmlDocument();
WebClient webClient = new WebClient();
htmlDoc.LoadHtml(blogsPost.description);
var ImgList = htmlDoc.DocumentNode.Descendants("img"); int procCount = + ImgList.Count(); SendMsg(procCount, procIndex++, string.Format("数据分析完成,总共需要上传{0}张图片", ImgList.Count()));
int imgErr = ;//图片上传错误数量
foreach (var i in ImgList)
{
SendMsg(procCount, procIndex++, "正在上传图片数据……");
//获取图片文件字符串
string ImgUrl = i.GetAttributeValue("src", "");
if (string.IsNullOrEmpty(ImgUrl))
{
imgErr++;
continue;
}
try
{
var imgeData = webClient.DownloadData(ImgUrl);//下载文件 FileData fd = default(FileData);
fd.bits = imgeData;//图片数据
fd.name = Path.GetExtension(ImgUrl);//文件名
fd.type = string.Format("image/{0}", fd.name.Substring()); UrlData obj = metaTools.newMediaObject(BlogId, userId, password, fd);
blogsPost.description = blogsPost.description.Replace(ImgUrl, obj.url);
}
catch
{
imgErr++;
continue;
}
}
try
{
if (string.IsNullOrWhiteSpace(postId))
{
SendMsg(procCount, procIndex++, "开始发布文章……");
postId = metaTools.newPost(BlogId, userId, password, blogsPost, publish);
}
else
{
SendMsg(procCount, procIndex++, "正在更新文章……");
metaTools.editPost(postId, userId, password, blogsPost, publish);
}
}
catch (Exception ex)
{
Common.ShowMessage("博客发送失败");
return postId;
} if (imgErr == )
{
Common.ShowMessage("博客发送成功");
}
else
{
Common.ShowMessage(string.Format("博客发送成功了,但是有{0}张图片发送失败", imgErr));
}
SendMsg(procCount, procCount, "完成");
return postId; }

具体API实现方法见代码中的BlogsAPI项目

PDF导出

PDF导出功能,使用了HTML转PDF方法 相关DLL已经包含在项目当中了

 //html to Pdf
public static void HtmlToPdf(string filePath, string html, bool isOrientation = false)
{
if (string.IsNullOrEmpty(html))
html = "Null";
// 创建全局信息
GlobalConfig gc = new GlobalConfig();
gc.SetMargins(new Margins(, , , ))
.SetDocumentTitle("MarkWord")
.SetPaperSize(PaperKind.A4)
.SetPaperOrientation(isOrientation)
.SetOutlineGeneration(true); //页面信息
ObjectConfig oc = new ObjectConfig();
oc.SetCreateExternalLinks(false)
.SetFallbackEncoding(Encoding.UTF8)
.SetLoadImages(true)
.SetScreenMediaType(true)
.SetPrintBackground(true);
//.SetZoomFactor(1.5); var pechkin = new SimplePechkin(gc);
pechkin.Finished += Pechkin_Finished;
pechkin.Error += Pechkin_Error;
pechkin.ProgressChanged += Pechkin_ProgressChanged;
var buf = pechkin.Convert(oc, html); if (buf == null)
{
Common.ShowMessage("导出异常");
return;
} try
{
string fn = filePath; //Path.GetTempFileName() + ".pdf";
FileStream fs = new FileStream(fn, FileMode.Create);
fs.Write(buf, , buf.Length);
fs.Close(); //Process myProcess = new Process();
//myProcess.StartInfo.FileName = fn;
//myProcess.Start();
}
catch { }
}

 

CommonMark使用

最后就Markdown的转换,在这里我使用了CommonMark,使用方法比较简单

CommonMark.CommonMarkConverter.Convert("### test")

编辑与html页面同步原理 

在改工具中比较有意思的就是编辑器与Webbrower的页面同步功能,包括页面"无刷新"同步呈现,已经页面同步滚动,在这里使用的是编辑器触发 textEditor_TextChanged 事件和 ScrollViewer 触发的scrViewer_ScrollChanged 分别通过webbrowser 的 InvokeScript 动态调用Js实现的,我们先来看看两个js的内容

同步呈现

function updatePageContent(msg){
document.body.innerHTML= msg;
}

非常简单,只是将转换出来的html直接通过document.body.innerHTML 赋给当前页面既可以了。

同步滚动

function scrollToPageContent(value){
window.scrollTo(0, value * (document.body.scrollHeight - document.body.clientHeight));
}

这部分,是需要通过WPF页面转过来一个对应的页面位移高度与窗口显示高度的一个页面比例,然后在webbrowser中根据该比例计算页面需要偏移量来实现同步移动

而对应的WPF端的代码为

         /// <summary>
/// 同步呈现
/// </summary>
/// <param name="value"></param>
public void LoadBody(string MarkValue)
{ if (winWebDoc.Document == null)
return;
winWebDoc.Document.InvokeScript("updatePageContent", new object[] { CommonMark.CommonMarkConverter.Convert(MarkValue) });
} /// <summary>
/// 文本更变
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void textEditor_TextChanged(object sender, EventArgs e)
{
if (!isLoadFlag)
{
if (this.textEditor.Text != "" && scrViewer != null)
if (scrViewer.ScrollableHeight == scrViewer.VerticalOffset)
scrViewer.ScrollToBottom(); BLL.FileManager.isChangeFlag = true;
}
//加载文档
if (MarkDoc == null)
return;
if (Config.Common.WorkType == WorkType.Both)
{
MarkDoc.LoadBody(this.textEditor.Text);
}
}
//////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 同步滚动
/// </summary>
/// <param name="value"></param>
public void ScrollAuto(double value)
{
if (winWebDoc.Document == null)
return;
winWebDoc.Document.InvokeScript("scrollToPageContent", new object[] { value.ToString(System.Globalization.CultureInfo.InvariantCulture) }); }
//计算比例
public double ScrollViewerPositionPercentage
{
get
{
double num = this.scrViewer.ExtentHeight - this.scrViewer.ViewportHeight;
double result;
if (num != 0.0)
{
result = this.scrViewer.VerticalOffset / num;
}
else
{
result = 0.0;
}
return result;
}
} //触发同步
private void scrViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (MarkDoc == null) return;
if (Config.Common.WorkType == WorkType.Both)
{
MarkDoc.ScrollAuto(this.ScrollViewerPositionPercentage);
}
}

至此,Markword 中设计到的内容点已经基本覆盖到了,如有疑问欢迎交流!!!


最后来一发小广告

NetAnalyzer2016网络协议分析软件源码开放购买,可以分析80多种协议,支持http数据还原(包含chunked和gzip数据) ,欢迎大家可以支持一下!!

墨云NetAnalyzer官网
代码购买链接
如有疑问欢迎QQ联系:470200051

祝大家周末愉快

MarkWord - 可发布博客的 Markdown编辑器 代码开源的更多相关文章

  1. 博客用Markdown编辑器插入视频

    要展示一些App的效果用或者更方便地展示工具的操作,可以使用视频. 以下有两种方式可以在博客中插入视频 第一种 此方法适用于插入来源优酷的视频或者你自己录制了视频上传到优酷,这种方法的好处是可以插入时 ...

  2. Orchard运用 - 为博客启用Markdown编辑器

    有时决定你是否使用某一个博客系统,最看重就是如何更简便的写博客,不能让其成为一个负担或别扭费力不讨好的工作. 对此一个好的编辑器就是一个最靓丽的卖点.比如最新的博客系统ghost.org就只定位一个最 ...

  3. 201771010117—马兴德—实验一 软件工程准备—掌握博客中MarkDown的使用以及通读《现代软件工程—构建之法》的总结

    实验一 软件工程的前期准备工作 在前期的准备工作以及老师上课的讲解中,我懂得了"软件=程序+软件工程"这句话的基本含义,以前只是对软件工程有一个很浅显的概念,现在在读了<现代 ...

  4. 从零开始,搭建博客系统MVC5+EF6搭建框架(4)下,前后台布局实现、发布博客以及展示。

    一.博客系统进度回顾 目前已经完成了,前台展示,以及后台发布的功能,最近都在做这个,其实我在国庆的时候就可以弄完的,但是每天自己弄,突然最后国庆2天,连电脑都不想碰,所以就一直拖着,上一篇写了前端实现 ...

  5. Flask博客开发——Tinymce编辑器

    之前Flask博客的文本编辑器比较简陋,这里为博客添加个优雅易用的Tinymce文本编辑器. 1.项目中添加Tinymce 下载好Tinymce包以及语言包,并添加到项目中.添加到项目的方法,参考了这 ...

  6. 【干货】利用MVC5+EF6搭建博客系统(四)(下)前后台布局实现、发布博客以及展示

    二.博客系统后台布局实现 2.1.这里所用的是MVC的布局页来实现的,后台主要分为三部分:导航.菜单.主要内容 代码实现: 这里把后台单独放在一个区域里面,所以我这里建立一个admin的区域 在布局页 ...

  7. 测试用Word2007发布博客文章

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  8. 用WORD2007发布博客文章

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  9. Word2007发布博客

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

随机推荐

  1. linux sudo环境变量设置

    这是第一次在博客园中写自己的随笔,也是第一次使用Markdown的编辑环境,值得纪念一下!希望在以后学习linux的道路上能多多记录自己的学习心得和遇到问题的解决方法,朝着运维的方向迈出坚实的脚步. ...

  2. ASP.NET中的SQL注入攻击与防护

    什么是SQL注入攻击? 它是在执行SQL查询的时候,由于接收了用户的非法参数从而导致,所执行的SQL语义与业务逻辑原本所要查询的语义不相符,从而实现的攻击. 例如我们经常使用的用户登录,通常会出现这样 ...

  3. 【译】addEventListener 第二个参数

    这是原文链接:Our Backwards DOM Event Libraries 浏览器APIs 先简单回顾一下各个浏览器提供了哪些绑定事件的接口. IE浏览器提供了element.attachEve ...

  4. 将EmEditor加入到鼠标右键菜单

    在清理系统的时候,无意中将EmEditor的鼠标右键功能给清理掉了,在EmEditor的配置中又没有找到如何加入到鼠标右键菜单的方法,只好使用导入注册表功能了,以下的代码,拷贝到记事本中,保存为EmE ...

  5. 【创建型】Abstract Factory模式 & Factory Method模式

    本文主要介绍简单工厂模式与抽象工厂模式.以下如有叙述不当之处,欢迎批评指正,欢迎交流探讨. 一:简单工厂模式 在23种设计模式中,简单工厂模式其实是不在列的,但理解该模式对于抽象工厂模式的思想理解是有 ...

  6. iOS开发——C篇&动态内存分析

    再C语言中关于内存是一个很重要的知识点,所以今天我就从c语言的内存分配开始为大家解析一下C语言再iOS开发中非常重要的一些知识. 1:malloc函数的介绍 C语言中开辟内存空间:malloc函数(堆 ...

  7. IE11新特性 -- Internet Explorer 11:请不要再叫我IE

    Internet Explorer 11 中的一些新特性,包括对WebGL 的支持.预抓取.预渲染.flexbox.mutationobservers 以及其他一些 Web 标准的支持.但是更有趣的是 ...

  8. iOS-OC命名规范

    IOS开发(OC)中的命名规范 正文:通过读写大量代码我有自己的一套编程思路和习惯,自认为自己的编码习惯还是不错的,代码结构也算清晰,因为我一直以来都是代码看的多写的多,但是总结的比较少,知识经常不成 ...

  9. RazorEngine 学习笔记

    refer : https://github.com/Antaris/RazorEngine 微软的模板编辑器. Install-Package RazorEngine using RazorEngi ...

  10. Entity Framework with MySQL 学习笔记一(乐观并发)

    在做项目时,通常我们对乐观并发有几种处理模式 1. 告诉用户此数据已被其他人捷足先登,更改了.你就算新一下重来吧. 2.直接把数据覆盖上去,我最大. 3.用被人的数据. 这里给出 code first ...