找回密码
 立即注册
首页 业界区 安全 .NET驾驭Word之力:数据驱动文档 - 邮件合并与自定义数 ...

.NET驾驭Word之力:数据驱动文档 - 邮件合并与自定义数据填充完全指南

撇瞥 前天 12:00
你是否曾经需要为数百名员工生成个性化的工资条?你是否希望根据客户信息批量生成合同文档?你是否想要根据数据库中的数据自动生成各类报告?通过本文介绍的邮件合并和自定义数据填充技术,你将能够轻松实现这些功能,大大提高文档处理的效率和准确性。
在实际的企业应用场景中,基于.net平台的 Word 自动化处理技术可以实现:

  • 人力资源管理:批量生成工资条、入职通知书、绩效评估报告等
  • 销售与客户管理:批量生成客户合同、报价单、服务协议等
  • 财务管理:批量生成发票、对账单、财务报告等
  • 行政办公:批量生成各类通知、证书、证明文件等
  • 教育培训:批量生成成绩单、结业证书、培训记录等
  • 法律服务:批量生成法律文书、合同模板、案件报告等
本文将详细介绍如何使用MudTools.OfficeInterop.Word 库来实现传统的邮件合并功能和更灵活的自定义数据填充方案。如何从数据库(SQL Server)、Excel、JSON文件等数据源读取数据,并使用循环和上文技术(书签、查找替换、表格操作)将数据批量填充到Word文档的指定位置。最后,将通过一个实战示例,创建一个批量员工工资条生成系统,真正掌握Word数据交互的精髓。
使用传统的邮件合并功能

邮件合并是Word中最经典的数据交互功能之一,它允许我们将外部数据源(如Excel表格、Access数据库等)与Word文档模板结合,批量生成个性化的文档。
传统的邮件合并功能虽然强大,但在现代应用开发中,我们往往需要更灵活的控制方式。不过,了解邮件合并的基本原理仍然很有价值,因为它为我们理解数据驱动文档的核心概念提供了基础。
传统的邮件合并过程通常包括以下步骤:

  • 创建包含合并域的主文档(模板)
  • 准备数据源(如Excel文件或数据库)
  • 在Word中配置邮件合并向导
  • 预览并完成合并
虽然MudTools.OfficeInterop.Word库目前没有直接提供邮件合并功能,但我们可以通过自定义数据填充的方式实现更强大、更灵活的功能。
实际业务场景:传统邮件合并的局限性

在许多企业环境中,传统的邮件合并功能虽然能满足基本需求,但在面对复杂业务场景时往往显得力不从心。
场景一:多数据源整合
某大型制造企业需要为供应商生成年度评估报告。这些报告需要整合来自多个系统的数据:

  • ERP系统(供应商基本信息、交易记录)
  • 质量管理系统(质量检测数据)
  • 财务系统(付款记录、信用评级)
传统的邮件合并只能处理单一数据源,无法满足这种多源数据整合的需求。
场景二:动态格式要求
某金融机构需要为客户生成个性化的投资报告。不同类型的客户(个人客户、企业客户、VIP客户)需要不同的报告格式和内容结构。传统的邮件合并只能生成格式固定的文档,无法根据客户类型动态调整文档结构。
场景三:复杂的业务逻辑
某咨询公司需要为不同行业的客户生成市场分析报告。报告内容需要根据客户的行业特点、规模、地理位置等信息应用不同的分析模型和展示方式。传统的邮件合并缺乏处理复杂业务逻辑的能力。
通过自定义数据填充方案,我们可以突破这些限制,实现更智能、更灵活的文档生成系统。
更灵活的方案:自定义数据填充

自定义数据填充是一种比传统邮件合并更灵活、更可控的数据交互方案。通过这种方式,我们可以从各种数据源读取数据,并精确控制数据在文档中的填充位置和格式。
从数据库(SQL Server)、Excel、JSON文件等数据源读取数据

在实际应用中,数据可能来自各种不同的源,包括关系型数据库、Excel文件、JSON数据等。我们需要能够灵活地处理这些不同的数据源。
  1. using MudTools.OfficeInterop;
  2. using MudTools.OfficeInterop.Word;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Data;
  6. using System.Data.SqlClient;
  7. using System.IO;
  8. using Newtonsoft.Json;
  9. // 数据模型
  10. public class Employee
  11. {
  12.     public int Id { get; set; }
  13.     public string Name { get; set; }
  14.     public string Department { get; set; }
  15.     public decimal Salary { get; set; }
  16.     public decimal Bonus { get; set; }
  17.     public DateTime HireDate { get; set; }
  18. }
  19. // 数据访问服务
  20. public class DataService
  21. {
  22.     /// <summary>
  23.     /// 从SQL Server数据库读取员工数据
  24.     /// </summary>
  25.     /// <param name="connectionString">数据库连接字符串</param>
  26.     /// <returns>员工数据列表</returns>
  27.     public List<Employee> GetEmployeesFromDatabase(string connectionString)
  28.     {
  29.         var employees = new List<Employee>();
  30.         
  31.         try
  32.         {
  33.             using (var connection = new SqlConnection(connectionString))
  34.             {
  35.                 connection.Open();
  36.                 var command = new SqlCommand("SELECT Id, Name, Department, Salary, Bonus, HireDate FROM Employees", connection);
  37.                 using (var reader = command.ExecuteReader())
  38.                 {
  39.                     while (reader.Read())
  40.                     {
  41.                         employees.Add(new Employee
  42.                         {
  43.                             Id = reader.GetInt32("Id"),
  44.                             Name = reader.GetString("Name"),
  45.                             Department = reader.GetString("Department"),
  46.                             Salary = reader.GetDecimal("Salary"),
  47.                             Bonus = reader.GetDecimal("Bonus"),
  48.                             HireDate = reader.GetDateTime("HireDate")
  49.                         });
  50.                     }
  51.                 }
  52.             }
  53.         }
  54.         catch (Exception ex)
  55.         {
  56.             Console.WriteLine($"从数据库读取员工数据时发生错误: {ex.Message}");
  57.         }
  58.         
  59.         return employees;
  60.     }
  61.    
  62.     /// <summary>
  63.     /// 从Excel文件读取员工数据
  64.     /// </summary>
  65.     /// <param name="excelFilePath">Excel文件路径</param>
  66.     /// <returns>员工数据列表</returns>
  67.     public List<Employee> GetEmployeesFromExcel(string excelFilePath)
  68.     {
  69.         var employees = new List<Employee>();
  70.         
  71.         try
  72.         {
  73.             // 这里应该使用适当的Excel读取库,如EPPlus或NPOI
  74.             // 为简化示例,我们直接返回模拟数据
  75.             employees.Add(new Employee
  76.             {
  77.                 Id = 1,
  78.                 Name = "张三",
  79.                 Department = "技术部",
  80.                 Salary = 15000,
  81.                 Bonus = 3000,
  82.                 HireDate = new DateTime(2020, 1, 15)
  83.             });
  84.             
  85.             employees.Add(new Employee
  86.             {
  87.                 Id = 2,
  88.                 Name = "李四",
  89.                 Department = "销售部",
  90.                 Salary = 12000,
  91.                 Bonus = 5000,
  92.                 HireDate = new DateTime(2019, 3, 22)
  93.             });
  94.         }
  95.         catch (Exception ex)
  96.         {
  97.             Console.WriteLine($"从Excel文件读取员工数据时发生错误: {ex.Message}");
  98.         }
  99.         
  100.         return employees;
  101.     }
  102.    
  103.     /// <summary>
  104.     /// 从JSON文件读取员工数据
  105.     /// </summary>
  106.     /// <param name="jsonFilePath">JSON文件路径</param>
  107.     /// <returns>员工数据列表</returns>
  108.     public List<Employee> GetEmployeesFromJson(string jsonFilePath)
  109.     {
  110.         var employees = new List<Employee>();
  111.         
  112.         try
  113.         {
  114.             if (File.Exists(jsonFilePath))
  115.             {
  116.                 var jsonContent = File.ReadAllText(jsonFilePath);
  117.                 employees = JsonConvert.DeserializeObject<List<Employee>>(jsonContent);
  118.             }
  119.         }
  120.         catch (Exception ex)
  121.         {
  122.             Console.WriteLine($"从JSON文件读取员工数据时发生错误: {ex.Message}");
  123.         }
  124.         
  125.         return employees;
  126.     }
  127. }
复制代码
应用场景:多数据源集成处理与复杂业务逻辑实现

在现代企业运营中,数据孤岛现象普遍存在,关键信息分散在HR系统、财务系统、CRM系统、ERP系统等多个独立平台中。传统的邮件合并功能只能处理单一数据源,而自定义数据填充方案则能够打破这些壁垒,实现跨系统的数据整合与智能处理。
  1. using MudTools.OfficeInterop;
  2. using MudTools.OfficeInterop.Word;
  3. using System;
  4. using System.Collections.Generic;
  5. // 综合数据服务
  6. public class ComprehensiveDataService
  7. {
  8.     private readonly DataService _dataService;
  9.    
  10.     public ComprehensiveDataService()
  11.     {
  12.         _dataService = new DataService();
  13.     }
  14.    
  15.     /// <summary>
  16.     /// 获取综合员工数据
  17.     /// </summary>
  18.     /// <returns>综合员工数据列表</returns>
  19.     public List<ComprehensiveEmployeeData> GetComprehensiveEmployeeData()
  20.     {
  21.         var comprehensiveDataList = new List<ComprehensiveEmployeeData>();
  22.         
  23.         try
  24.         {
  25.             // 从不同数据源获取数据
  26.             var hrEmployees = _dataService.GetEmployeesFromDatabase("HR数据库连接字符串");
  27.             // var financeData = _dataService.GetEmployeesFromExcel("财务数据Excel路径");
  28.             // var projectData = _dataService.GetEmployeesFromJson("项目数据JSON路径");
  29.             
  30.             // 整合数据
  31.             foreach (var employee in hrEmployees)
  32.             {
  33.                 var comprehensiveData = new ComprehensiveEmployeeData
  34.                 {
  35.                     Id = employee.Id,
  36.                     Name = employee.Name,
  37.                     Department = employee.Department,
  38.                     Salary = employee.Salary,
  39.                     Bonus = employee.Bonus,
  40.                     HireDate = employee.HireDate,
  41.                     // 这里可以添加从其他数据源获取的信息
  42.                     PerformanceRating = CalculatePerformanceRating(employee),
  43.                     ProjectsCompleted = GetProjectsCompleted(employee.Id)
  44.                 };
  45.                
  46.                 comprehensiveDataList.Add(comprehensiveData);
  47.             }
  48.         }
  49.         catch (Exception ex)
  50.         {
  51.             Console.WriteLine($"获取综合员工数据时发生错误: {ex.Message}");
  52.         }
  53.         
  54.         return comprehensiveDataList;
  55.     }
  56.    
  57.     /// <summary>
  58.     /// 计算绩效评级
  59.     /// </summary>
  60.     /// <param name="employee">员工信息</param>
  61.     /// <returns>绩效评级</returns>
  62.     private string CalculatePerformanceRating(Employee employee)
  63.     {
  64.         // 简化的绩效评级计算逻辑
  65.         if (employee.Salary > 15000)
  66.             return "优秀";
  67.         else if (employee.Salary > 10000)
  68.             return "良好";
  69.         else
  70.             return "合格";
  71.     }
  72.    
  73.     /// <summary>
  74.     /// 获取完成的项目数量
  75.     /// </summary>
  76.     /// <param name="employeeId">员工ID</param>
  77.     /// <returns>完成的项目数量</returns>
  78.     private int GetProjectsCompleted(int employeeId)
  79.     {
  80.         // 模拟数据
  81.         return employeeId switch
  82.         {
  83.             1 => 5,
  84.             2 => 3,
  85.             _ => 0
  86.         };
  87.     }
  88. }
  89. /// <summary>
  90. /// 综合员工数据模型
  91. /// </summary>
  92. public class ComprehensiveEmployeeData
  93. {
  94.     public int Id { get; set; }
  95.     public string Name { get; set; }
  96.     public string Department { get; set; }
  97.     public decimal Salary { get; set; }
  98.     public decimal Bonus { get; set; }
  99.     public DateTime HireDate { get; set; }
  100.     public string PerformanceRating { get; set; }
  101.     public int ProjectsCompleted { get; set; }
  102.    
  103.     /// <summary>
  104.     /// 获取总收入(薪资+奖金)
  105.     /// </summary>
  106.     public decimal TotalIncome => Salary + Bonus;
  107.    
  108.     /// <summary>
  109.     /// 获取工作年限
  110.     /// </summary>
  111.     public int YearsOfService => DateTime.Now.Year - HireDate.Year;
  112. }
复制代码
使用循环和上文技术(书签、查找替换、表格操作)将数据批量填充到Word文档的指定位置

有了数据源之后,我们需要将数据填充到Word文档中。通过结合循环和之前学习的技术(书签、查找替换、表格操作),我们可以实现灵活的数据填充。
  1. using MudTools.OfficeInterop;
  2. using MudTools.OfficeInterop.Word;
  3. using System;
  4. using System.Collections.Generic;
  5. // 文档生成服务
  6. public class DocumentGenerationService
  7. {
  8.     /// <summary>
  9.     /// 生成员工工资条
  10.     /// </summary>
  11.     /// <param name="templatePath">模板路径</param>
  12.     /// <param name="outputDirectory">输出目录</param>
  13.     /// <param name="employees">员工数据列表</param>
  14.     public void GeneratePaySlips(string templatePath, string outputDirectory, List<Employee> employees)
  15.     {
  16.         foreach (var employee in employees)
  17.         {
  18.             try
  19.             {
  20.                 // 基于模板创建新文档
  21.                 using var wordApp = WordFactory.CreateFrom(templatePath);
  22.                 var document = wordApp.ActiveDocument;
  23.                
  24.                 // 隐藏Word应用程序以提高性能
  25.                 wordApp.Visibility = WordAppVisibility.Hidden;
  26.                 wordApp.DisplayAlerts = WdAlertLevel.wdAlertsNone;
  27.                
  28.                 // 使用书签填充数据
  29.                 FillDataUsingBookmarks(document, employee);
  30.                
  31.                 // 生成文件名
  32.                 string fileName = $"工资条_{employee.Name}_{DateTime.Now:yyyyMM}.docx";
  33.                 string outputPath = Path.Combine(outputDirectory, fileName);
  34.                
  35.                 // 保存文档
  36.                 document.SaveAs(outputPath, WdSaveFormat.wdFormatXMLDocument);
  37.                 document.Close();
  38.                
  39.                 Console.WriteLine($"已生成工资条: {fileName}");
  40.             }
  41.             catch (Exception ex)
  42.             {
  43.                 Console.WriteLine($"为员工 {employee.Name} 生成工资条时发生错误: {ex.Message}");
  44.             }
  45.         }
  46.     }
  47.    
  48.     /// <summary>
  49.     /// 使用书签填充数据
  50.     /// </summary>
  51.     /// <param name="document">Word文档</param>
  52.     /// <param name="employee">员工数据</param>
  53.     private void FillDataUsingBookmarks(IWordDocument document, Employee employee)
  54.     {
  55.         // 填充基本信息
  56.         SetBookmarkText(document, "EmployeeName", employee.Name);
  57.         SetBookmarkText(document, "EmployeeId", employee.Id.ToString());
  58.         SetBookmarkText(document, "Department", employee.Department);
  59.         SetBookmarkText(document, "PayPeriod", DateTime.Now.ToString("yyyy年MM月"));
  60.         
  61.         // 填充薪资信息
  62.         SetBookmarkText(document, "BaseSalary", employee.Salary.ToString("C"));
  63.         SetBookmarkText(document, "Bonus", employee.Bonus.ToString("C"));
  64.         SetBookmarkText(document, "TotalIncome", (employee.Salary + employee.Bonus).ToString("C"));
  65.         SetBookmarkText(document, "Deductions", "0.00");
  66.         SetBookmarkText(document, "NetPay", (employee.Salary + employee.Bonus).ToString("C"));
  67.         
  68.         // 填充日期信息
  69.         SetBookmarkText(document, "PayDate", DateTime.Now.ToString("yyyy年MM月dd日"));
  70.         SetBookmarkText(document, "HireDate", employee.HireDate.ToString("yyyy年MM月dd日"));
  71.     }
  72.    
  73.     /// <summary>
  74.     /// 设置书签文本
  75.     /// </summary>
  76.     /// <param name="document">Word文档</param>
  77.     /// <param name="bookmarkName">书签名称</param>
  78.     /// <param name="text">文本内容</param>
  79.     private void SetBookmarkText(IWordDocument document, string bookmarkName, string text)
  80.     {
  81.         try
  82.         {
  83.             var bookmark = document.Bookmarks[bookmarkName];
  84.             if (bookmark != null)
  85.             {
  86.                 bookmark.Range.Text = text;
  87.             }
  88.         }
  89.         catch (Exception ex)
  90.         {
  91.             Console.WriteLine($"设置书签 {bookmarkName} 文本时发生错误: {ex.Message}");
  92.         }
  93.     }
  94.    
  95.     /// <summary>
  96.     /// 使用查找替换填充数据
  97.     /// </summary>
  98.     /// <param name="document">Word文档</param>
  99.     /// <param name="employee">员工数据</param>
  100.     private void FillDataUsingFindReplace(IWordDocument document, Employee employee)
  101.     {
  102.         // 使用查找替换填充数据
  103.         document.FindAndReplace("[员工姓名]", employee.Name);
  104.         document.FindAndReplace("[员工编号]", employee.Id.ToString());
  105.         document.FindAndReplace("[部门]", employee.Department);
  106.         document.FindAndReplace("[薪资月份]", DateTime.Now.ToString("yyyy年MM月"));
  107.         document.FindAndReplace("[基本工资]", employee.Salary.ToString("C"));
  108.         document.FindAndReplace("[奖金]", employee.Bonus.ToString("C"));
  109.         document.FindAndReplace("[总收入]", (employee.Salary + employee.Bonus).ToString("C"));
  110.         document.FindAndReplace("[扣除项]", "0.00");
  111.         document.FindAndReplace("[实发工资]", (employee.Salary + employee.Bonus).ToString("C"));
  112.         document.FindAndReplace("[发放日期]", DateTime.Now.ToString("yyyy年MM月dd日"));
  113.         document.FindAndReplace("[入职日期]", employee.HireDate.ToString("yyyy年MM月dd日"));
  114.     }
  115. }
复制代码
应用场景:复杂企业级批量文档生成系统

在现代企业运营中,文档自动化处理已成为提升效率、确保合规性和改善客户体验的关键环节。通过结合循环和上文技术(书签、查找替换、表格操作),我们能够构建一个功能强大、灵活可扩展的企业级批量文档生成系统,满足各种复杂的业务需求。
特别值得一提的是,还可以集成SemanticKernel、ML.Net实现以下AI能力:

  • 使用自然语言处理技术,自动生成个性化的绩效评语和职业发展建议
  • 通过机器学习分析历史数据,预测可能的薪酬纠纷并提前预警
  • 利用光学字符识别(OCR)技术,自动解析纸质文档并将其纳入数字工作流
  1. // 批量文档生成系统
  2. public class BatchDocumentGenerationSystem
  3. {
  4.     private readonly DataService _dataService;
  5.     private readonly DocumentGenerationService _documentService;
  6.    
  7.     public BatchDocumentGenerationSystem()
  8.     {
  9.         _dataService = new DataService();
  10.         _documentService = new DocumentGenerationService();
  11.     }
  12.    
  13.     /// <summary>
  14.     /// 批量生成员工工资条
  15.     /// </summary>
  16.     /// <param name="templatePath">模板路径</param>
  17.     /// <param name="outputDirectory">输出目录</param>
  18.     /// <param name="dataSourceType">数据源类型</param>
  19.     /// <param name="dataSourcePath">数据源路径</param>
  20.     public void BatchGeneratePaySlips(string templatePath, string outputDirectory,
  21.         DataSourceType dataSourceType, string dataSourcePath)
  22.     {
  23.         try
  24.         {
  25.             // 确保输出目录存在
  26.             if (!Directory.Exists(outputDirectory))
  27.             {
  28.                 Directory.CreateDirectory(outputDirectory);
  29.             }
  30.             
  31.             // 根据数据源类型获取员工数据
  32.             List<Employee> employees = dataSourceType switch
  33.             {
  34.                 DataSourceType.Database => _dataService.GetEmployeesFromDatabase(dataSourcePath),
  35.                 DataSourceType.Excel => _dataService.GetEmployeesFromExcel(dataSourcePath),
  36.                 DataSourceType.Json => _dataService.GetEmployeesFromJson(dataSourcePath),
  37.                 _ => throw new ArgumentException("不支持的数据源类型")
  38.             };
  39.             
  40.             Console.WriteLine($"从{dataSourceType}数据源获取到 {employees.Count} 名员工的数据");
  41.             
  42.             // 生成工资条
  43.             _documentService.GeneratePaySlips(templatePath, outputDirectory, employees);
  44.             
  45.             Console.WriteLine($"批量工资条生成完成,共生成 {employees.Count} 份工资条");
  46.         }
  47.         catch (Exception ex)
  48.         {
  49.             Console.WriteLine($"批量生成工资条时发生错误: {ex.Message}");
  50.         }
  51.     }
  52.    
  53.     /// <summary>
  54.     /// 批量生成客户合同
  55.     /// </summary>
  56.     /// <param name="templatePath">模板路径</param>
  57.     /// <param name="outputDirectory">输出目录</param>
  58.     /// <param name="customers">客户数据列表</param>
  59.     public void BatchGenerateContracts(string templatePath, string outputDirectory, List<Customer> customers)
  60.     {
  61.         try
  62.         {
  63.             // 确保输出目录存在
  64.             if (!Directory.Exists(outputDirectory))
  65.             {
  66.                 Directory.CreateDirectory(outputDirectory);
  67.             }
  68.             
  69.             foreach (var customer in customers)
  70.             {
  71.                 try
  72.                 {
  73.                     // 基于模板创建新文档
  74.                     using var wordApp = WordFactory.CreateFrom(templatePath);
  75.                     var document = wordApp.ActiveDocument;
  76.                     
  77.                     // 隐藏Word应用程序以提高性能
  78.                     wordApp.Visibility = WordAppVisibility.Hidden;
  79.                     wordApp.DisplayAlerts = WdAlertLevel.wdAlertsNone;
  80.                     
  81.                     // 填充客户数据
  82.                     FillCustomerContractData(document, customer);
  83.                     
  84.                     // 生成文件名
  85.                     string fileName = $"合同_{customer.Name}_{DateTime.Now:yyyyMMdd}.docx";
  86.                     string outputPath = Path.Combine(outputDirectory, fileName);
  87.                     
  88.                     // 保存文档
  89.                     document.SaveAs(outputPath, WdSaveFormat.wdFormatXMLDocument);
  90.                     document.Close();
  91.                     
  92.                     Console.WriteLine($"已生成合同: {fileName}");
  93.                 }
  94.                 catch (Exception ex)
  95.                 {
  96.                     Console.WriteLine($"为客户 {customer.Name} 生成合同时发生错误: {ex.Message}");
  97.                 }
  98.             }
  99.             
  100.             Console.WriteLine($"批量合同生成完成,共生成 {customers.Count} 份合同");
  101.         }
  102.         catch (Exception ex)
  103.         {
  104.             Console.WriteLine($"批量生成合同时发生错误: {ex.Message}");
  105.         }
  106.     }
  107.    
  108.     /// <summary>
  109.     /// 填充客户合同数据
  110.     /// </summary>
  111.     /// <param name="document">Word文档</param>
  112.     /// <param name="customer">客户数据</param>
  113.     private void FillCustomerContractData(IWordDocument document, Customer customer)
  114.     {
  115.         // 使用书签填充数据
  116.         SetBookmarkText(document, "CustomerName", customer.Name);
  117.         SetBookmarkText(document, "CustomerAddress", customer.Address);
  118.         SetBookmarkText(document, "CustomerPhone", customer.Phone);
  119.         SetBookmarkText(document, "ContractDate", DateTime.Now.ToString("yyyy年MM月dd日"));
  120.         SetBookmarkText(document, "ContractAmount", customer.ContractAmount.ToString("C"));
  121.         SetBookmarkText(document, "ServiceDescription", customer.ServiceDescription);
  122.         SetBookmarkText(document, "ContractTerm", customer.ContractTerm);
  123.     }
  124.    
  125.     /// <summary>
  126.     /// 设置书签文本
  127.     /// </summary>
  128.     /// <param name="document">Word文档</param>
  129.     /// <param name="bookmarkName">书签名称</param>
  130.     /// <param name="text">文本内容</param>
  131.     private void SetBookmarkText(IWordDocument document, string bookmarkName, string text)
  132.     {
  133.         try
  134.         {
  135.             var bookmark = document.Bookmarks[bookmarkName];
  136.             if (bookmark != null)
  137.             {
  138.                 bookmark.Range.Text = text;
  139.             }
  140.         }
  141.         catch (Exception ex)
  142.         {
  143.             Console.WriteLine($"设置书签 {bookmarkName} 文本时发生错误: {ex.Message}");
  144.         }
  145.     }
  146. }
  147. /// <summary>
  148. /// 数据源类型枚举
  149. /// </summary>
  150. public enum DataSourceType
  151. {
  152.     Database,
  153.     Excel,
  154.     Json
  155. }
  156. /// <summary>
  157. /// 客户数据模型
  158. /// </summary>
  159. public class Customer
  160. {
  161.     public int Id { get; set; }
  162.     public string Name { get; set; }
  163.     public string Address { get; set; }
  164.     public string Phone { get; set; }
  165.     public decimal ContractAmount { get; set; }
  166.     public string ServiceDescription { get; set; }
  167.     public string ContractTerm { get; set; }
  168. }
复制代码
实战:生成批量员工工资条或客户合同

创建一个完整的批量文档生成系统,展示如何实现数据驱动的文档处理。
创建工资条模板

创建一个工资条模板,其中包含用于数据填充的书签。
  1. // 工资条模板创建器
  2. public class PaySlipTemplateCreator
  3. {
  4.     /// <summary>
  5.     /// 创建工资条模板
  6.     /// </summary>
  7.     /// <param name="templatePath">模板保存路径</param>
  8.     public void CreatePaySlipTemplate(string templatePath)
  9.     {
  10.         try
  11.         {
  12.             // 创建新文档
  13.             using var wordApp = WordFactory.BlankWorkbook();
  14.             var document = wordApp.ActiveDocument;
  15.             
  16.             // 隐藏Word应用程序以提高性能
  17.             wordApp.Visibility = WordAppVisibility.Hidden;
  18.             wordApp.DisplayAlerts = WdAlertLevel.wdAlertsNone;
  19.             
  20.             // 设置文档格式
  21.             SetupDocumentFormat(document);
  22.             
  23.             // 添加模板内容
  24.             AddTemplateContent(document);
  25.             
  26.             // 添加书签
  27.             AddBookmarks(document);
  28.             
  29.             // 保存为模板
  30.             document.SaveAs(templatePath, WdSaveFormat.wdFormatXMLTemplate);
  31.             document.Close();
  32.             
  33.             Console.WriteLine($"工资条模板已创建: {templatePath}");
  34.         }
  35.         catch (Exception ex)
  36.         {
  37.             Console.WriteLine($"创建工资条模板时发生错误: {ex.Message}");
  38.         }
  39.     }
  40.    
  41.     /// <summary>
  42.     /// 设置文档格式
  43.     /// </summary>
  44.     /// <param name="document">Word文档</param>
  45.     private void SetupDocumentFormat(IWordDocument document)
  46.     {
  47.         // 设置页面格式
  48.         foreach (IWordSection section in document.Sections)
  49.         {
  50.             var pageSetup = section.PageSetup;
  51.             pageSetup.PaperSize = WdPaperSize.wdPaperA4;
  52.             pageSetup.Orientation = WdOrientation.wdOrientPortrait;
  53.             pageSetup.TopMargin = 36;  // 0.5英寸
  54.             pageSetup.BottomMargin = 36;
  55.             pageSetup.LeftMargin = 36;
  56.             pageSetup.RightMargin = 36;
  57.         }
  58.     }
  59.    
  60.     /// <summary>
  61.     /// 添加模板内容
  62.     /// </summary>
  63.     /// <param name="document">Word文档</param>
  64.     private void AddTemplateContent(IWordDocument document)
  65.     {
  66.         var content = document.Content;
  67.         
  68.         // 添加标题
  69.         content.Text = "员工工资条\n\n";
  70.         content.Font.Name = "微软雅黑";
  71.         content.Font.Size = 16;
  72.         content.Font.Bold = true;
  73.         content.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphCenter;
  74.         
  75.         // 添加基本信息表格
  76.         var infoRange = content.Duplicate;
  77.         infoRange.Collapse(WdCollapseDirection.wdCollapseEnd);
  78.         infoRange.Text = "基本信息\n";
  79.         infoRange.Font.Size = 12;
  80.         infoRange.Font.Bold = true;
  81.         infoRange.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphLeft;
  82.         
  83.         // 创建基本信息表格(3行4列)
  84.         var infoTable = document.Tables.Add(infoRange, 3, 4);
  85.         infoTable.Borders.Enable = 1;
  86.         infoTable.AllowAutoFit = true;
  87.         
  88.         // 设置表头
  89.         infoTable.Cell(1, 1).Range.Text = "员工姓名";
  90.         infoTable.Cell(1, 2).Range.Text = "[员工姓名]";
  91.         infoTable.Cell(1, 3).Range.Text = "员工编号";
  92.         infoTable.Cell(1, 4).Range.Text = "[员工编号]";
  93.         
  94.         infoTable.Cell(2, 1).Range.Text = "部门";
  95.         infoTable.Cell(2, 2).Range.Text = "[部门]";
  96.         infoTable.Cell(2, 3).Range.Text = "薪资月份";
  97.         infoTable.Cell(2, 4).Range.Text = "[薪资月份]";
  98.         
  99.         infoTable.Cell(3, 1).Range.Text = "入职日期";
  100.         infoTable.Cell(3, 2).Range.Text = "[入职日期]";
  101.         infoTable.Cell(3, 3).Range.Text = "发放日期";
  102.         infoTable.Cell(3, 4).Range.Text = "[发放日期]";
  103.         
  104.         // 添加薪资明细
  105.         var salaryRange = infoRange.Duplicate;
  106.         salaryRange.Collapse(WdCollapseDirection.wdCollapseEnd);
  107.         salaryRange.Text = "\n薪资明细\n";
  108.         salaryRange.Font.Size = 12;
  109.         salaryRange.Font.Bold = true;
  110.         salaryRange.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphLeft;
  111.         
  112.         // 创建薪资明细表格(4行2列)
  113.         var salaryTable = document.Tables.Add(salaryRange, 4, 2);
  114.         salaryTable.Borders.Enable = 1;
  115.         salaryTable.AllowAutoFit = true;
  116.         
  117.         // 设置表头
  118.         salaryTable.Cell(1, 1).Range.Text = "项目";
  119.         salaryTable.Cell(1, 2).Range.Text = "金额";
  120.         
  121.         salaryTable.Cell(2, 1).Range.Text = "基本工资";
  122.         salaryTable.Cell(2, 2).Range.Text = "[基本工资]";
  123.         
  124.         salaryTable.Cell(3, 1).Range.Text = "奖金";
  125.         salaryTable.Cell(3, 2).Range.Text = "[奖金]";
  126.         
  127.         salaryTable.Cell(4, 1).Range.Text = "总收入";
  128.         salaryTable.Cell(4, 2).Range.Text = "[总收入]";
  129.         
  130.         // 添加扣除项和实发工资
  131.         var deductionRange = salaryRange.Duplicate;
  132.         deductionRange.Collapse(WdCollapseDirection.wdCollapseEnd);
  133.         deductionRange.Text = "\n";
  134.         
  135.         // 创建扣除项表格(3行2列)
  136.         var deductionTable = document.Tables.Add(deductionRange, 3, 2);
  137.         deductionTable.Borders.Enable = 1;
  138.         deductionTable.AllowAutoFit = true;
  139.         
  140.         deductionTable.Cell(1, 1).Range.Text = "扣除项";
  141.         deductionTable.Cell(1, 2).Range.Text = "[扣除项]";
  142.         
  143.         deductionTable.Cell(2, 1).Range.Text = "实发工资";
  144.         deductionTable.Cell(2, 2).Range.Text = "[实发工资]";
  145.         
  146.         deductionTable.Cell(3, 1).Range.Text = "大写金额";
  147.         deductionTable.Cell(3, 2).Range.Text = "人民币[大写实发工资]";
  148.     }
  149.    
  150.     /// <summary>
  151.     /// 添加书签
  152.     /// </summary>
  153.     /// <param name="document">Word文档</param>
  154.     private void AddBookmarks(IWordDocument document)
  155.     {
  156.         // 定义书签映射
  157.         var bookmarkMappings = new Dictionary<string, string>
  158.         {
  159.             { "EmployeeName", "[员工姓名]" },
  160.             { "EmployeeId", "[员工编号]" },
  161.             { "Department", "[部门]" },
  162.             { "PayPeriod", "[薪资月份]" },
  163.             { "HireDate", "[入职日期]" },
  164.             { "PayDate", "[发放日期]" },
  165.             { "BaseSalary", "[基本工资]" },
  166.             { "Bonus", "[奖金]" },
  167.             { "TotalIncome", "[总收入]" },
  168.             { "Deductions", "[扣除项]" },
  169.             { "NetPay", "[实发工资]" }
  170.         };
  171.         
  172.         // 为每个占位符添加书签
  173.         foreach (var mapping in bookmarkMappings)
  174.         {
  175.             AddBookmarkToPlaceholder(document, mapping.Key, mapping.Value);
  176.         }
  177.     }
  178.    
  179.     /// <summary>
  180.     /// 为占位符添加书签
  181.     /// </summary>
  182.     /// <param name="document">Word文档</param>
  183.     /// <param name="bookmarkName">书签名称</param>
  184.     /// <param name="placeholder">占位符文本</param>
  185.     private void AddBookmarkToPlaceholder(IWordDocument document, string bookmarkName, string placeholder)
  186.     {
  187.         try
  188.         {
  189.             var range = document.Content.Duplicate;
  190.             if (range.FindAndReplace(placeholder, "") > 0)
  191.             {
  192.                 document.Bookmarks.Add(bookmarkName, range);
  193.             }
  194.         }
  195.         catch (Exception ex)
  196.         {
  197.             Console.WriteLine($"为占位符 {placeholder} 添加书签时发生错误: {ex.Message}");
  198.         }
  199.     }
  200. }
复制代码
完整的工资条生成系统

创建一个完整的工资条生成系统,整合数据读取、模板创建和文档生成功能。
  1. using MudTools.OfficeInterop;
  2. using MudTools.OfficeInterop.Word;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. // 完整的工资条生成系统
  7. public class CompletePaySlipGenerationSystem
  8. {
  9.     private readonly DataService _dataService;
  10.     private readonly PaySlipTemplateCreator _templateCreator;
  11.     private readonly DocumentGenerationService _documentService;
  12.    
  13.     public CompletePaySlipGenerationSystem()
  14.     {
  15.         _dataService = new DataService();
  16.         _templateCreator = new PaySlipTemplateCreator();
  17.         _documentService = new DocumentGenerationService();
  18.     }
  19.    
  20.     /// <summary>
  21.     /// 运行完整的工资条生成流程
  22.     /// </summary>
  23.     /// <param name="dataSourceType">数据源类型</param>
  24.     /// <param name="dataSourcePath">数据源路径</param>
  25.     /// <param name="outputDirectory">输出目录</param>
  26.     public void RunPaySlipGenerationProcess(DataSourceType dataSourceType, string dataSourcePath, string outputDirectory)
  27.     {
  28.         try
  29.         {
  30.             Console.WriteLine("开始工资条生成流程...");
  31.             
  32.             // 1. 创建模板(如果不存在)
  33.             string templatePath = Path.Combine(outputDirectory, "工资条模板.dotx");
  34.             if (!File.Exists(templatePath))
  35.             {
  36.                 _templateCreator.CreatePaySlipTemplate(templatePath);
  37.             }
  38.             
  39.             // 2. 从数据源获取员工数据
  40.             List<Employee> employees = GetEmployeeData(dataSourceType, dataSourcePath);
  41.             if (employees == null || employees.Count == 0)
  42.             {
  43.                 Console.WriteLine("未获取到员工数据,流程终止");
  44.                 return;
  45.             }
  46.             
  47.             Console.WriteLine($"成功获取 {employees.Count} 名员工的数据");
  48.             
  49.             // 3. 生成工资条
  50.             _documentService.GeneratePaySlips(templatePath, outputDirectory, employees);
  51.             
  52.             Console.WriteLine($"工资条生成流程完成,共生成 {employees.Count} 份工资条");
  53.         }
  54.         catch (Exception ex)
  55.         {
  56.             Console.WriteLine($"运行工资条生成流程时发生错误: {ex.Message}");
  57.         }
  58.     }
  59.    
  60.     /// <summary>
  61.     /// 获取员工数据
  62.     /// </summary>
  63.     /// <param name="dataSourceType">数据源类型</param>
  64.     /// <param name="dataSourcePath">数据源路径</param>
  65.     /// <returns>员工数据列表</returns>
  66.     private List<Employee> GetEmployeeData(DataSourceType dataSourceType, string dataSourcePath)
  67.     {
  68.         try
  69.         {
  70.             return dataSourceType switch
  71.             {
  72.                 DataSourceType.Database => _dataService.GetEmployeesFromDatabase(dataSourcePath),
  73.                 DataSourceType.Excel => _dataService.GetEmployeesFromExcel(dataSourcePath),
  74.                 DataSourceType.Json => _dataService.GetEmployeesFromJson(dataSourcePath),
  75.                 _ => throw new ArgumentException("不支持的数据源类型")
  76.             };
  77.         }
  78.         catch (Exception ex)
  79.         {
  80.             Console.WriteLine($"获取员工数据时发生错误: {ex.Message}");
  81.             return new List<Employee>();
  82.         }
  83.     }
  84.    
  85.     /// <summary>
  86.     /// 创建示例数据文件
  87.     /// </summary>
  88.     /// <param name="outputDirectory">输出目录</param>
  89.     public void CreateSampleDataFiles(string outputDirectory)
  90.     {
  91.         try
  92.         {
  93.             // 创建示例JSON数据文件
  94.             var sampleEmployees = new List<Employee>
  95.             {
  96.                 new Employee
  97.                 {
  98.                     Id = 1001,
  99.                     Name = "张三",
  100.                     Department = "技术部",
  101.                     Salary = 15000,
  102.                     Bonus = 3000,
  103.                     HireDate = new DateTime(2020, 1, 15)
  104.                 },
  105.                 new Employee
  106.                 {
  107.                     Id = 1002,
  108.                     Name = "李四",
  109.                     Department = "销售部",
  110.                     Salary = 12000,
  111.                     Bonus = 5000,
  112.                     HireDate = new DateTime(2019, 3, 22)
  113.                 },
  114.                 new Employee
  115.                 {
  116.                     Id = 1003,
  117.                     Name = "王五",
  118.                     Department = "人事部",
  119.                     Salary = 10000,
  120.                     Bonus = 2000,
  121.                     HireDate = new DateTime(2021, 5, 10)
  122.                 }
  123.             };
  124.             
  125.             // 保存为JSON文件
  126.             string jsonPath = Path.Combine(outputDirectory, "员工数据.json");
  127.             var jsonContent = Newtonsoft.Json.JsonConvert.SerializeObject(sampleEmployees, Newtonsoft.Json.Formatting.Indented);
  128.             File.WriteAllText(jsonPath, jsonContent);
  129.             
  130.             Console.WriteLine($"示例数据文件已创建: {jsonPath}");
  131.         }
  132.         catch (Exception ex)
  133.         {
  134.             Console.WriteLine($"创建示例数据文件时发生错误: {ex.Message}");
  135.         }
  136.     }
  137. }
  138. // 使用示例
  139. class Program
  140. {
  141.     static void Main(string[] args)
  142.     {
  143.         var paySlipSystem = new CompletePaySlipGenerationSystem();
  144.         
  145.         // 创建输出目录
  146.         string outputDirectory = @"C:\PaySlips";
  147.         if (!Directory.Exists(outputDirectory))
  148.         {
  149.             Directory.CreateDirectory(outputDirectory);
  150.         }
  151.         
  152.         // 创建示例数据文件
  153.         paySlipSystem.CreateSampleDataFiles(outputDirectory);
  154.         
  155.         // 运行工资条生成流程
  156.         string jsonPath = Path.Combine(outputDirectory, "员工数据.json");
  157.         paySlipSystem.RunPaySlipGenerationProcess(DataSourceType.Json, jsonPath, outputDirectory);
  158.         
  159.         Console.WriteLine("工资条生成系统运行完成!");
  160.     }
  161. }
复制代码
总结

使用MudTools.OfficeInterop.Word库实现数据驱动的文档处理,包括传统的邮件合并功能简介和更灵活的自定义数据填充方案:

  • 传统邮件合并功能:虽然库中未直接提供,但理解其原理有助于我们设计更好的自定义方案
  • 自定义数据填充方案

    • 从数据库(SQL Server)、Excel、JSON文件等数据源读取数据
    • 使用循环和上文技术(书签、查找替换、表格操作)将数据批量填充到Word文档的指定位置

通过实战示例,创建了一个完整的批量员工工资条生成系统,展示了这些功能在实际工作中的强大应用。这些技能在实际工作中非常有用,能够大大提高文档处理的效率和质量。
掌握了这些技巧后,将能够:

  • 快速批量生成个性化文档,节省大量人工处理时间
  • 整合来自不同数据源的信息,创建综合性的报告文档
  • 实现真正的数据驱动文档生成,确保内容的准确性和一致性
  • 构建企业级的文档自动化系统,提升整体办公效率

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册