在这篇文章中,我将介绍AlexisEditor项目下主要Form的实现,即MainForm、EditForm。
MainForm
MainForm包含的主要变量如下
以frm开头的都是对应的窗体变量,chmDocument表示当前的电子书,dockPanel是MainForm上的Panel,负责实现Visual Studio风格的面板。
下图是MainForm的主要方法。
在一开始是实例化Form窗体的时候会调自身的构造器,在构造器中我们其他的窗体,主要代码如下
frmIndex.Show(dockPanel);//显示目录窗体
frmIndex.DockTo(dockPanel, DockStyle.Left);
frmList.Show(dockPanel);//显示搜索窗体
frmList.DockTo(dockPanel, DockStyle.Fill);
this.frmIndex.TreeIndex.NodeMouseDoubleClick += new TreeNodeMouseClickEventHandler(TreeIndex_NodeMouseDoubleClick);//注册编辑文章事件
加载界面的时候会触发MainForm_Load事件,我们在这个方法里面加载电子书的目录,代码如下:
chmDocument.Load("index.xml");//加载目录
RefreshView(chmDocument, frmIndex.TreeIndex);
RefreshView是同步TreeView和CHMDocument的方法,很重要


{
tvw.BeginUpdate();
tvw.Nodes.Clear();
System.Windows.Forms.TreeNode node = tvw.Nodes.Add(doc.Title);
node.Tag = doc;
node.ImageIndex = 0 ;
node.SelectedImageIndex = 0 ;
AddNodes(doc.Nodes, node);
tvw.EndUpdate();
tvw.SelectedNode = node;
node.Expand();
}
RefreshView会调用AddNodes方法添加节点,方法明细如下


{
if (list == null || list.Count == 0 )
return ;
foreach (CHMNode node in list)
{
System.Windows.Forms.TreeNode n = new TreeNode(node.Name);
n.Tag = node;
if (node.Nodes.Count > 0 )
n.ImageIndex = 0 ;
else
n.ImageIndex = 1 ;
n.SelectedImageIndex = n.ImageIndex;
RootNode.Nodes.Add(n);
if (node.Nodes.Count > 0 )
AddNodes(node.Nodes, n);
}
}
New方法是新建文章方法,当我们选中目录节点,右击的时候会出现一些菜单,其中就有新建文章
方法体很简单,其他的事情都交给EditForm去完成
EditForm frmEdit = EditForm.CreateEditForm();
frmEdit.Show();
Compile方法是编译方法,负责将目录中的文章编译为对应的CHM电子书,并且在编译的时候主页面下方的状态栏会显示编译过程,虽然是比较简陋的编译过程。


private void Compile()
{
frmOutPut.Show(dockPanel);
frmOutPut.DockTo(dockPanel, DockStyle.Bottom);
chmDocument.FileName = " index.xml " ;
chmDocument.Compile();
// frmOutPut.RtbOutput.Text = chmDocument.OutPutText;
frmOutPut.TxtOutput.Text = chmDocument.OutPutText;
}
AddPage对应着程序工具栏上的IE图标,添加HMTL页面的功能,主要代码如下:


private void AddPage()
{
TreeNode node = this .frmIndex.TreeIndex.SelectedNode; // 选中的节点
// 查看是否是根节点或是目录节点
CHMNodeList list = this .GetNodeList(node);
if (list == null )
{
MessageBox.Show( " 请选择根节点或是目录节点 " );
return ;
}
using (OpenFileDialog ofd = new OpenFileDialog()) // 可以批量选择
{
ofd.Filter = " HTML Files|*.html;*.htm " ;
ofd.Multiselect = true ; // 设置可以选择多个文件
ofd.ShowDialog();
if (ofd.FileNames.Length > 0 )
{
for ( int i = 0 ; i < ofd.FileNames.Length; i ++ )
{
CHMNode newNode = new CHMNode(); // 创建新的节点
newNode.Name = ofd.SafeFileNames[i].ToString();
newNode.ImageNo = " 1 " ;
newNode.Local = ofd.FileNames[i].ToString();
newNode.Nodes = null ;
list.Add(newNode);
System.Windows.Forms.TreeNode node2 = new TreeNode(newNode.Name);
node2.Tag = newNode;
node2.ImageIndex = 1 ;
node2.SelectedImageIndex = 1 ;
node.Nodes.Add(node2); // 将新节点添加到树中
node.ImageIndex = 0 ;
node.SelectedImageIndex = 0 ;
}
}
}
}
保存方法是将目录上的信息保存到xml 文件中,是调用CHMDocument类中的Save方法。
//保存方法
private void Save()
{
chmDocument.Save("index.xml");
}
EditForm窗体
startPath:程序的开始路径,有重要用处
node属性:负责和其他页面的交互
wbEditor:WebBrowser控件的实例,负责加载HTML编辑器,保存文章等功能
txtName:文章的标题
txtKeyWords:文章的关键字,用于Lucene.NET搜索
下面来看看他的一些主要方法及其实现:
EditForm_Load方法:加载编辑器,实现如下:


/// 窗体加载事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void EditForm_Load( object sender, EventArgs e)
{
startPath = Application.StartupPath; // 起始路径
// 这边可以做成从配置文件中读取选择什么编辑器
// Uri u = new Uri(startPath + @"\ckeditor\index.html");
this .wbEditor.Navigating += new WebBrowserNavigatingEventHandler(wbEditor_Navigating); // 为了获取前台的点击事件
Uri u = new Uri(startPath + @" \优快云_UBB\normal.htm " );
this .wbEditor.Url = u;
}
WebBrowser控件中的html事件,是通过Navigating方法来实现的,WebBrowser导航发生改变时就会触发如下的方法,我们可以自己写js事件,让WebBrowser的导航发生改变
如这边
<script type="text/javascript">
function getValue(){
document.getElementById("content").value=document.getElementById("tb_ReplyBody___Editor").innerHTML;
this.location.href="loading.htm";
}
</script>
具体的实现可以参考源代码


{
if (e.Url.AbsolutePath.ToString().Replace( ' / ' , ' \\ ' ) == startPath + @" \优快云_UBB\loading.htm " )
{
HtmlDocument hd = this .wbEditor.Document; // 获取文档信息
HtmlElement he = hd.GetElementById( " content " );
IHTMLDocument2 doc = (IHTMLDocument2) this .wbEditor.Document.DomDocument;
mshtml.HTMLInputElement text1 = (HTMLInputElement)doc.all.item( " content " ); // 获取隐藏域中的值
string rr = text1.value;
if ( this .txtName.Text == "" )
{
MessageBox.Show( " 文章标题不能为空! " );
return ;
}
string filename = GetFileName();
if (filePathEdit != "" )
{
filename = filePathEdit.Substring(filePathEdit.LastIndexOf( ' \\ ' ) + 1 );
filename = filename.Substring( 0 , filename.LastIndexOf( ' . ' ));
File.Delete(filePathEdit);
}
// 将内容存入到html模板中,并生产html文件
if (rr != "" )
{
FileStream fs = new FileStream( " html_files\\ " + filename + " .htm " , FileMode.Create); // 文件名
StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.GetEncoding( " UTF-8 " ));
sw.WriteLine( " <!DOCTYPE html PUBLIC \ " - // W3C // DTD XHTML 1.0 Transitional // EN\" \" http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd \">");
sw.WriteLine( " <html xmlns=\ " http: // www.w3.org/1999/xhtml\">");
sw.WriteLine( " <head> " );
sw.WriteLine( " <title> " + this .txtName.Text + " </title> " ); // 文章名
sw.WriteLine( " <meta content=\ " text / html; charset = utf - 8 \ " http-equiv=\ " content - type\ " /> " );
sw.WriteLine( " <link type=\ " text / css\ " rel=\ " stylesheet\ " href=\ " Styles / SyntaxHighlighter.css\ " ></link> " );
sw.WriteLine( " <script type=\ " text / javascript\ " src=\ " Scripts / shCore.js\ " ></script> " );
sw.WriteLine( " <script type=\ " text / javascript\ " src=\ " Scripts / shBrushCSharp.js\ " ></script> " );
sw.WriteLine( " <script type=\ " text / javascript\ " src=\ " Scripts / shBrushXml.js\ " ></script> " );
sw.WriteLine( " <script type=\ " text / javascript\ " > window.onload = function () { " );
sw.WriteLine( " dp.SyntaxHighlighter.ClipboardSwf = 'Scripts/clipboard.swf'; " );
sw.WriteLine( " dp.SyntaxHighlighter.HighlightAll('code');} " );
sw.WriteLine( " </script> " );
sw.WriteLine( " </head> " );
sw.WriteLine( " <body> " );
rr = ChangeString(rr);
sw.WriteLine(rr);
sw.WriteLine( " </body> " );
sw.WriteLine( " </html> " );
sw.Close();
}
// 将节点返回给目录,暂不做保存操作
node = new CHMNode();
node.Local = startPath + " \\html_files\\ " + filename + " .htm " ;
node.Name = this .txtName.Text;
node.Nodes = null ;
node.ImageNo = " 1 " ;
// TODO: 使用Lucene.Net存储索引,方便以后的搜索
this .Close();
// this.wbEditor.Url = new Uri(startPath + @"\success.htm");
}
}
#endregion
ok,至此,主要的部分都已经讲解了(还有一个BookIndexForm,在下篇中和其他的一起讲解),还有许多细节的地方可参考我的源代码
PS:不是最新版的源代码,最新版的源代码还在开发中, 恕不提供,嘿嘿