因为前一段时间看到 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. maven部署命令

    参考文档:http://blog.csdn.net/woshixuye/article/details/8133050 http://www.blogjava.net/itvincent/archiv ...

  2. (转)用JS判断ckeditor3.6版本编辑器内容为空的方法

    因为编者我还是一个初学入门者,无论是JS还是PHP,都是懂了点皮毛.今天在研究ckeditor编辑器的时候遇到了一些问题,虽然这只是我的个人问题,但觉得可以分享给其他人,或许也有像我这样的初学者也会遇 ...

  3. (转)Repeater在无数据记录时显示暂无数据

    方法就是在FooterTemplate加个Label并根据repeater.Items.Count判断是否有记录.关键代码如下: <FooterTemplate>     <asp: ...

  4. json数据相对于xml数据.

    JSON is a valid subset of JavaScript, Python, and YAML JSON parsing is generally faster than XML par ...

  5. Using Notepad++ to Execute Oracle SQL

    原文链接:http://www.toadworld.com/products/toad-for-oracle/b/weblog/archive/2013/08/21/using-notepad-to- ...

  6. JavaScript 类、构造函数、原型

    类.构造函数.原型  :本质均为函数 利用的原理是:词法作用域,调用对象及作用域链  闭包  属性查找方式    设计和new运算符一起使用的函数叫做构造函数. 构造函数的工作:初始化一个新创建的对象 ...

  7. DirectX Graphics Infrastructure (DXGI) 全屏设置相关问题

    原文地址: https://msdn.microsoft.com/en-us/library/windows/desktop/ee417025(v=vs.85).aspx 未完待续... DXGI是在 ...

  8. gui小日历

    package MyCal; import java.awt.EventQueue; import javax.swing.JFrame; import javax.swing.JPanel; imp ...

  9. google protocol buffer -2-.proto 定义规则

    essage为主要关键字,类似于java中的class.定义简单message类型 SearchRequest.proto定义了每个查询请求的消息格式,每个请求都会有查询关键词query,查询结果的页 ...

  10. win8\win server 2012添加【中文--美式键盘】

    1. 修改注册表 Windows Registry Editor Version 5.00 [HKEY_CURRENT_USERKeyboard Layout] [HKEY_CURRENT_USERK ...