经历了快一个月的开发(因为都是在闲暇时间做的,实际实际可能不到一周),AlexisEditor总算完成了。

这边说明一下为什么有些网友不能新增文章的问题。

原因是路径中有中文字符,我一直用的是英文系统,所以没有出现这样的情况。感谢网友初中生的net梦 在xp、.Net2.0 平台下的测试 ,发现了这个bug。

具体来说一下这个bug,是因为WebBrowser导航发生改变的时候会对Uri进行编码,而我们这边不需要进行编码,于是就可以用反编码就行了。

解决方案如下

//特别注意,如果路径中有中文,url会对其进行编码

  1. if (System.Web.HttpUtility.UrlDecode(e.Url.AbsolutePath.ToString()).Replace('/', '\\') == saveUrl)

再次更新下程序(也许是最后一次更新了)

源代码下载(vs2010版)

源代码下载(vs2005版)

程序下载(XP版,如果你的IE版本是6.0,请下载此版本)

呵呵,如果觉得好的话,请推荐之!

下面将我这个系列遇到的问题和经验总结下,然后着手学习WPF和SilverLight的知识,希望里面的知识点能够对你有帮助。

篇幅可能有点长,为了方便起见,增加导航

一、在WinForm实现类似CSS Sprites(CSS图像拼合技术)

二、WebBrowser控件的使用技巧

三、XML的妙用之存储树

四、Visual Studio界面风格WinForm实现

五、 WinForm中的状态栏初探

六、 C#调用系统的cmd命令

七、 TreeView节点重命名

八、DataGridView中的一些技巧

九、Lucene.Net简单的应用

十、简易版的log类

一、在WinForm实现类似CSS Sprites(CSS图像拼合技术)

在WinForm我们会用到许多的小图片,可能要求是ico格式的,而且像素一般是16*16的,如果将这么多的ico图片放在一个文件夹里,当然 是可以,不过,如果一张图片2k,那么50张图片就是100k,浪费空间。我们可以像web那样做,将许多图片拼合到一张图片中,然后写一个静态类来调用 图片中的第几个图形。

如下图一张480*16 bmp格式的图片(演示需要,放大了)

设置图片的背景为比较明显的颜色(为了后面显示透明),总共就有30个图形,于是我们就可以遍历然后将图片存到一个List中了,详细代码如下:

  1. System.Resources.ResourceManager resource = new System.Resources.ResourceManager("AlexisEditor.Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
  2. Bitmap bitmap = (Bitmap)resource.GetObject("bookicons");
  3. //将加载的位图的图片提取出来,并放在list中
  4. p_w_picpathList = new ImageList();
  5. iconList = new List<Icon>();
  6. for (int i = 0; i < bitmap.Width / 16; i++)
  7. {
  8. Bitmap img = bitmap.Clone(new Rectangle(16 * i, 0, 16, 16), bitmap.PixelFormat);//切割图标
  9. img.MakeTransparent(Color.Magenta);//设置过滤色
  10. p_w_picpathList.Images.Add(img);
  11. System.IntPtr iconHandle = img.GetHicon();
  12. System.Drawing.Icon icon = Icon.FromHandle(iconHandle);
  13. iconList.Add(icon);
  14. }

首先从资源文件中获取名为bookicons的位图,然后遍历,将每个图形存入到p_w_picpathList中或是自定义的List,

这边给出了如何将bmp图片转换为Icon图片的代码

  1. System.IntPtr iconHandle = img.GetHicon();
  2. System.Drawing.Icon icon = Icon.FromHandle(iconHandle);

整个IconHelper类的代码如下:

  1. private static ImageList p_w_picpathList;
  2. private static List<Icon> iconList;
  3. static IconHelper()
  4. {
  5. System.Resources.ResourceManager resource = new System.Resources.ResourceManager("AlexisEditor.Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
  6. Bitmap bitmap = (Bitmap)resource.GetObject("bookicons");
  7. //将加载的位图的图片提取出来,并放在list中
  8. p_w_picpathList = new ImageList();
  9. iconList = new List<Icon>();
  10. for (int i = 0; i < bitmap.Width / 16; i++)
  11. {
  12. Bitmap img = bitmap.Clone(new Rectangle(16 * i, 0, 16, 16), bitmap.PixelFormat);//切割图标
  13. img.MakeTransparent(Color.Magenta);//设置过滤色
  14. p_w_picpathList.Images.Add(img);
  15. System.IntPtr iconHandle = img.GetHicon();
  16. System.Drawing.Icon icon = Icon.FromHandle(iconHandle);
  17. iconList.Add(icon);
  18. }
  19. }
  20. public static Image GetBuildImage()
  21. {
  22. System.Resources.ResourceManager resource = new System.Resources.ResourceManager("AlexisEditor.Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
  23. return (Image)resource.GetObject("Build");
  24. }
  25. /// <summary>
  26. /// 书籍ico图标
  27. /// </summary>
  28. public static Icon BookIcon
  29. {
  30. get { return iconList[0]; }
  31. }

二、WebBrowser控件的使用技巧

设置当前的Uri地址

  1. this.wbEditor.Url = new Uri(startPath + @"\CSDN_UBB\normalTemp.htm");

获取当前WebBrowser中的文档

  1. HtmlDocument hd = this.wbEditor.Document;//获取文档信息

获取当前Dom文档中指定Id的元素

  1. HtmlElement he = hd.GetElementById("content");

获取指定元素的值,比如获取TextArea中的值

首先添加mshtml的引用

  1. IHTMLDocument2 doc = (IHTMLDocument2)this.wbEditor.Document.DomDocument;mshtml.HTMLInputElement text1 = (HTMLInputElement)doc.all.item("content");

后台调用页面中已有的js函数

  1. ((mshtml.HTMLDocumentClass)webBrowser.Document).parentWindow.execScript( "func()", "JScript" );

具体的应用可以参考我的源代码

三、XML的妙用之存储树

程序中使用XML存储电子书的目录信息,方便hhc.exe编译为CHM电子书。

在.Net中有现成的类来操作XML,即System.Xml.XmlDocument, 他表示一个XML文档(XML基本知识我就不介绍了),XML有根节点,根节点里面可以有子节点,节点有属性等等。

可以使用XmlDocument的Load方法来将一个XML文档加载到内存中,如下代码:

  1. System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
  2. doc.Load(filename);

然后获取xml根节点里面的一些信息,根节点下面才是书籍目录的信息

  1. private void FromXML(System.Xml.XmlElement RootElement)
  2. {
  3. //this.defaultPage = RootElement.GetAttribute("DefaultTopic");
  4. this._title = RootElement.GetAttribute("Title");//标题
  5. nodeList.Clear();
  6. foreach (System.Xml.XmlNode node in RootElement.ChildNodes)
  7. {
  8. if (node.Name == "Items")
  9. {
  10. NodesFromXML(nodeList, (System.Xml.XmlElement)node);
  11. }
  12. }
  13. }
  14. //xml转为为nodes
  15. private void NodesFromXML(CHMNodeList nodes, System.Xml.XmlElement RootElement)
  16. {
  17. foreach (System.Xml.XmlNode node in RootElement.ChildNodes)
  18. {
  19. if (node.Name == "Node")
  20. {
  21. System.Xml.XmlElement element = (System.Xml.XmlElement)node;
  22. CHMNode NewNode = new CHMNode();
  23. NewNode.Name = element.GetAttribute("Name");
  24. NewNode.Local = element.GetAttribute("Local");
  25. NewNode.ImageNo = element.GetAttribute("ImageNumber");
  26. nodes.Add(NewNode);
  27. foreach (System.Xml.XmlNode node2 in element.ChildNodes)
  28. {
  29. if (node2.Name == "Items")
  30. {
  31. NodesFromXML(NewNode.Nodes, (System.Xml.XmlElement)node2);
  32. }
  33. }
  34. }
  35. }
  36. }

四、Visual Studio界面风格WinForm实现

实现步骤(一个小的Demo):

1.创建WinForm项目,取名为DockDemo,

2.在工具栏中添加工具,导向 WeifenLuo.WinFormsUI.Docking.dll

3.建立MainForm,将DockPanel拖到MainForm中 ,设置其Dock属性为Fill

4.建立SolutionForm,将其继承有Form改为 WeifenLuo.WinFormsUI.Docking.DockContent

5.在MainForm的构造函数中实例化SolutionForm,代码如下

  1. SolutionForm  form=new SolutionForm();
  2. form.Show(dockPanel);//显示目录窗体
  3. form.DockTo(dockPanel, DockStyle.Right);

同时,我们看到visual studio中,将ToolBox关闭掉可以点击 工具栏中的图标重新调用,我们可以设置SolutionForm的属性HideOnClose为True,即点击关闭时并不是真正的释放,而是隐藏起来。重新显示调form.Show(dockPanel);即可

五、 WinForm中的状态栏初探

用过Visual Studio的程序员都知道,Visual Studio下方的状态栏提供了各种各样的状态给开发者,使得开发者能够实时知道Visual Studio现在处于什么状态。

代码如下,创建ToolStripStatusLabel 对象的实例,添加到StatusStrip中,当编译完后移除。(有更好的方法欢迎指导

  1. ToolStripStatusLabel tsl = new ToolStripStatusLabel();
  2. tsl.Text = "正在编译....";
  3. ToolStripStatusLabel tslBuilding = new ToolStripStatusLabel();
  4. tsl.Image = IconHelper.GetBuildImage();
  5. tsl.Dock = DockStyle.Right;
  6. this.statusStrip.Items.AddRange(new ToolStripItem[] { tsl,tslBuilding });
  7. this.statusStrip.Text = "正在编译...";
  8. chmDocument.Compile();
  9. frmOutPut.TxtOutput.Text = chmDocument.OutPutText;
  10. this.statusStrip.Items.Remove(tsl);
  11. this.statusStrip.Items.Remove(tslBuilding);ToolStripStatusLabel tsl = new ToolStripStatusLabel();
  12. tsl.Text = "正在编译....";
  13. ToolStripStatusLabel tslBuilding = new ToolStripStatusLabel();
  14. tsl.Image = IconHelper.GetBuildImage();
  15. tsl.Dock = DockStyle.Right;
  16. this.statusStrip.Items.AddRange(new ToolStripItem[] { tsl,tslBuilding });
  17. this.statusStrip.Text = "正在编译...";
  18. chmDocument.Compile();
  19. frmOutPut.TxtOutput.Text = chmDocument.OutPutText;
  20. this.statusStrip.Items.Remove(tsl);
  21. this.statusStrip.Items.Remove(tslBuilding);

六、 C#调用系统的cmd命令

我们有时候需要在C#中调用一些command命令,如点击Label打开浏览器。AlexisEditor程序中编译为CHM电子书的功能就是 调用系统自带(一般正版的Windows系统都会自带,其他版本的Windows可能会阉割掉)的hhc.exe,并且可以获得当前的编译情况

Process helpCompileProcess = new Process();  //创建新的进程,用Process启动HHC.EXE来Compile一个CHM文件

  1. ProcessStartInfo processStartInfo = new ProcessStartInfo();
  2. processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
  3. processStartInfo.FileName = config.HhcPath;  //调入HHC.EXE文件
  4. processStartInfo.Arguments = "\"" + strHhp + "\"";//获取空的HHP文件
  5. processStartInfo.UseShellExecute = false;
  6. processStartInfo.CreateNoWindow = true;
  7. processStartInfo.RedirectStandardOutput = true;
  8. helpCompileProcess.StartInfo = processStartInfo;
  9. helpCompileProcess.Start();
  10. helpCompileProcess.WaitForExit(); //组件无限期地等待关联进程退出
  11.     string _outPutText = helpCompileProcess.StandardOutput.ReadToEnd();//进程中的信息

七、 TreeView节点重命名

有时候我们需要重命名TreeView的节点,实现代码如下:

首先设置TreeView的LabelEdit属性为True,然后在触发的事件中,设置选中的节点为编辑状态,接下来就是编辑后触发的事件即AfterLabelEdit 。

  1. private void ReNameMToolStripMenuItem_Click(object sender, EventArgs e)
  2. {
  3. this.tvIndex.SelectedNode.BeginEdit();
  4. }
  5. private void tvIndex_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
  6. {
  7. this.tvIndex.SelectedNode.Name = e.Label;
  8. TreeNode node = this.tvIndex.SelectedNode;
  9. if (node.Tag is CHMDocument)
  10. {
  11. ((CHMDocument)node.Tag).Title = e.Label;
  12. }
  13. if (node.Tag is CHMNode)
  14. {
  15. ((CHMNode)node.Tag).Name = e.Label;
  16. }
  17. }

八、DataGridView中的一些技巧  程序中使用DataGridView显示查询的结果,因为查询的结果是自己拼凑起来的,即使用Lucene.Net检索到多少内容,然后拼凑为DataTable,最后在绑定到

DataGridView中,因为要在DataGridView中增加链接,使得点击链接可以打开文章进行编辑,所以在前台DataGridView可视化界面中增加LinkLabel的Column。

并设置它的DataPropertyName设为后台DataTable中的名字,代码如下

  1. //创建DataTable用于绑定
  2. DataTable dtResult = new DataTable();
  3. DataColumn dc1 = new DataColumn("Title", Type.GetType("System.String"));
  4. DataColumn dc2= new DataColumn("KeyWords", Type.GetType("System.String"));
  5. DataColumn dc3 = new DataColumn("Content", Type.GetType("System.String"));
  6. DataColumn dc4 = new DataColumn("FilePath", Type.GetType("System.String"));
  7. dtResult.Columns.Add(dc1);
  8. dtResult.Columns.Add(dc2);
  9. dtResult.Columns.Add(dc3);
  10. dtResult.Columns.Add(dc4);

注意,如果在可视化界面中不设置列的DataPropertyName属性,运行后会出现多列,有点类似于GridView中的AutoGenerateColumn属性

然后遍历索引检索到的条数,将内容添加到DataTable中

  1. if (hits != null && hits.Length()>0)
  2. {
  3. for (int i = 0; i < hits.Length(); i++)
  4. {
  5. Document doc = hits.Doc(i);
  6. DataRow dr=dtResult.NewRow();
  7. dr["Title"] = doc.Get("title");//文章标题
  8. dr["KeyWords"] = doc.Get("keywords");//文章关键字
  9. dr["Content"] = doc.Get("contents");//内容
  10. dr["FilePath"] = doc.Get("filename");//文件路径
  11. dtResult.Rows.Add(dr);
  12. }
  13. this.tcList.SelectedIndex = 1;
  14. this.dgvResult.DataSource = dtResult;
  15. this.dgvResult.Columns["FilePath"].Visible = false;
  16. }
  17. else
  18. {
  19. MessageBox.Show("没有查到相关记录!");
  20. }

使用this.dgvResult.DataSource = dtResult;绑定数据源

下面来看看如何获取DataGridView选中行中所有列的数据,当我们点击超链接时会触发CellContentClick事件,我们在这个事件中获取选中行的

  1. private void dgvResult_CellContentClick(object sender, DataGridViewCellEventArgs e)
  2. {
  3. //点击的是超链接
  4. if (e.ColumnIndex==0)
  5. {
  6. //获取当前行的文件名
  7. string path=this.dgvResult.CurrentRow.Cells[3].Value.ToString();
  8. //调用编辑窗口
  9. GetNode(path,this.nodes);
  10. CHMNode node = this.nodeOpen;
  11. EditForm form = new EditForm();
  12. form.Edit(node);
  13. form.ShowDialog();
  14. }
  15. }

这句话就是获取我们要打开文章

  1. string path=this.dgvResult.CurrentRow.Cells[3].Value.ToString();

九、Lucene.Net简单的应用

程序中使用了Lucene.Net来搜索文,原因是因为Lucene.Net支持全文检索,即我们可以输入关键字,在我们写的文章中查询有没有匹配的词。

思路是这样的,选择检索方式:标题检索、关键字检索、全文检索,每个检索都会搜索不同的索引。

点击搜索按钮的时候生成索引的,获取关键字 ,获取检索方式,检索,显示搜索结构。

  1. //INDEX_STORE_PATH 为索引存储目录
  2. string INDEX_STORE_PATH = Application.StartupPath+@"\index";
  3. //先存储索引
  4. IndexWriter writer = new IndexWriter(INDEX_STORE_PATH, new StandardAnalyzer(), true);
  5. SetIndex(writer,this.nodes);

而SetIndex是使用递归的方法遍历树,有关写入Index的代码如下

  1. try
  2. {
  3. Document doc = new Document();
  4. doc.Add(new Field("filename", node.Local, Field.Store.YES, Field.Index.TOKENIZED));
  5. doc.Add(new Field("title", node.Name, Field.Store.YES, Field.Index.TOKENIZED));
  6. doc.Add(new Field("keywords", node.KeyWords, Field.Store.YES, Field.Index.TOKENIZED));
  7. doc.Add(new Field("contents", new StreamReader(node.Local, System.Text.Encoding.Default)));
  8. writer.AddDocument(doc);
  9. }
  10. catch (FileNotFoundException fnfe)
  11. {
  12. LogHelper.WriteLog(fnfe.Message);
  13. }

然后查询

1.申明一个IndexSearcher 2.设置查询路径 3.申明一个QueryParser 4.设置查询使用的value 5.查询 6.Hits 对象即查询结果

  1. //在从索引中查询
  2. IndexSearcher searcher;
  3. searcher = new IndexSearcher(INDEX_STORE_PATH);
  4. QueryParser q = null;
  5. q = new QueryParser("title", new StandardAnalyzer());
  6. Query qquery = q.Parse(KEYWORD);
  7. Hits hits = searcher.Search(query);

十、简易版的log类

在写一写“危险”代码时,我们经常使用try。。catch语句进行异常捕获,而且往往也会忘了对捕获信息的存储。这里提供一个简易版的日志记录类

  1. public static class LogHelper
  2. {
  3. public static void WriteLog(string log)
  4. {
  5. string path = Application.StartupPath + "\\log.txt";
  6. FileStream filestream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
  7. StreamWriter sw = new StreamWriter(filestream, Encoding.Default);
  8. sw.BaseStream.Seek(0, SeekOrigin.End);
  9. sw.WriteLine("*********Exception*********");
  10. sw.WriteLine("Time:" + DateTime.Now);
  11. sw.WriteLine("Message:" + log);
  12. sw.WriteLine("*********Exception*********");
  13. sw.WriteLine();
  14. sw.WriteLine();
  15. sw.Close();
  16. }
  17. }

在捕获到异常的时候直接调用方法即可

转载于:https://blog.51cto.com/alexis/574473

C#生成CHM文件(应用篇)之代码库编辑器(5)【总结、程序、源代码】相关推荐

  1. C#生成CHM文件(应用篇)之代码库编辑器(3)【附源代码下载】

    在这篇文章中,我将介绍AlexisEditor项目下主要Form的实现,即MainForm.EditForm. MainForm MainForm包含的主要变量如下 以frm开头的都是对应的窗体变量, ...

  2. C#生成CHM文件(应用篇)之代码库编辑器(1)

    下面的这个系列是以一个小软件的开发过程为基础,和大家分享下我在开发这个软件时遇到的一些问题和总结. 先更新下软件:代码库编辑器Beta版下载 ,上一版的程序见<C#生成CHM文件(应用篇)> ...

  3. C#生成CHM文件(汇总篇)

    本文是前面的C#生成CHM文件系列文章的汇总以及一些其他的关于CHM的资料链接等. C#生成CHM文件(入门篇) http://www.cnblogs.com/alexis/archive/2010/ ...

  4. C# 生成CHM文件 资料汇总

    本文是前面的C#生成CHM文件系列文章的汇总以及一些其他的关于CHM的资料链接等. C#生成CHM文件(入门篇) http://www.cnblogs.com/alexis/archive/2010/ ...

  5. C#生成CHM文件(中级篇)

    在上篇<C#生成CHM文件(入门篇)>中,我们利用微软自带的hhc.exe以编程的方式创建一个CHM文件,而且调用的是一个静态的HMTL文件.   在中篇中,实现以下几个目标  1.将在线 ...

  6. C#生成CHM文件(应用篇)

    在入门篇中我们了解到如何使用C#调用hhc.exe来生成CHM文件,而在中篇中,我们进行了CHM反编译和将CHM文件转化为Word.在下篇中,我将简单介绍下这些技术在如何应用在实际项目中. CHM电子 ...

  7. C#生成CHM文件(外篇使用hha.dll)

    在<C#生成CHM文件>一系列中,我们是以微软自带的hhc.exe来编译CHM文件的,这样有一个弊端就是当我们的机器里面并没有装hhc.exe就会报错,这通常在盗版的Windows系统比较 ...

  8. 使用Teleport Ultra批量克隆网站,使用Easy CHM合并生成chm文件

    1.要下载的页面 http://www.howsoftworks.net/javaapi/ 2. 下载Teleport Ultra 3.使用Teleport Ultra批量克隆网站 4.下载Easy ...

  9. 生成静态文件的新闻系统核心代码

    在网上看了许多能生成静态页的新闻系统,但基于asp.net的系统极少,闲下时间来自己写了一个,发出来,大家一起研究,代码没做什么优化,只是实现了功能 using System; using Syste ...

最新文章

  1. Vue多个单文件组件使用
  2. Security+jwt+验证码实现验证和授权
  3. jvm gc策略_IBM JVM调整– gencon GC策略
  4. 位运算符 | ^ ~的厉害__10进制 To 2进制
  5. java 接口嵌套接口_Java接口嵌套
  6. visual studio 最新稳定版本_速来围观!Android Studio 4.0 稳定版发布了
  7. Codeforces 875C National Property(拓扑排序)
  8. php抽奖幸运,幸运大转盘-jQuery+PHP实现的抽奖程序
  9. 功率因数cosφ仪表盘
  10. sgu 309 Real Fun
  11. STM32f1之L298N电机驱动+PWM调速(附主代码)
  12. 520情人节送什么礼物合适、送给女生礼物推荐
  13. 使用mockplus设计大屏原型
  14. num_workers
  15. java学生成绩管理系统类图,学生成绩管理系统的用例类图
  16. 微信名片加好友服务器繁忙,还傻乎乎的微信加好友?这些细节你要注意!
  17. Spring MVC使用篇(八)—— 处理器(Handler)方法的返回值
  18. JetBrains 又出了一款新神器,一套代码适应多端!
  19. Incarnation概念
  20. 最新防伪和代{过}{滤}理授权查询系统网站源码V1.3

热门文章

  1. 爆气球这道题目,展开了新的思路
  2. jQuery 中 attr() 和 prop() 方法的区别
  3. VMware网络选项分析
  4. 跨浏览器开发经验总结(三)
  5. SQL中使用WITH AS提高性能-使用公用表表达式(CTE)简化嵌套SQL
  6. Python进阶之路 3.4.2 条件语句(if、else和elif)
  7. Linux Socket编程(不限Linux)
  8. LeetCode之All Possible Full Binary Trees(Kotlin)
  9. 如何实现手机自动适应网页
  10. 用百度siteapp的uaredirect.js判断用户访问端而进行域名的自动跳转