C# 实现多种Word邮件合并功能
在处理Word文档的工作中经常会遇见这样一种情况:文件的主要内容和格式大体相同,只是需要填充的数据不同。如果一个一个填写数据的话会非常麻烦,而且很耗时间。这时候我们就可以灵活运用Word邮件合并功能来快速实现这一操作。
这里我将介绍如何使用C#和Word组件Spire.Doc实现一些常用的Word文档邮件合并功能。
Spire.Doc组件概述
Spire.Doc是一款专门对 Word 文档进行操作的 .NET类库,用于在.NET应用程序中创建、编辑、打印和转换Word文档,并且无需安装Microsoft Word。它支持几乎所有的 Word 文档元素,主要包括页面、节、页眉、页脚、脚注、尾注、段落、项目符号和编号、表格、文本、域、超链接、书签、注释、图片、样式、背景设置、打印功能、文档设置和文档保护。同时,也支持形状、文本框、图片、OLE 对象和内容控件。
它的安装比较简单,可以从官网或Nuget直接下载组件的dll文件。在VisualStudio的NuGet Package Manager Console中输入以下PowerShell命令回车,组件的dll就会自动地引用到项目中:
PM>Install-Package Spire.Doc
1. 创建邮件合并模板文档
1.1. Microsoft Word创建邮件合并模板文档
我们知道,执行邮件合并前需要先根据需求创建带有合并域的模板文档。下图展示了如何在Microsoft Word中插入合并域(MergeField)到Word文档。
1.2. Spire.Doc创建邮件合并模板文档
在Spire.Doc中,我们可以通过Paragraph对象调用AppendField (string fieldName, FieldTypefieldType) 方法插入合并域到Word文档。
//创建Word文档
Document document = new Document();
//添加节
Section section = document.AddSection();
//添加段落
Paragraph paragraph = section.AddParagraph();
//添加文本
paragraph.AppendText("编号:");
//添加合并域“Emp_Id”
paragraph.AppendField("Emp_Id",FieldType.FieldMergeField);
//添加文本
paragraph.AppendText("\n姓名:");
//添加合并域“Name”
paragraph.AppendField("Name",FieldType.FieldMergeField);
//添加文本
paragraph.AppendText("\n电话:");
//添加合并域“Phone”
paragraph.AppendField("Phone",FieldType.FieldMergeField);
//添加文本
paragraph.AppendText("\n部门:");
//添加合并域“Department”
paragraph.AppendField("Department",FieldType.FieldMergeField);
//保存文档
document.SaveToFile("模板.docx",FileFormat.Docx2013);
document.Close();
注:此处如果不想使用\n换行,可在每次插入域之后再插入换行符:
paragraph.AppendBreak(BreakType.LineBreak);
2. 执行邮件合并
2.1. 简单邮件合并
MailMerge类中提供了执行邮件合并的方法Execute (),它共有7种重载方法:
从上图可以看出,选择不同的重载方法,可以从不同的数据源如Datatable,Dataview,DataReader和数组等合并数据。
下面我使用刚刚创建的模板文档,并以一对数组作为Execute ()方法的参数。其中第一个数组表示域的名称,第二个数组表示域的值。名称和值的数量需要一致。
//加载模板文档
Document document = new Document("模板.docx");
string[] fieldNames = new string[] { "Emp_Id","Name", "Phone","Department" };
string[] fieldValues = new string[] { "0065","李强", "+86151XXXX1101", "开发部" };
//执行邮件合并(也就是添加数据)
document.MailMerge.Execute(fieldNames, fieldValues);
//保存文档
document.SaveToFile("MergeText.docx", FileFormat.Docx2013);
document.Close();
2.2. 带图片邮件合并
除简单的文字合并以外,MailMerge类还支持通过MergeImageField事件来添加图片到合并域。
Document doc = new Document();
doc.LoadFromFile("图片.docx");
var fieldNames = new string[] { "Photo "};
var fieldValues = new string[] { "Photo.jpg"};
doc.MailMerge.MergeImageField += new MergeImageFieldEventHandler(MailMerge_MergeImageField);
doc.MailMerge.Execute(fieldNames, fieldValues);
doc.SaveToFile("MergeImage.docx",FileFormat.Docx);
static void MailMerge_MergeImageField(object sender, MergeImageFieldEventArgsfield)
{
string filePath =field.FieldValue as string;
if (!string.IsNullOrEmpty(filePath))
{
field.Image= Image.FromFile(filePath);
}
}
2.3. 区域邮件合并
区域邮件合并顾名思义就是在Word文档的指定区域添加数据。需要注意的是区域邮件合并需要模板文档中含有指定区域的标识符,这种标识符应该由一对组成(包括区域开始标识和区域结束标识),且通常有两种类型:«GroupStart:XXX» 和 «GroupEnd:XXX»,以及«TableStart:XXX»和«TableEnd:XXX»。其中XXX表示区域的名称。如下图所示:
我首先创建了一个类"Product",在这个类中创建了构造函数 Product (int number, string type, stringname, string price, string vendor) 并添加了一些属性 "Number", "Type","Name", "Price" 和"Vendor"。
Product p1 = new Product(1, "Software","A", "799","Company A");
Product p2 = new Product(2, "Software","B", "599","Company B");
Listlist = new List();
list.Add(p1);
list.Add(p2);
//加载模板
Document document = new Document("产品清单.docx");
MailMergeDataTable table = new MailMergeDataTable("Products", list); //注意此处所使用的区域名称必须和模板文档中的区域名称一致
//执行区域邮件合并
document.MailMerge.ExecuteGroup(table);
//保存文档
document.SaveToFile("MergeWithinRegion.docx");
从生成结果可以看出区域邮件合并会为数据源中的每条数据创建一条单独的记录,换句话说区域合并可以在Word文档的指定区域重复添加多条相同类型的数据。
2.4. 邮件合并时生成多个文档
我们还可以为每条数据创建一个单独的文档,只需要在每条数据执行合并前复制一次模板文档,然后在副本中进行数据合并,并将结果保存为一个单独的文档。也可以加载文档,但复制文档速度更快。
DataTable datatable = new DataTable();
datatable.Columns.Add("TeamName", typeof(string));
datatable.Columns.Add("TotalPoint",typeof(int));
datatable.Columns.Add("Ranking",typeof(int));
datatable.Columns.Add("Prize",typeof(string));
DataRow dr1 = datatable.NewRow();
dr1["TeamName"]= "A";
dr1["TotalPoint"]= "20";
dr1["Ranking"]= "1";
dr1["Prize"]= "$1000";
datatable.Rows.Add(dr1);
DataRow dr2 = datatable.NewRow();
dr2["TeamName"]= "B";
dr2["TotalPoint"]= "15";
dr2["Ranking"]= "2";
dr2["Prize"]= "$500";
datatable.Rows.Add(dr2);
int i = 0;
Document document = new Document();
document.LoadFromFile("团队排名.docx");
foreach (DataRow row in datatable.Rows)
{
DocumentdestDocument = document.Clone();
destDocument.MailMerge.Execute(row);
destDocument.SaveToFile(string.Format("FileOut{0}.doc",i++));
}
2.5. 嵌套邮件合并
嵌套邮件合并是在两个或多个嵌套的区域中添加数据。在下面的模板中包含了两个嵌套区域(Group和Table):
接下来我将从下面的xml文档中读取数据并填充到以上模板中。
Listlist = new List();
DataSet dsData = new DataSet();
//读取xml文件
dsData.ReadXml(@"Orders.xml");
//加载模板文档
Document document = new Document();
document.LoadFromFile(@"报价单.docx");
DictionaryEntry dictionaryEntry = new DictionaryEntry("Quote", string.Empty);
list.Add(dictionaryEntry);
dictionaryEntry = newDictionaryEntry("Supply","Quote_Id = %Quote.Quote_Id%");
list.Add(dictionaryEntry);
//由于我的xml文件中有多条记录,因此插入分页符以便查看
document.MailMerge.MergeGroup +=MailMerge_MergeGroup;
//执行嵌套合并
document.MailMerge.ExecuteWidthNestedRegion(dsData,list);
//保存文档
document.SaveToFile("NestedMailMerge.docx",FileFormat.Docx2013);
static voidMailMerge_MergeGroup(object sender, MergeGroupEventArgs args)
{
if(args.EventType == GroupEventType.GroupStart)
{
if(args.RowIndex > 0)
{
MergeField mergeField =args.MergeField as MergeField;
Paragraph ownerPara =mergeField.OwnerParagraph;
ownerPara.AppendBreak(BreakType.PageBreak);
}
}
}
总结
以上就是博主所总结的Spire.Doc所支持的一些Word邮件合并功能,如有任何疑问,欢迎给博主留言!。