通如何使用郵件合并創(chuàng)建報(bào)告
我們已經(jīng)介紹了如何在 C# 和 VB.NET 中比較兩個(gè) Word 文檔。從 Spire.Doc V8.12.14 開(kāi)始,它支持在結(jié)構(gòu)列表中獲取兩個(gè) Word 文檔之間的差異。本文將向您展示如何使用 Spire.Doc 通過(guò)比較兩個(gè) Word 文檔來(lái)獲取差異。
介紹
郵件合并通常用于批量打印報(bào)表,例如財(cái)務(wù)報(bào)表、工資單或成績(jī)單。合并后的文件可以通過(guò)電子郵件發(fā)送。
在本文中,我將展示一種通過(guò) Spire.Doc 生成郵件合并報(bào)告的方法。
報(bào)告概覽
此報(bào)告包括多張發(fā)票,每張發(fā)票都從一個(gè)新頁(yè)面開(kāi)始。發(fā)票標(biāo)志和供應(yīng)商信息將顯示在每頁(yè)的標(biāo)題中。
訂單、裝運(yùn)、客戶、訂單詳情和總價(jià)構(gòu)成一張完整的發(fā)票。
下圖為發(fā)票外觀:
每張發(fā)票的內(nèi)容詳情如下所示:
訂單數(shù)據(jù)概覽
本示例中的所有數(shù)據(jù)均來(lái)自 Northwind 數(shù)據(jù)庫(kù),該數(shù)據(jù)庫(kù)是 Microsoft Access 2003 提供的示例數(shù)據(jù)庫(kù)。
我們將從Orders、Shippers、Customers、Employees、[Order Details]和Products表中導(dǎo)出數(shù)據(jù)以生成我們的報(bào)告。下圖展示了6個(gè)表之間的關(guān)系。
步驟:
我們需要完成以下 3 個(gè)步驟來(lái)生成我們的報(bào)告。
- 創(chuàng)建郵件合并模板。
- 從數(shù)據(jù)庫(kù)加載數(shù)據(jù)。
- 將數(shù)據(jù)合并到模板中并保存。
每個(gè)步驟都包含幾個(gè)子步驟,在#2 和#3 中我們需要編寫(xiě)一些代碼。
創(chuàng)建郵件合并模板
模板是可重用的文檔。它呈現(xiàn)了我們報(bào)告的模式。我們可以修改它來(lái)更改我們的報(bào)告,而無(wú)需修改任何代碼。
注意:在本節(jié)中,所有表均指 DataTable 實(shí)例,而不是數(shù)據(jù)庫(kù)中的物理表。
我們可以在 MS Word 或其他程序中創(chuàng)建模板。請(qǐng)看下圖。這是我們需要?jiǎng)?chuàng)建的模板。數(shù)據(jù)將填寫(xiě)在紅方。
將郵件合并字段作為占位符插入紅塊。本例中將使用三種類型的郵件合并字段:
GeneralField 是一個(gè)通用的 Word 郵件合并字段。這是真實(shí)的數(shù)據(jù)字段,我們的數(shù)據(jù)將在合并過(guò)程中填寫(xiě)。我們需要在每個(gè)紅塊中插入一個(gè) GeneralField 并用相應(yīng)的數(shù)據(jù)名稱命名這些字段。插入 GeneralFields 后,我們的模板將如下所示:
TableField 是輔助郵件合并字段,用作多個(gè)相關(guān) GeneralField 和其他 TableField 的容器。所以它不是數(shù)據(jù)占位符,不會(huì)填充任何數(shù)據(jù)。它由兩個(gè)特殊的郵件合并字段組成:
TableStart: TableName和 TableEnd: TableName。在合并過(guò)程中,同一個(gè) TableField 所包含的相關(guān) GeneralField 的數(shù)據(jù)將來(lái)自同一個(gè)數(shù)據(jù)表。例如,客戶信息塊中的字段將填充數(shù)據(jù)表Customer中的數(shù)據(jù),因此我們需要將它們放入 TableField Customer中。
在第一個(gè)CompanyName字段之前插入一個(gè)字段名稱為 TableStart:Customer的郵件合并字段,并在字段 Country 之后立即插入另一個(gè)字段名稱為T(mén)ableEnd:Customer的郵件合并字段。然后我們?cè)诳蛻粜畔K中的字段如下所示:
在合并過(guò)程中,表Customer的CompanyName列中的數(shù)據(jù)將填充到字段CompanyName中,將Customer.Address填充到字段Address中,將Customer.City填充到字段City中等等。
訂單信息表中銷(xiāo)售人員列字段數(shù)據(jù)來(lái)自員工表
訂單信息表中Ship Via欄的字段數(shù)據(jù)來(lái)自Shipper表
訂單明細(xì)表中的字段數(shù)據(jù)來(lái)自表Detail,除了字段ProductName。字段ProductName的數(shù)據(jù)來(lái)自表Product。Invoice總計(jì)信息中InvoiceSubtotal和InvoiceTotal字段的數(shù)據(jù)來(lái)自表Total(虛擬表)
GroupField 也是輔助郵件合并字段。它可以包含多個(gè)相關(guān)的 GeneralFields 和 TableFields。它由兩個(gè)特殊的郵件合并字段組成: GroupStart: GroupName和 GroupEnd: GroupName。在合并過(guò)程中,將復(fù)制 GroupField 中包含的所有 Word 文檔元素。數(shù)據(jù)表中的一行有一個(gè)副本,該行中的數(shù)據(jù)將填充到副本中的字段中。
如果該行有子數(shù)據(jù)表,則子數(shù)據(jù)表中的數(shù)據(jù)將填充到相應(yīng)的TableField中包含的字段中。如果子數(shù)據(jù)表有多個(gè)數(shù)據(jù)行,對(duì)應(yīng)的TableField也會(huì)被復(fù)制填充。
我們需要在模板正文的頂部插入一個(gè)名為 GroupStart:Order 的郵件合并字段,并在模板正文的底部插入一個(gè)名為GroupEnd:Order的郵件合并字段。在此之后,我們的模板如下所示:
您可以在隨附的源包中找到名為 InvoiceTemplate.doc 的完整模板。
從數(shù)據(jù)庫(kù)加載數(shù)據(jù)
Spire.Doc 提供來(lái)自 DataSet 的合并數(shù)據(jù)。因此,我們將使用 DataAdapter 將 NorthWind 數(shù)據(jù)庫(kù)中的數(shù)據(jù)表填充到 DataSet 中,并將其合并到我們的模板中。與DataSet 的DataRelation 不同,Spire.Doc 擁有表關(guān)系功能。所以我們不需要為 DataSet 對(duì)象創(chuàng)建 DataRelation 實(shí)例。下面的代碼僅顯示加載訂單數(shù)據(jù)。其他代碼請(qǐng)參見(jiàn)隨附的源包。
[C#]
String connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Northwind.mdb"; DataSet dataSet = new DataSet(); using(OleDbConnection conn = new OleDbConnection(connectionString)) { //load December 1997 orders String sql = " SELECT * " + " FROM Orders " + " WHERE ShippedDate Between #12/1/1997# And #12/31/1997# "; using (OleDbDataAdapter dataAdapter = new OleDbDataAdapter(sql, conn)) { dataAdapter.Fill(dataSet, "Order"); } }
將數(shù)據(jù)合并到模板中并保存
在本節(jié)中,我們需要編寫(xiě)一些代碼來(lái)調(diào)用 Spire.Doc 來(lái)合并我們的數(shù)據(jù)表和模板。
創(chuàng)建 Spire.Doc.Document 對(duì)象并加載模板。
[C#]
Document document = new Document(); document.LoadFromFile("InvoiceTemplate.doc", FileFormat.Doc);
建立數(shù)據(jù)表之間的關(guān)系。
[C#]
List<DictionaryEntry> list = new List<DictionaryEntry> { new DictionaryEntry("Order", String.Empty), new DictionaryEntry("Shipper", "ShipperID = %Order.ShipVia%"), new DictionaryEntry("Customer", "CustomerID = %Order.CustomerID%"), new DictionaryEntry("Employee", "EmployeeID = %Order.EmployeeID%"), new DictionaryEntry("Detail", "OrderID = %Order.OrderID%"), new DictionaryEntry("Product", "ProductID = %Detail.ProductID%"), new DictionaryEntry("Total", "OrderID = %Order.OrderID%") };
將數(shù)據(jù)集合并到模板中并將文檔保存到文件中。
[C#]
//clear empty value fields during merge process document.MailMerge.ClearFields = true; //clear empty paragraphs if it has only empty value fields. document.MailMerge.RemoveEmptyParagraphs = true; //merge document.MailMerge.ExecuteWidthNestedRegion(dataSet, list); //set word view type. document.ViewSetup.DocumentViewType = DocumentViewType.PrintLayout; document.SaveToFile("Invoice.doc");
為了在新頁(yè)面中開(kāi)始每張發(fā)票,我們?cè)诘谝欢沃安迦胍粋€(gè)分頁(yè)符,以便合并新的訂單行。為此,我們需要處理在字段合并之前觸發(fā)的事件 MergeField。
[C#]
//index of row of merged order data int mergedRowIndex = 0; document.MailMerge.MergeField += delegate(object sender, MergeFieldEventArgs e) { if (e.TableName == "Order") { if (e.RowIndex > mergedRowIndex) { mergedRowIndex = e.RowIndex; //insert page break symbol before the paragraph of current field InsertPageBreak(e.CurrentMergeField); } } };
方法 InsertPageBreak 的代碼
[C#]
private static void InsertPageBreak(IMergeField field) { //append a page break symbol Break pageBreak = field.OwnerParagraph.AppendBreak(BreakType.PageBreak); //move to the start of the paragraph field.OwnerParagraph.Items.Insert(0, pageBreak); }
歡迎下載|體驗(yàn)更多E-iceblue產(chǎn)品
如需獲取更多產(chǎn)品相關(guān)信息請(qǐng)咨詢慧都在線客服