1.使用的开发工具
- 微软Visual Studio 2005
- Microsoft Word 2003
- 编程语言。C#
2. 使用C#的Word自动化
通过C#实现的Word自动化是指使用C#代码以编程方式生成Word文档。在Word上工作被认为是直截了当的,但以编程方式做同样的事情就有点复杂了。Word自动化几乎完全涉及到与对象和引用类型的工作。几乎所有我们在word 2003上执行的任务都可以用C#或VB来编程完成。像插入目录、链接文档、邮件合并、插入文档、嵌入文档、插入图片、水印......等任务都可以通过编程完成。
3. 设置工作环境
首先,第一步是将Word dll's纳入解决方案中。这可以通过在项目的解决方案资源管理器中右击参考文件夹并选择添加参考来完成。
图1.
浏览可用的COM对象并选择Microsoft Office 11.0 Object Library & Microsoft Word 11.0 Object Library。这个DLL拥有所有我们要执行的自动化的方法。
注意 :这个DLL只有在机器上安装了Microsoft Office才会出现。
在使用的命名空间中也包括 "using Microsoft.Office;"。
图2.
图3.
4. 自动化中使用的对象
所有用于Word自动化的方法都派生自Word.Application或Word.Document 类。
让我们考虑一下,我们想用Word应用程序创建一个文档,我们最终可能要做以下步骤。
- 打开Word应用程序。(打开Word应用程序默认会创建一个新文档,但在自动化中,我们需要手动添加一个文档)
- 添加一个新文档。
- 编辑该文档。
- 保存它。
同样的步骤需要通过编程来完成。Word.Application和Word.Document是用来打开Word和添加一个新文档的。
4.1 Word.Application
这表示在Word应用程序中没有加载任何新的文档。这就像创建一个新文档所需要的基类。创建一个新的Word.Application的实例可以被可视化,如下所示。
图4.
4.2 Word.Document
如果我们需要添加一个新的文档文件,首先要创建一个Word.Document对象的实例,然后把它添加到Word.Application中。
- Object oMissing = System.Reflection.Missing.Value()。
- 对象 oTrue = true。
- 对象 oFalse = false。
- Word.Application oWord = new Word.Application()。
- Word.Document oWordDoc = new Word.Document()。
- oWord.Visible = true。
- oWordDoc = oWord.Documents.Add(ref oMissing, ref oMissing, ref oMissing, ref oMissing)。
这在Word应用程序中触发了以下操作
图5.
执行自动化的方法
- 我们可以有一个基础模板(.dot)文件,然后打开基础模板文件并对其进行操作。
- 否则我们可以从头开始建立一个word文档。
4.3 标准输入参数
大多数方法的输入参数都是参考类型的,其值大多为真、假或缺失(null)。在自动化领域,为什么大多数输入参数都是参考类型的,这可能是因为大多数方法都有大量的输入参数(许多方法有超过10个输入参数),它们的值在大多数情况下都是真、假或缺失。因此,我们可以让所有的输入参数都指向内存中的同一个变量,而不是提供10次相同的输入参数。
4.3.1 范围对象
当我们在Word应用程序中工作时,如果我们想在第11行中输入一些文本,那么我们要手动地把光标点击在所需的行上,然后开始输入。为了完成同样的任务,我们在C#中使用Range变量。Word.Document对象的Range变量表示光标在当前文档中的位置。
有许多可能的方法来指向文档上的特定位置。我曾经广泛地使用过书签定位器,因为我使用基础模板进行自动化工作。在这种方法中,我们在基础模板上插入书签,并以编程方式定位这些书签,在其上设置范围,并在该特定位置插入文本或文档。也有许多其他可能的方法来设置范围。
- Object oBookMarkName = "My_Inserted_Bookmark_On_Template";
- Word.Range wrdRange = oWordDoc.Bookmarks.get_Item(ref oBookMarkName).Range.Select()。
4.3.2 选择对象
在处理word时,我们通过点击和拖动鼠标指针在文档中的内容上选择一个文本范围。这些内容可以是文本、格式化文本、表格或文档中的任何其他项目。我们通过使用从Word.Selection派生出来的Selection对象,以编程方式表示相同的内容。在前面的范围例子中,我们找到了一个书签,并在这个特定的书签上设置了范围,我们选择了它。现在,选择对象代表了那个特定的位置。这就像把光标放在文档上那个特定的书签位置上。跨越文本的选择可以通过在两个范围之间选择一个文本范围来完成。然后,被选中的范围可以被复制、删除或格式化。
4.3.3 在书签之间进行选择
- 对象oBookmarkStart = "BookMark__Start"。
- Object oRngoBookMarkStart = oWordDoc.Bookmarks.get_Item(ref oBookmarkDesignInfoStart).Range.Start。
- 对象 oBookmarkEnd = "BookMark__End";
- Object oRngoBookMarkEnd = oWordDoc.Bookmarks.get_Item(ref oBookmarkDesignInfoEnd).Range.Start。
- Word.Range rngBKMarkSelection = oWordDoc.Range(ref oRngoBookMarkStart, ref oRngoBookMarkEnd) 。
- rngBKMarkSelection.Select()。
- rngBKMarkSelection.Delete(ref oMissing, ref oMissing)。
5.使用基础模板的自动化
基准模板文件的方法是比较好的,因为它在执行自动化时给我们更多的灵活性,它在执行邮件合并时非常方便。
在基础模板方法中,当我们调用应用程序对象的Documents.Add 方法时,我们给出.dot文件的路径。
- 对象oTemplatePath = "C:\\Program Files\MyTemplate.dot"。
- oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing)。
现在.dot文件被打开了,当我们保存生成的文件时,我们把它保存为一个新文件。
6. 邮件合并
邮件合并是一个有用的工具,在这种情况下,我们要随机地生成只有几个字段变化的同类文档。例如,在工资单中,有一个基本的模板,只有雇员的姓名、编号和工资细节需要为每个雇员改变。现在我们可以有一个基本模板,它是一个保存为文档模板文件的word文件。
在.dot文件中,手动插入一个邮件合并字段,把光标放在需要的位置,插入 -> 字段,在字段名中选择**"合并字段**",现在邮件合并字段将用<>表示。该模板可以是这样的
联系信息
如需进一步的信息和讨论,请联系。
姓名:<>
地址:<>
电话:<>(工作)
<>(手机)
传真:<>
电子邮件<>。
现在,对于使用代码以编程方式替换邮件合并字段,文件中默认有许多字段。但是用户输入的字段有前缀和后缀,可以作为标识符来替换这些字段。
- Object oMissing = System.Reflection.Missing.Value();
- Object oTrue = true;
- Object oFalse = false。
- Word.应用程序 oWord = new Word.应用程序()。
- Word.Document oWordDoc = new Word.Document()。
- oWord.Visible = true。
- Object oTemplatePath = "C:\\Program Files\MyTemplate.dot";
- oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
- foreach (Word.Field myMergeField in oWordDoc.Fields)
- {
- iTotalFields++。
- Word.Range rngFieldCode = myMergeField.Code。
- String fieldText = rngFieldCode.Text;
- 如果(fieldText.StartsWith(" MERGEFIELD")
- {
- Int32 endMerge = fieldText.IndexOf("\")。
- Int32 fieldNameLength = fieldText.Length - endMerge;
- String fieldName = fieldText.Substring(11, endMerge - 11);
- fieldName = fieldName.Trim();
- 如果(fieldName == "MyField")
- {
- myMergeField.Select();
- oWord.Selection.TypeText("这个文本替换了模板中的字段")。
- }
- }
- }
还有一种替换合并字段的方法,在msdn中提到,它使用一种相当耗费内存的方法。在该方法中,一个单独的文档被打开,它被插入一个表格,该表格的第一行是邮件合并字段名,第二行是替换值,然后表格中的值与原始文档的值相匹配,发生替换,第二个文档被清除。
7. 嵌入文件
嵌入一个文件是通过应用程序完成的
插入-> 对象-> 从文件创建-> 选择文件-> 显示 为图标。 这将文件嵌入到选定的位置作为一个图标,用户可以双击该图标来打开文件。同样的事情也可以通过自动化完成。
范围应该设置在所需的地方,并且必须选择相同的地方(范围可以通过上面提到的任何方式设置)。现在通过选择,文件可以被嵌入。
- Object oIconLabel = "File Name";
- 对象oIconFileName = "C:\\Document and Settings\IconFile.ico"。
- Object oBookMark = "My_Custom_BookMark";
- Object oFileDesignInfo = "C:\Document and Settings\somefile.doc";
- Object oClassType = "Word.Document.8";
- 对象 oTrue = true。
- Object oFalse = false;
- Object oMissing = System.Reflection.Missing.Value;
- oWordDoc.Bookmarks.get_Item(ref oBookMark).Range.InlineShapes.AddOLEObject(
- ref oClassType,ref oFileDesignInfo,ref oFalse, ref oTrue, ref oIconFileName,
- ref oMissing,ref oIconLabel, ref oMissing)。
8. 插入一个文档文件
一个Word文档的内容也可以通过以下方式从应用程序中插入到当前文档中。
插入 -> 文件 -> 选择文件*。* 这样就可以从选定的文件中提取内容并插入到当前文档中。
在自动化中,我们需要遵循类似的方法,将范围放在所需的点上并选择它,然后插入文件。
- String oFilePath = "C:\\Document and Settings\somefile.doc"。
- oWordDoc.Bookmarks.get_Item(ref oBookMark).Range.InsertFile(oFilePath,ref oMissing, ref oFalse, ref oFalse, ref oFalse)。
9. 在文档背景中包括水印/图片
包括水印是任何官方文件的另一个重要特征,因为水印可能有公司的标志、草案标志或任何其他图片/文字。当我们希望在整个文件的背景中出现一个图片或一些文字时,这是非常有用的。
我们通过执行以下任务在应用程序中插入一个水印。
**格式 ->****背景 ->**打印水印
同样也可以通过编程来完成;此外,由于我们手动定义了水印的倾斜角度和实际位置等值,我们在定义水印的确切位置时有更大的灵活性。
9.1 在文档标题中嵌入图片
- oWord.ActiveWindow.ActivePane.View.SeekView = Word.WdSeekView.wdSeekCurrentPageHeader。
- Word.Shape logoCustom = null;
- String logoPath = "C:\\Document and Settings\MyLogo.jpg"。
- logoCustom = oWord.Selection.HeaderFooter.Shapes.AddPicture(logoPath,
- ref oFalse, ref oTrue, ref oMissing, ref oMissing, ref oMissing, ref oMissing)。
- logoCustom.Select(ref oMissing);
- logoCustom.Name = "CustomLogo";
- logoCustom.Left = (float)Word.WdShapePosition.wdShapeLeft;
- oWord.ActiveWindow.ActivePane.View.SeekView = Word.WdSeekView.wdSeekMainDocument。
9.2 在文档中心插入文字作为水印
- Word.Shape logoWatermark = null;
- logoWatermark = oWord.Selection.HeaderFooter.Shapes.AddTextEffect(
- Microsoft.Office.Core.MsoPresetTextEffect.msoTextEffect1,
- "在此输入文字", "Arial", (float)60,
- Microsoft.Office.Core.MsoTriState.msoTrue。
- Microsoft.Office.Core.MsoTriState.msoFalse,
- 0, 0, ref oMissing)。
- logoWatermark.Select(ref oMissing);
- logoWatermark.Fill.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
- logoWatermark.Line.Visible = Microsoft.Office.Core.MsoTriState.msoFalse;
- logoWatermark.Fill.Solid();
- logoWatermark.Fill.ForeColor.RGB = (Int32)Word.WdColor.wdColorGray30;
- logoWatermark.RelativeHorizontalPosition = Word.WdRelativeHorizontalPosition.wdRelativeHorizontalPositionMargin;
- logoWatermark.RelativeVerticalPosition = Word.WdRelativeVerticalPosition.wdRelativeVerticalPositionMargin;
- logoWatermark.Left = (float)Word.WdShapePosition.wdShapeCenter;
- logoWatermark.Top = (float)Word.WdShapePosition.wdShapeCenter;
- logoWatermark.Height = oWord.InchesToPoints(2.4f);
- logoWatermark.Width = oWord.InchesToPoints(6f);
- oWord.ActiveWindow.ActivePane.View.SeekView = Word.WdSeekView.wdSeekMainDocument。
9.3 在页面中央插入文本,并旋转90度
- Word.Shape midRightText;
- midRightText = oWord.Selection.HeaderFooter.Shapes.AddTextEffect(
- Microsoft.Office.Core.MsoPresetTextEffect.msoTextEffect1,
- "Text Goes Here", "Arial", (float)10,
- Microsoft.Office.Core.MsoTriState.msoTrue。
- Microsoft.Office.Core.MsoTriState.msoFalse,
- 0, 0, ref oMissing)。
- midRightText.Select(ref oMissing);
- midRightText.Name = "PowerPlusWaterMarkObject2"。
- midRightText.Fill.Visible = Microsoft.Office.Core.MsoTriState.msoTrue。
- midRightText.Line.Visible = Microsoft.Office.Core.MsoTriState.msoFalse;
- midRightText.Fill.Solid();
- midRightText.Fill.ForeColor.RGB = (int)Word.WdColor.wdColorGray375;
- midRightText.Rotation = (float)90;
- midRightText.RelativeHorizontalPosition = (int)Word.WdColor.WdColorGray375
- Word.WdRelativeHorizontalPosition.wdRelativeHorizontalPositionMargin。
- midRightText.RelativeVerticalPosition =
- Word.WdRelativeVerticalPosition.wdRelativeVerticalPositionMargin。
- midRightText.Top = (float)Word.WdShapePosition.wdShapeCenter;
- midRightText.Left = (float)480;
**10.**在页脚中包括页码
在页脚中包括自动生成的页码是另一个有用的功能,可以在代码中进行模拟。
- oWord.ActiveWindow.ActivePane.View.SeekView = Word.WdSeekView.wdSeekCurrentPageFooter。
- oWord.Selection.TypeParagraph();
- String docNumber = "1";
- String revisionNumber = "0";
- oWord.Selection.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft;
- oWord.ActiveWindow.Selection.Font.Name = "Arial";
- oWord.ActiveWindow.Selection.Font.Size = 8;
- oWord.ActiveWindow.Selection.TypeText("Document #: " + docNumber + " - Revision #: " + revisionNumber)。
- oWord.ActiveWindow.Selection.TypeText("\t")。
- oWord.ActiveWindow.Selection.TypeText("\t")。
- oWord.ActiveWindow.Selection.TypeText("Page")。
- Object CurrentPage = Word.WdFieldType.wdFieldPage;
- oWord.ActiveWindow.Selection.Fields.Add(oWord.Selection.Range, ref CurrentPage, ref oMissing, ref oMissing)。
- oWord.ActiveWindow.Selection.TypeText(" of ")。
- Object TotalPages = Word.WdFieldType.wdFieldNumPages;
- oWord.ActiveWindow.Selection.Fields.Add(oWord.Selection.Range, ref TotalPages, ref oMissing, ref oMissing) 。
- oWord.ActiveWindow.ActivePane.View.SeekView = Word.WdSeekView.wdSeekMainDocument。
11. 基本文本格式化选项
11.1 分段
这相当于在文档中按下回车键。
- oWord.Selection.TypeParagraph()。
11.2 文本格式化选项
所有在Word应用程序中的文本格式化选项也可以通过自动化来复制。
- oWord.Selection.Font.Bold = 1;
- oWord.Selection.Font.Color = Word.WdColor.wdColorAqua。
- oWord.Selection.Font.Italic = 1;
- oWord.Selection.Font.underline = Word.WdUnderline.wdUnderlineDashHeavy。
11.3 清除格式化
当格式化被应用到一个选区时,同样的格式化会被带到下一行,为了清除格式化,需要选择下一行并调用ClearFormatting()方法。
- oWord.Selection.ClearFormatting()。
12. 内容表
当涉及到官方文件或一些跨越许多页的技术论文时,目录是非常方便的。目录可以在文档建立的过程中被插入和更新。
为了使目录自动生成而不产生任何麻烦,至关重要的是标题、副标题和正文都有各自的属性设置。当我们在应用程序上工作时,这些值会自己设置,我们只需要在需要时进行编辑。但在编程时,我们必须在代码中设置这些值,以防止目录被更新时出现任何异常。
下面是一个以编程方式生成的文件的例子。
图6.
很明显,页眉2和页眉3以及正文的格式是不同的,甚至在目录中,页眉2也与页眉1稍有偏差。
打开上述文件和勾画工具条,查看-> 工具条-> 勾画。将光标移到样本标题2上,我们可以看到格式是标题2,勾勒水平是2级。
图7.
对于正文,格式是Normal + Arial,10pt,勾勒级别是正文。
图8.
为了生成目录,需要以编程方式设置同样的值。
12.1 章节格式
为了设置选择的格式,选择整个文本(像前面选择部分提到的在书签之间选择)并设置值
- Object styleHeading2 = "Heading 2";
- Object styleHeading3 = "Heading 3";
- oWord.Selection.Range.set_Style(ref styleHeading2)。
- oWord.Selection.Range.set_Style(ref styleHeading3)。
12.2 轮廓水平
为了设置大纲级别,选择内容并将其设置为下面提到的数值之一
- oWord.Selection.Paragraphs.OutlineLevel =Word.WdOutlineLevel.wdOutlineLevel2。
- oWord.Selection.Paragraphs.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel3。
- oWord.Selection.Paragraphs.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevelBodyText。
12.3:插入目录
一旦设置了大纲 级别和章节风格,就可以以编程方式插入目录,并且根据用户设置的大纲级别和章节风格,自动填充页数。(也可以参考这个MSDN链接)
- Object oBookmarkTOC = "Bookmark_TOC";
- Word.Range rngTOC = oWordDoc.Bookmarks.get_Item(ref oBookmarkTOC).Range。
- rngTOC.Select()。
- Object oUpperHeadingLevel = "1";
- Object oLowerHeadingLevel = "3";
- Object oTOCTableID = "TableOfContents";
- oWordDoc.TablesOfContents.Add(rngTOC, ref oTrue, ref oUpperHeadingLevel,
- ref oLowerHeadingLevel,ref oMissing, ref oTOCTableID, ref oTrue,
- ref oTrue, ref oMissing, ref oTrue, ref oTrue, ref oTrue)。
12.4 更新目录
通常情况下,目录是在文档生成之初插入的,一旦所有的内容被填充,标题和副标题的位置就会发生变化。如果目录没有被更新,那么它的内容就会指向不同的页面。为了克服这个麻烦,目录需要在自动化结束时被更新。
- oWordDoc.TablesOfContents[1].Update()。
- oWordDoc.TablesOfContents[1].UpdatePageNumbers()。
13. 保存/关闭和重新打开文件
13.1 保存文件
- Object oSaveAsFile = (Object) "C:\\SampleDoc.doc"。
- oWordDoc.SaveAs(ref oSaveAsFile, ref oMissing, ref oMissing, ref oMissing,
- ref oMissing, ref oMissing,ref oMissing, ref oMissing, ref oMissing,
- 参考文献 oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
- 参考 oMissing, 参考 oMissing)。
13.2 关闭文件
- oWordDoc.Close(ref oFalse, ref oMissing, ref oMissing)。
- oWord.Quit(ref oMissing, ref oMissing, ref oMissing)。
13.3 重新打开文件
如果客户在他们的机器上安装了另一个版本的Word,我们在Word2003 dll中使用的Open()方法可能会产生一个异常。如果客户使用的是Word 2002,那么他只能通过Open2002()方法来打开一个word文件。Word 2003中的Open()方法在Word 2002环境下可能会出现异常。 而对于Word 2000,有一个方法叫Open2000(),对于Office 2002,有一个方法叫Open2002()等等。因此,明智的做法是把Open()放在一个try-catch块中,如下所述。
图10.
14.Word自动化创建新文档的技巧(非基础模板方法)
当我们在不使用基本模板的情况下创建一个新文档时,最有用的实体是内置的书签endofdoc。这将是一个从头开始的方法,程序员开始自动化,插入他的第一节内容,然后设置范围指向endofdoc书签,选择它并插入他的内容,再次选择endofdoc,它将指向文档的结尾,现在是在两节之后。