C#生成CHM文件(应用篇)之代码库编辑器(2)
在上一篇文章中,我大致介绍了代码编辑器里面的一些主要功能和大致实现方法,从这篇文章开始,我将会将里面涉及到的一些技术跟大家分享下。
更新下程序 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接下来看下编译方法是怎么实现,具体的代码就不贴了,前面的文章中《C#生成CHM文件(入门篇)》中就有涉及,这里要提到的就是里面的递归算法,即分别将树中的
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);
}
}
}
Name及Local写入到hhc文件中及hhk(索引文件中),两个主要的方法代码如下:
//递归实现将nodes写入hhc文件中private void NodesHhc(CHMNodeList nodeList)ok,至此已经讲了
{
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);
}
}
}
至于获取文件的相对路径和绝对路径的方法相信大家都会写,这里就不介绍了。
如何创建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)
如果您喜欢我的文章,您可以通过支付宝对我进行捐助,您的支持是我最大的动力https://me.alipay.com/alexis
作者:Alexis
出处:http://www.cnblogs.com/alexis/
关于作者:专注于Windows Phone 7、Silverlight、Web前端(jQuery)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,可以通过shuifengxuATgmail.com 联系我,非常感谢。