在上一篇文章中,我大致介绍了代码编辑器里面的一些主要功能和大致实现方法,从这篇文章开始,我将会将里面涉及到的一些技术跟大家分享下。
更新下程序 AlexisEditor下载
看下程序的界面,有菜单里、工具栏,还有几个可以悬停的面板
程序的Soultion , 可以看到有三个项目,一个WinForm项目及两个类库项目,增加类库项目是为了更好的实现代码分离。
下面的两张图是主项目AlexisEditor的类关系图:
在来看看ChmHelper项目的类关系图(这张图会在下面反复涉及)
Viusal Studio风格的界面的实现
在上一篇文章中有介绍到Viusal Studio风格的界面,它的实现很简单,由上图我们看到有许多Form是继承自BaseDockForm的,而BaseDockForm是继承自DockContent的。
实现步骤如下:
添加 WeifenLuo.WinFormsUI.Docking.dll引用,新建BaseForm继承自WeifenLuo.WinFormsUI.Docking.DockContent。
在主界面中放置一个DockPanel,设置它的Dock属性为Fill,然后在主界面中使用如下代码即可
- public MainForm()
- {
- InitializeComponent();
- frmIndex.Show(dockPanel);//显示目录窗体
- frmIndex.DockTo(dockPanel, DockStyle.Left);
- }
这样目录窗体就可以自动靠左显示,并可以自动隐藏。其他的窗体可以类似实现。
目录树的实现
上篇文章中讲到使用xml存储目录,那么这个xml是什么样的格式呢?AlexisEditor的目录树如下:
- <CHMDocument Title="帮助文档">
- <Items>
- <Node Name="但是使用" Local="E:\WorkSpace\projects\AlexisEditor\AlexisEditor\bin\Debug\html_files\129317762488604234.htm" ImageNumber="1" KeyWords="" />
- <Node Name="aa" Local="E:\WorkSpace\projects\AlexisEditor\AlexisEditor\bin\Debug\html_files\129317940192503066.htm" ImageNumber="1" KeyWords="" />
- <Node Name="新建文件夹" Local="" ImageNumber="0" KeyWords="">
- <Items>
- <Node Name="aa" Local="E:\WorkSpace\projects\AlexisEditor\AlexisEditor\bin\Debug\html_files\129317940469098887.htm" ImageNumber="1" KeyWords="aaa" />
- </Items>
- </Node>
- </Items>
- </CHMDocument>
根节点是CHMDocument ,如果几点有<Items>子节点,表示该节点是父节点。
每个节点有这样的属性,Name表示文章的标题,Local表示文章的实际路径,ImageNumber表示几点的图片索引,KeyWords表示文章中的关键字。
如果该节点有子节点,则子节点也是这样的,当然父节点的Local、KeyWords为空。
这样的节点对应着类CHMNode,从类关系图中可以看到还有一个Nodes属性,它表示节点的子节点的集合。它是类CHMNodeList的实例,CHMNodeList继承自CollectionBase,并重写了一些集合的主要的方法。
CHMDocument类
CHMDocument类是ChmHelper中最重要的类,它表示当前的电子书,并且负责将书籍编译为CHM电子书的重任。下面着重来看它是怎么实现的,从上述的关系图中看到它有许多的方法、属性和字段。下面分别介绍:
CHMDocument类之属性
FileName表示CHM文件名,Nodes表示电子书除了根节点以外的节点集合,OutPutText表示在生成CHM电子书的编译信息,Title表示CHM的标题
CHMDocument类之字段
streamWriter:以流实现写入文件的类的实例,strHhp、strHhc、strHhk分别是临时生成的hhp、hhc、hhk文件的文件名,默认为alexisEditor,至于config他是静态类XBookConfig类的实例,用来实现一些配置信息,如编译器的路径,是否删除临时文件等。
CHMDocument类之方法
下图是CHMDocument类的主要方法及一些简单说明
先来看加载方法及其调用的方法
- public void Load(string filename)
- {
- System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
- doc.Load(filename);
- FromXML(doc.DocumentElement);
- }
和
- private void FromXML(System.Xml.XmlElement RootElement)
- {
- //this.defaultPage = RootElement.GetAttribute("DefaultTopic");
- this._title = RootElement.GetAttribute("Title");//标题
- nodeList.Clear();
- foreach (System.Xml.XmlNode node in RootElement.ChildNodes)
- {
- if (node.Name == "Items")
- {
- NodesFromXML(nodeList, (System.Xml.XmlElement)node);
- }
- }
- }
和
- private void NodesFromXML(CHMNodeList nodes, System.Xml.XmlElement RootElement)
- {
- foreach (System.Xml.XmlNode node in RootElement.ChildNodes)
- {
- if (node.Name == "Node")
- {
- System.Xml.XmlElement element = (System.Xml.XmlElement)node;
- CHMNode NewNode = new CHMNode();
- NewNode.Name = element.GetAttribute("Name");
- NewNode.Local = element.GetAttribute("Local");
- NewNode.ImageNo = element.GetAttribute("ImageNumber");
- NewNode.KeyWords = element.GetAttribute("KeyWords");
- nodes.Add(NewNode);
- foreach (System.Xml.XmlNode node2 in element.ChildNodes)
- {
- if (node2.Name == "Items")
- {
- NodesFromXML(NewNode.Nodes, (System.Xml.XmlElement)node2);
- }
- }
- }
- }
- }
注意NodesFromXML 方法是递归的方法,大家可以仔细琢磨下这些代码,保存方法其实是类似的,不同的是将节点保存到xml中,代码如下:
- public void Save(string filename)
- {
- System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
- doc.AppendChild(doc.CreateElement("CHMDocument"));
- ToXML(doc.DocumentElement);
- doc.Save(filename);
- _fileName = filename;
- }
- private void ToXML(System.Xml.XmlElement RootElement)
- {
- //RootElement.SetAttribute("DefaultTopic", this.strDefaultTopic);
- RootElement.SetAttribute("Title", this._title);
- System.Xml.XmlElement element = RootElement.OwnerDocument.CreateElement("Items");
- RootElement.AppendChild(element);
- NodesToXML(nodeList, element);
- }
- //nodes保存为xml
- private void NodesToXML(CHMNodeList nodes, System.Xml.XmlElement RootElement)
- {
- System.Xml.XmlDocument doc = RootElement.OwnerDocument;
- foreach (CHMNode node in nodes)
- {
- System.Xml.XmlElement NodeElement = doc.CreateElement("Node");
- NodeElement.SetAttribute("Name", node.Name);
- NodeElement.SetAttribute("Local", node.Local);
- NodeElement.SetAttribute("ImageNumber", node.ImageNo);
- NodeElement.SetAttribute("KeyWords", node.KeyWords);
- RootElement.AppendChild(NodeElement);
- if (node.Nodes != null && node.Nodes.Count > 0)
- {
- System.Xml.XmlElement ItemsElement = doc.CreateElement("Items");
- NodeElement.AppendChild(ItemsElement);
- NodesToXML(node.Nodes, ItemsElement);
- }
- }
- }
接下来看下编译方法是怎么实现,具体的代码就不贴了,前面的文章中《C#生成CHM文件(入门篇)》中就有涉及,这里要提到的就是里面的递归算法,即分别将树中的Name及Local写入到hhc文件中及hhk(索引文件中),两个主要的方法代码如下:
- //递归实现将nodes写入hhc文件中
- private void NodesHhc(CHMNodeList nodeList)
- {
- if (nodeList.Count == 0 || nodeList == null)
- return;
- streamWriter.WriteLine(" <UL>");
- foreach (CHMNode node in nodeList)
- {
- if (node.Nodes != null && node.Nodes.Count > 0)//如果是父节点
- {
- streamWriter.WriteLine(" <LI><OBJECT type=\"text/sitemap\">");
- streamWriter.WriteLine(" <param name=\"Name\" value=\"" + node.Name + "\">");
- streamWriter.WriteLine(" </OBJECT>");
- NodesHhc(node.Nodes);
- }
- else//如果是子节点
- {
- streamWriter.WriteLine(" <LI><OBJECT type=\"text/sitemap\">");
- streamWriter.WriteLine(" <param name=\"Name\" value=\"" + node.Name + "\">");
- streamWriter.WriteLine(" <param name=\"Local\" value=\"" + node.Local + "\">");
- streamWriter.WriteLine(" </OBJECT>");
- }
- }
- streamWriter.WriteLine(" </UL>");
- }
- 及
- //递归写hhp中的Files
- private void NodesHhp(CHMNodeList nodeList)
- {
- if (nodeList == null || nodeList.Count == 0)
- return;
- foreach (CHMNode node in nodeList)
- {
- if (node.Nodes == null || node.Nodes.Count == 0)
- {
- streamWriter.WriteLine(node.Local);
- }
- else
- {
- NodesHhp(node.Nodes);
- }
- }
- }
至于获取文件的相对路径和绝对路径的方法相信大家都会写,这里就不介绍了。
ok,至此已经讲了
如何创建Viusl Studio风格的窗体程序?
【让要悬停的窗体继承自DockContent,在调用窗体添加DockPanel,实例化悬停窗体,调DockTo方法】
PS:说明下,如何在ToolBox中添加DockPanel图标==》右击工具箱(ToolBox),选择“选择项...”,添加WeifenLuo.WinFormsUI.Docking.dll引用即可
以及目录是怎么通过xml实现的?
【使用xml存储书籍目录信息,使用类与xml、书籍对应,使用递归的方法获取树的节点】
当然目录树中还有许多其他的问题,今天将的只是类库里面的东西,不过万变不离其中,前台基本上都市调用这些代码的。
看了这篇文章后,大家可以尝试建立个Visual Studio风格的窗体、ChmHelper类库项目的大体(具体实现个随喜好),如果关于以上两点大家还有什么不明白的,
可以留言或者发邮件给我,我会尽快回答的。
再次PS下,如果觉得好的话,请推荐。另:求visual studio编译项目的图标(BMP格式,16*16)
附件:http://down.51cto.com/data/2358205
本文转自xshf12345 51CTO博客,原文链接:http://blog.51cto.com/alexis/574413,如需转载请自行联系原作者