C#对word的操作,已经有一大堆了。近来看的时候,在开篇里面的设计思想和理念我觉得很受用,虽然之前知道这些理论,但这本书以实例的形式将这些理念传播出来,使得接受起来更容易。在此本文只是利用对word操作的例子进行加深一下所学。
"先对问题进行整体分析规划,确定其做什么,再决定其如何做",当你看到这样的理论的时候,你可能会说这理论太老套了,我早就知道,oo思想。回过头想想以前做的项目,有多少项目你真正按照这种指导思想在做。
在<<Data Structures and Program Design In C++>>开篇介绍了程序设计原理,通过life游戏设计,逐一点明oo思想理念。逐层分析,使得问题逐渐明朗。文笔笨拙,无法言明,有兴趣的话可以看看它的讲述,的确很有意思。
正好手边有个C#对word操作的例子(本例需要word的com组件的支持),抛出一己之见。
对word的操作,我们自然会想到word头处理、word中正文内容的处理、word尾部的处理。有什么问题?我们的跨幅太大了。按照oo思想,创建一个word对象,然后初始化、生成word。
1WordObj doc;
2doc.initialize();
3doc.process();
那么WordObj是什么样的呢?
WordObj code
1using System;
2using System.Web;
3using System.Reflection;
4using Microsoft.Office.Interop.Word;
5public class WordObj {
6 private object miss;
7 private object strTemplate;
8 private object strPostion;
9 private string filename;
10
11 private ReportDoc(){//private constructer to void other create instance
12 }
13
14 public void initialize();
15 public process();
16 }
initialize()该做什么。word需要文件名,需要生成后的存储路径。可能想自己提供一个模板。那么就该对它重构一下:
Initialize
1 public void initialize(string filefolder,string docTemplate,string filename){
2 strTemplate=docTemplate;
3 strPostion=filefolder;
4 miss=System.Reflection.Missing.Value;
5 filename=filename;
6 }
7
8 public void initialize(string filefolder,string filename){
9 strPostion=filefolder;
10 miss=System.Reflection.Missing.Value;
11 strTemplate=@"E:\MyTemplate.dot";
12 filename=filename
13 }
14
15 public void initialize(){
16 miss=System.Reflection.Missing.Value;
17 strTemplate=@"E:\MyTemplate.dot";
18 filename=@"test.doc";
19 }
初始化完成。再看看process()的处理过程。
ProcessToWord Code
1 public void ProcessToWord(){
2 ApplicationClass appc=new ApplicationClass();
3 //设置文件存储路径
4 StrOper strop=new StrOper();
5 string filepath=strop.CreateFolder(strPostion);//创建存储到的目标文件夹,CreateFolder()string folder如果存在这样的文件夹返回folder,否则创建并返回folder
6 strPostion=HttpRuntime.AppDomainAppPath+filepath+"\\"+filename;
7
8 //增加文档
9 Document doc=appc.Documents.Add(ref strTemplate,ref miss,ref miss,ref miss);
10 appc.Visible=false;
11 doc.Activate();
12
13 DataTable dt=this.GetData();//取数据
14 if(dt.Rows.Count>0)
15 {
16 //写入内容
17 #region
18
19 this.addWordTable(ref doc,ref appc,dt,miss);
20
21 this.setParagraphTitle(ref appc,"存在问题");
22 this.setParagraphContent(ref appc,this.stringFormat(dt.Rows[0][8]));
23
24 //设置页尾
25 this.setDocBottom(ref appc,this.stringFormat(dt.Rows[0]["report_person"]));
26 this.setDocBottom(ref appc,this.stringFormat(dt.Rows[0]["fill_time"]));
27
28 #endregion
29 doc.SaveAs(ref strPostion,ref miss,ref miss,ref miss,ref miss,ref miss,ref miss,ref miss,ref miss,ref miss,ref miss,ref miss,ref miss,ref miss,ref miss,ref miss);
30
31 doc.Close(ref miss,ref miss,ref miss);
32
33 appc.Quit(ref miss,ref miss,ref miss);
34
35 }
36 else
37 this.MessageBox("没有数据,不能生成");
38
39 }
对word头、word正文内容、word尾部的处理,放在一起使得程序阅读起来不方便,同时也违背了oo思想。增加三个方法:
Code
1
2 private void setParagraphTitle(ref ApplicationClass appc,string strTitle){//设置word title
3 appc.Selection.TypeParagraph();
4 appc.Selection.Font.Size=14;//4号字体
5 appc.Selection.ParagraphFormat.LeftIndent=appc.CentimetersToPoints(float.Parse("0"));
6 appc.Selection.Font.Bold=(int)WdConstants.wdToggle;//加粗
7 appc.Selection.TypeText(strTitle);
8 appc.Selection.Font.Bold=(int)WdConstants.wdToggle;//加粗结束
9 }
10
11 private void setParagraphContent(ref ApplicationClass appc,string strContent){//设置word paragraph
12 appc.Selection.TypeParagraph();
13 appc.Selection.Font.Size=10.5f;
14 appc.Selection.Font.NameFarEast="宋体";
15 appc.Selection.Font.Bold=0;
16 appc.Selection.ParagraphFormat.LeftIndent=appc.CentimetersToPoints(float.Parse("1"));//设置段落行首缩进2个字符
17 appc.Selection.TypeText(strContent);
18 appc.Selection.Font.Bold=0;
19 }
20
21 private void setDocBottom(ref ApplicationClass appc,string strContent){//设置word落款:签名及日期
22 appc.Selection.TypeParagraph();
23 appc.Selection.Font.Size=10.5f;
24 appc.Selection.Font.NameFarEast="宋体";
25 appc.Selection.Font.Bold=0;
26 appc.Selection.ParagraphFormat.LeftIndent=appc.CentimetersToPoints(float.Parse("10"));
27 appc.Selection.TypeText(strContent);
28 appc.Selection.Font.Bold=0;
29 }
好像还少点什么?还缺少数据源,程序当然是为了简化我们的操作,没有数据源就显得无意义了:)。 本例中取得数据源为:
DataTable dt=this.GetData();
在对正文内容处理中,我们可能会插入其它元素,比如表、图片或者其它对象。在此只给出对插入表格的操作.
Code
1private void addWordTable(ref Document doc,ref ApplicationClass appc,DataTable dt,object miss){
2 //传入参数doc:word document;appc:ApplicationClass的一个实例;dt:数据源;miss:System.Reflection.Missing.Value;
3 //引用传参
4 //不返回值
5 Microsoft.Office.Interop.Word.Table docTable=doc.Tables.Add(appc.Selection.Range,7,3,ref miss,ref miss);//插入了一个7行3列的table到word中
6
7 this.setDocTable(ref docTable,dt);
8
9 object count=docTable.Rows.Count+1;
10 object wdline=Microsoft.Office.Interop.Word.WdUnits.wdLine;
11 appc.Selection.MoveDown(ref wdline,ref count,ref miss);//移动appc焦点选区到word table之后
12 }
Code
1private void setDocTable(ref Microsoft.Office.Interop.Word.Table doctable,DataTable dt){//填充表格数据内容
2 //输入参数 WordTable:要填充的word表,DataTable:数据源
3 //引用传参
4 //不返回值
5 this.setDocTableSytle(ref doctable);
6 doctable.Cell(1,1).Range.Text="报告名称";
7 doctable.Cell(1,2).Range.Text=":";
8
9 doctable.Cell(1,3).Range.Text=this.stringFormat(dt.Rows[0][0]);
10
11 /**//*
12 fill the data to doc
13 */
14 }
15
16
有了table,还要对其设定成想要的格式,这样看起来才美观
Code
1private void setDocTableSytle(ref Microsoft.Office.Interop.Word.Table doctable){//设置word table的样式
2 doctable.Columns[1].Width=100f;
3 doctable.Columns[2].Width=20f;
4 doctable.Columns[3].Width=280f;
5 for(int i=1;i<=doctable.Rows.Count;i++){
6 doctable.Cell(i,1).Range.Font.NameFarEast="黑体";
7 doctable.Cell(i,1).Range.Font.Size=15;
8 }
9 }
10
在setParagraphContent()中,因是从数据库取的数据,增加了一个数据格式的处理,处理出现null的列。
StringFormat code
1private string stringFormat(object obj){//格式化数据,datatable的column为Null时,返回""
2 if(obj!=System.DBNull.Value)
3 return obj.ToString();
4 return "";
5 }
在对word的处理中,人为的增添了限制:word模板和word com组件。这些限制使得程序并不很完善,进一步就需要一一摘除这些限制。由于能力有限,去除word com组件还有困难。
通过对word操作,加固自己对这一程序设计理念的印象,努力改变以前"搭棚式程序设计"。