c# 收件单通知单生成程序
项目概述
一个基于C# WinForms的批量文档生成工具,用于从Excel数据自动生成Word文档(收件单和调查工作笔录)。
技术栈
- 开发框架: .NET WinForms 
- Excel处理: EPPlus 5.8.14 
- Word处理: Aspose.Words 
- 界面: Windows Forms 
核心功能
1. 文件选择管理
- 电子表格选择(支持.xls, .xlsx, .csv) 
- 双模板支持(模板01和模板02) 
- 输出目录选择 
- 默认路径预设(Z:\0000) 
2. 数据读取
// 读取Excel Sheet2数据
private List<Dictionary<string, string>> ReadExcelData()
{ExcelPackage.LicenseContext = LicenseContext.NonCommercial;// 读取表头和数据行
}3. 文档替换逻辑
18个字段的自动替换:
| 字段 | 数据来源 | 说明 | 
|---|---|---|
| 01新宗地号 | Excel | 取后7位 | 
| 02权利人姓名 | Excel | 权利人姓名 | 
| 03地址 | Excel | 地址信息 | 
| 04收件人 | textBox1 | 固定值"陈XX" | 
| 05收件人日期 | textBox2 | 固定值"2024.7.15" | 
| 06电话号码 | Excel | 电话号码 | 
| 07坐落 | Excel | 坐落信息 | 
| 08笔录时间 | textBox3 | 固定值"2024.10.15" | 
| 09房本面积 | Excel | 房本面积 | 
| 10原权利人 | Excel | 原权利人 | 
| 11房屋翻建时间 | Excel | 房屋翻建时间 | 
| 12村指界人签字 | textBox4 | 固定值"彭XX" | 
| 13房本编号 | Excel | 房本编号 | 
| 14yyyy | 笔录时间 | 年份(2024) | 
| 15MM | 笔录时间 | 月份(10) | 
| 16dd | 笔录时间 | 日期(15) | 
| 17镇村 | textBox6 | 固定值"XXX镇XXX村" | 
| 18dd | 笔录时间-2天 | 日期减2天(13) | 
4. 目录结构
Z:\0000\
└── [Excel文件名]├── 调查工作笔录\│   └── [新宗地号]_[权利人姓名]_调查工作笔录.docx└── 收件单\└── [新宗地号]_[权利人姓名]_收件单.docx关键代码特性
1. 智能路径处理
// 自动创建目录结构
private string CreateOutputDirectory(string folderName)
{string outputPath = Path.Combine(outputDirectory, excelName, folderName);Directory.CreateDirectory(outputPath);return outputPath;
}2. 文档替换引擎
// 使用Aspose.Words进行批量替换
private void ReplaceInDocument(string templatePath, string outputPath, Dictionary<string, string> replacements)
{Document doc = new Document(templatePath);foreach (var replacement in replacements){doc.Range.Replace(replacement.Key, replacement.Value, findReplaceOptions);}doc.Save(outputPath);
}3. 日期处理逻辑
// 笔录时间格式化及计算
DateTime 笔录时间减2天 = 笔录时间.AddDays(-2);
string 笔录时间减2天dd = 笔录时间减2天.ToString("dd");界面控件说明
主要输入控件
- textBox1: 收件人(陈XX)
- textBox2: 收件日期(2024.7.15)
- textBox3: 笔录时间(2024.10.15)
- textBox4: 村指界人签字(彭XX)
- textBox6: 镇村信息(XXX镇XXX村)
功能按钮
- 收件单-通知单: 打开操作选择对话框 
- 开始生成: 执行文档生成 
- 预览结构: 显示目录结构预览 
- 清空选择: 重置所有选择 
使用流程
- 启动程序 → 自动设置默认路径 
- 选择电子表格 → 读取Sheet2数据 
- 验证模板路径 → 检查默认模板是否存在 
- 点击开始生成 → 批量生成文档 
- 查看输出 → 在指定目录查看生成的文件 
优势特点
- 批量处理: 一次性处理Excel中的所有数据行 
- 模板灵活: 支持两个独立的Word模板 
- 智能替换: 18个字段的自动替换 
- 目录组织: 按Excel文件名和模板类型自动组织文件 
- 用户友好: 可视化界面和状态提示 
- 错误处理: 完善的异常捕获和提示 
扩展可能性
- 模板管理: 支持更多模板类型 
- 字段扩展: 增加更多替换字段 
- 格式定制: 支持更多日期格式和数据处理 
- 批量转换: 添加PDF转换功能 
- 配置保存: 保存用户设置和路径偏好 
这个程序极大地提高了文档生成的效率,特别适用于需要批量生成标准化文档的办公场景。
项目文件结构
收件单通知单/
├── Properties/
│   ├── AssemblyInfo.cs
│   └── Resources.resx
├── References/
│   ├── Aspose.Words.dll
│   ├── EPPlus.dll
│   ├── System.Data.dll
│   └── System.Windows.Forms.dll
├── Form1.Designer.cs
├── Form1.cs
├── Program.cs
├── App.config
└── 收件单通知单.csproj代码结构详解
1. 程序入口 (Program.cs)
static class Program
{[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new Form1());}
}2. 主窗体类 (Form1.cs)
using Aspose.Words;
using Aspose.Words.Replacing;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using test;
using Document = Aspose.Words.Document;namespace 收件单通知单
{public partial class Form1 : Form{// 添加类级变量来存储路径private string excelFilePath = string.Empty;private string templateFilePath01 = string.Empty;private string templateFilePath02 = string.Empty;private string outputDirectory = string.Empty;// 默认路径private const string DEFAULT_BASE_PATH = @"Z:\0000";private const string DEFAULT_TEMPLATE01 = @"Z:\0000\调查工作笔录.docx";private const string DEFAULT_TEMPLATE02 = @"Z:\0000\收件单.docx";public Form1(){InitializeComponent();SetDefaultPaths();UpdateGenerateButtonState();}// 设置默认路径private void SetDefaultPaths(){// 设置默认输出目录outputDirectory = DEFAULT_BASE_PATH;txtOutputPath.Text = outputDirectory;// 设置默认模板路径(如果文件存在)if (File.Exists(DEFAULT_TEMPLATE01)){templateFilePath01 = DEFAULT_TEMPLATE01;txtTemplate01.Text = templateFilePath01;}if (File.Exists(DEFAULT_TEMPLATE02)){templateFilePath02 = DEFAULT_TEMPLATE02;txtTemplate02.Text = templateFilePath02;}UpdateStatus("默认路径已设置");UpdateGenerateButtonState();}private void button1_Click(object sender, EventArgs e){ShowOperationDialog();}private void ShowOperationDialog(){using (var choiceDialog = new Form(){Text = "请选择操作类型",Width = 300,Height = 280,FormBorderStyle = FormBorderStyle.FixedDialog,StartPosition = FormStartPosition.CenterParent,MaximizeBox = false,MinimizeBox = false}){var btnExcel = new Button() { Text = "1 选择电子表格", Left = 50, Top = 20, Width = 150, Height = 30 };var btnTemplate01 = new Button() { Text = "2 选择模板01", Left = 50, Top = 60, Width = 150, Height = 30 };var btnTemplate02 = new Button() { Text = "3 选择模板02", Left = 50, Top = 100, Width = 150, Height = 30 };var btnOutput = new Button() { Text = "4 选择生成目录", Left = 50, Top = 140, Width = 150, Height = 30 };var btnGenerate = new Button() { Text = "5 开始生成", Left = 50, Top = 180, Width = 150, Height = 30, Enabled = false };UpdateDialogGenerateButton(btnGenerate);btnExcel.Click += (s, args) =>{SelectExcelFile();UpdateDialogGenerateButton(btnGenerate);};btnTemplate01.Click += (s, args) =>{SelectTemplateFile("01");UpdateDialogGenerateButton(btnGenerate);};btnTemplate02.Click += (s, args) =>{SelectTemplateFile("02");UpdateDialogGenerateButton(btnGenerate);};btnOutput.Click += (s, args) =>{SelectOutputDirectory();UpdateDialogGenerateButton(btnGenerate);};btnGenerate.Click += (s, args) =>{choiceDialog.DialogResult = DialogResult.OK;GenerateDocuments();};choiceDialog.Controls.AddRange(new Control[] { btnExcel, btnTemplate01, btnTemplate02, btnOutput, btnGenerate });if (choiceDialog.ShowDialog(this) == DialogResult.OK){UpdateStatus("操作完成");}}}// 读取Excel数据 Sheet2private List<Dictionary<string, string>> ReadExcelData(){var data = new List<Dictionary<string, string>>();ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;using (var package = new ExcelPackage(new FileInfo(excelFilePath))){var worksheet = package.Workbook.Worksheets["Sheet2"];if (worksheet == null){throw new Exception("未找到Sheet2工作表");}int rowCount = worksheet.Dimension.Rows;int colCount = worksheet.Dimension.Columns;// 读取表头var headers = new List<string>();for (int col = 1; col <= colCount; col++){headers.Add(worksheet.Cells[1, col].Value?.ToString() ?? "");}// 读取数据行for (int row = 2; row <= rowCount; row++){var rowData = new Dictionary<string, string>();for (int col = 1; col <= colCount; col++){string header = headers[col - 1];string value = worksheet.Cells[row, col].Value?.ToString() ?? "";rowData[header] = value;}// 只添加有数据的行if (rowData.Values.Any(v => !string.IsNullOrEmpty(v))){data.Add(rowData);}}}return data;}// 使用Aspose.Words进行文档替换private void ReplaceInDocument(string templatePath, string outputPath, Dictionary<string, string> replacements){// 加载模板文档Document doc = new Document(templatePath);// 创建替换规则var findReplaceOptions = new FindReplaceOptions{MatchCase = false,FindWholeWordsOnly = false};// 执行所有替换foreach (var replacement in replacements){doc.Range.Replace(replacement.Key, replacement.Value, findReplaceOptions);}// 保存文档doc.Save(outputPath);}// 生成文档的主要逻辑private void GenerateDocumentsInternal(){try{// 读取Excel数据var excelData = ReadExcelData();UpdateStatus($"读取到 {excelData.Count} 条数据");// 处理笔录时间格式DateTime 笔录时间;if (!DateTime.TryParse(textBox3.Text, out 笔录时间)){笔录时间 = DateTime.Now;}string 笔录时间yyyy = 笔录时间.ToString("yyyy");string 笔录时间MM = 笔录时间.ToString("MM");string 笔录时间dd = 笔录时间.ToString("dd");// 18. 笔录时间减2天DateTime 笔录时间减2天 = 笔录时间.AddDays(-2);string 笔录时间减2天dd = 笔录时间减2天.ToString("dd");int processedCount = 0;foreach (var rowData in excelData){processedCount++;UpdateStatus($"正在处理第 {processedCount} 条数据...");// 准备替换数据var replacements = new Dictionary<string, string>();// 1. 新宗地号 取后7位string 新宗地号 = rowData.ContainsKey("新宗地号") ? rowData["新宗地号"] : "";if (!string.IsNullOrEmpty(新宗地号) && 新宗地号.Length > 7){新宗地号 = 新宗地号.Substring(新宗地号.Length - 7);}replacements["01新宗地号"] = 新宗地号;// 2. 权利人姓名replacements["02权利人姓名"] = rowData.ContainsKey("权利人姓名") ? rowData["权利人姓名"] : "";// 3. 地址replacements["03地址"] = rowData.ContainsKey("地址") ? rowData["地址"] : "";// 4. 收件人replacements["04收件人"] = textBox1.Text;// 5. 收件人日期replacements["05收件人日期"] = textBox2.Text;// 6. 电话号码replacements["06电话号码"] = rowData.ContainsKey("电话号码") ? rowData["电话号码"] : "";// 7. 坐落replacements["07坐落"] = rowData.ContainsKey("坐落") ? rowData["坐落"] : "";// 8. 笔录时间replacements["08笔录时间"] = textBox3.Text;// 9. 房本面积replacements["09房本面积"] = rowData.ContainsKey("房本面积") ? rowData["房本面积"] : "";// 10. 原权利人replacements["10原权利人"] = rowData.ContainsKey("原权利人") ? rowData["原权利人"] : "";// 11. 房屋翻建时间replacements["11房屋翻建时间"] = rowData.ContainsKey("房屋翻建时间") ? rowData["房屋翻建时间"] : "";// 12. 村指界人签字replacements["12村指界人签字"] = textBox4.Text;// 13. 房本编号replacements["13房本编号"] = rowData.ContainsKey("房本编号") ? rowData["房本编号"] : "";// 14-16. 笔录时间格式化replacements["14yyyy"] = 笔录时间yyyy;replacements["15MM"] = 笔录时间MM;replacements["16dd"] = 笔录时间dd;// 17. 镇村replacements["17镇村"] = textBox6.Text; // 使用textBox6的内容// 18. 笔录时间减2天replacements["18dd"] = 笔录时间减2天dd;// 使用模板01生成文档if (!string.IsNullOrEmpty(templateFilePath01)){string outputDir01 = CreateOutputDirectory(Path.GetFileNameWithoutExtension(templateFilePath01));string fileName = $"{新宗地号}_{replacements["02权利人姓名"]}_{Path.GetFileNameWithoutExtension(templateFilePath01)}.docx";string outputPath = Path.Combine(outputDir01, fileName);ReplaceInDocument(templateFilePath01, outputPath, replacements);}// 使用模板02生成文档if (!string.IsNullOrEmpty(templateFilePath02)){string outputDir02 = CreateOutputDirectory(Path.GetFileNameWithoutExtension(templateFilePath02));string fileName = $"{新宗地号}_{replacements["02权利人姓名"]}_{Path.GetFileNameWithoutExtension(templateFilePath02)}.docx";string outputPath = Path.Combine(outputDir02, fileName);ReplaceInDocument(templateFilePath02, outputPath, replacements);}}UpdateStatus($"成功生成 {processedCount} 个文档");}catch (Exception ex){throw new Exception($"生成文档时出错: {ex.Message}", ex);}}// 更新对话框中的生成按钮状态private void UpdateDialogGenerateButton(Button btnGenerate){bool canGenerate = !string.IsNullOrEmpty(excelFilePath) &&(!string.IsNullOrEmpty(templateFilePath01) || !string.IsNullOrEmpty(templateFilePath02)) &&!string.IsNullOrEmpty(outputDirectory);btnGenerate.Enabled = canGenerate;btnGenerate.BackColor = canGenerate ? Color.LightGreen : Color.LightGray;}private void SelectExcelFile(){using (OpenFileDialog dialog = new OpenFileDialog()){dialog.Title = "选择电子表格";dialog.Filter = "Excel文件 (*.xls;*.xlsx)|*.xls;*.xlsx|CSV文件 (*.csv)|*.csv|所有文件 (*.*)|*.*";dialog.FilterIndex = 1;dialog.Multiselect = false;if (dialog.ShowDialog() == DialogResult.OK){excelFilePath = dialog.FileName;txtExcelPath.Text = excelFilePath;UpdateStatus($"已选择Excel文件: {Path.GetFileName(excelFilePath)}");UpdateGenerateButtonState();}}}private void SelectTemplateFile(string templateType){using (OpenFileDialog dialog = new OpenFileDialog()){dialog.Title = $"选择模板{templateType}";dialog.Filter = "Word模板 (*.doc;*.docx)|*.doc;*.docx|所有文件 (*.*)|*.*";dialog.FilterIndex = 1;dialog.Multiselect = false;// 设置默认目录if (Directory.Exists(DEFAULT_BASE_PATH)){dialog.InitialDirectory = DEFAULT_BASE_PATH;}if (dialog.ShowDialog() == DialogResult.OK){if (templateType == "01"){templateFilePath01 = dialog.FileName;txtTemplate01.Text = templateFilePath01;}else{templateFilePath02 = dialog.FileName;txtTemplate02.Text = templateFilePath02;}UpdateStatus($"已选择模板{templateType}: {Path.GetFileName(dialog.FileName)}");UpdateGenerateButtonState();}}}private void SelectOutputDirectory(){using (test.FolderBrowserDialog dialog = new test.FolderBrowserDialog()){// 设置默认目录if (Directory.Exists(DEFAULT_BASE_PATH)){// 如果使用系统的FolderBrowserDialog,可能需要其他方式设置初始目录}if (dialog.ShowDialog(this) == DialogResult.OK){outputDirectory = dialog.DirectoryPath;txtOutputPath.Text = outputDirectory;UpdateStatus($"输出目录: {outputDirectory}");UpdateGenerateButtonState();}}}// 双击事件处理方法private void txtExcelPath_DoubleClick_1(object sender, EventArgs e){SelectExcelFile();}private void txtTemplate01_DoubleClick(object sender, EventArgs e){SelectTemplateFile("01");}private void txtTemplate02_DoubleClick(object sender, EventArgs e){SelectTemplateFile("02");}private void txtOutputPath_DoubleClick(object sender, EventArgs e){SelectOutputDirectory();}// 按钮点击事件处理方法private void btnGenerate_Click(object sender, EventArgs e){GenerateDocuments();}private void btnPreview_Click(object sender, EventArgs e){PreviewDirectoryStructure();}private void btnClear_Click(object sender, EventArgs e){ClearAllSelections();}// 更新生成按钮状态private void UpdateGenerateButtonState(){bool canGenerate = !string.IsNullOrEmpty(excelFilePath) &&(!string.IsNullOrEmpty(templateFilePath01) || !string.IsNullOrEmpty(templateFilePath02)) &&!string.IsNullOrEmpty(outputDirectory);btnGenerate.Enabled = canGenerate;btnGenerate.BackColor = canGenerate ? Color.LightGreen : SystemColors.Control;}// 更新状态显示private void UpdateStatus(string message){lblStatus.Text = $"{DateTime.Now:HH:mm:ss} - {message}";}// 预览目录结构private void PreviewDirectoryStructure(){if (string.IsNullOrEmpty(outputDirectory) || string.IsNullOrEmpty(excelFilePath)){MessageBox.Show("请先选择电子表格和输出目录!", "提示",MessageBoxButtons.OK, MessageBoxIcon.Warning);return;}string excelName = Path.GetFileNameWithoutExtension(excelFilePath);StringBuilder sb = new StringBuilder();sb.AppendLine("将生成以下目录结构:");sb.AppendLine(outputDirectory);sb.AppendLine($"└── {excelName}");if (!string.IsNullOrEmpty(templateFilePath01))sb.AppendLine($"    └── {Path.GetFileNameWithoutExtension(templateFilePath01)}");if (!string.IsNullOrEmpty(templateFilePath02))sb.AppendLine($"    └── {Path.GetFileNameWithoutExtension(templateFilePath02)}");MessageBox.Show(sb.ToString(), "目录结构预览",MessageBoxButtons.OK, MessageBoxIcon.Information);}// 清空所有选择private void ClearAllSelections(){excelFilePath = string.Empty;templateFilePath01 = string.Empty;templateFilePath02 = string.Empty;outputDirectory = string.Empty;txtExcelPath.Text = string.Empty;txtTemplate01.Text = string.Empty;txtTemplate02.Text = string.Empty;txtOutputPath.Text = string.Empty;UpdateStatus("已清空所有选择");UpdateGenerateButtonState();}// 生成文件的方法private void GenerateDocuments(){if (string.IsNullOrEmpty(excelFilePath) ||(string.IsNullOrEmpty(templateFilePath01) && string.IsNullOrEmpty(templateFilePath02)) ||string.IsNullOrEmpty(outputDirectory)){MessageBox.Show("请先选择Excel文件、至少一个模板文件和输出目录!", "提示",MessageBoxButtons.OK, MessageBoxIcon.Warning);return;}try{UpdateStatus("正在生成文档...");Cursor = Cursors.WaitCursor;// 实际生成逻辑GenerateDocumentsInternal();MessageBox.Show("文档生成完成!", "成功",MessageBoxButtons.OK, MessageBoxIcon.Information);UpdateStatus("文档生成完成");}catch (Exception ex){MessageBox.Show($"生成文档时出错: {ex.Message}", "错误",MessageBoxButtons.OK, MessageBoxIcon.Error);UpdateStatus($"错误: {ex.Message}");}finally{Cursor = Cursors.Default;}}// 创建输出目录结构private string CreateOutputDirectory(string templateType){if (string.IsNullOrEmpty(outputDirectory))throw new InvalidOperationException("输出目录未选择");string excelName = Path.GetFileNameWithoutExtension(excelFilePath);if (string.IsNullOrEmpty(excelName))throw new InvalidOperationException("无法获取电子表格名称");// 构建目录路径:输出目录\电子表格名字\模板X\string outputPath = Path.Combine(outputDirectory, excelName, $"{templateType}");// 如果目录不存在,则创建if (!Directory.Exists(outputPath)){Directory.CreateDirectory(outputPath);UpdateStatus($"创建目录: {outputPath}");}return outputPath;}}
}3. 界面设计器 (Form1.Designer.cs)
namespace 收件单通知单
{partial class Form1{/// <summary>/// 必需的设计器变量。/// </summary>private System.ComponentModel.IContainer components = null;/// <summary>/// 清理所有正在使用的资源。/// </summary>/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region Windows 窗体设计器生成的代码/// <summary>/// 设计器支持所需的方法 - 不要修改/// 使用代码编辑器修改此方法的内容。/// </summary>private void InitializeComponent(){this.button1 = new System.Windows.Forms.Button();this.txtExcelPath = new System.Windows.Forms.TextBox();this.label1 = new System.Windows.Forms.Label();this.label2 = new System.Windows.Forms.Label();this.label3 = new System.Windows.Forms.Label();this.txtTemplate01 = new System.Windows.Forms.TextBox();this.txtOutputPath = new System.Windows.Forms.TextBox();this.txtTemplate02 = new System.Windows.Forms.TextBox();this.btnGenerate = new System.Windows.Forms.Button();this.btnPreview = new System.Windows.Forms.Button();this.btnClear = new System.Windows.Forms.Button();this.lblStatus = new System.Windows.Forms.Label();this.label4 = new System.Windows.Forms.Label();this.label5 = new System.Windows.Forms.Label();this.textBox1 = new System.Windows.Forms.TextBox();this.textBox2 = new System.Windows.Forms.TextBox();this.label6 = new System.Windows.Forms.Label();this.textBox3 = new System.Windows.Forms.TextBox();this.label7 = new System.Windows.Forms.Label();this.textBox4 = new System.Windows.Forms.TextBox();this.textBox5 = new System.Windows.Forms.TextBox();this.label8 = new System.Windows.Forms.Label();this.textBox6 = new System.Windows.Forms.TextBox();this.SuspendLayout();// // button1// this.button1.Location = new System.Drawing.Point(12, 188);this.button1.Name = "button1";this.button1.Size = new System.Drawing.Size(116, 23);this.button1.TabIndex = 0;this.button1.Text = "收件单-通知单";this.button1.UseVisualStyleBackColor = true;this.button1.Click += new System.EventHandler(this.button1_Click);// // txtExcelPath// this.txtExcelPath.Location = new System.Drawing.Point(107, 12);this.txtExcelPath.Name = "txtExcelPath";this.txtExcelPath.Size = new System.Drawing.Size(380, 21);this.txtExcelPath.TabIndex = 4;this.txtExcelPath.DoubleClick += new System.EventHandler(this.txtExcelPath_DoubleClick_1);// // label1// this.label1.AutoSize = true;this.label1.Location = new System.Drawing.Point(12, 15);this.label1.Name = "label1";this.label1.Size = new System.Drawing.Size(89, 12);this.label1.TabIndex = 5;this.label1.Text = "1 选择电子表格";// // label2// this.label2.AutoSize = true;this.label2.Location = new System.Drawing.Point(12, 46);this.label2.Name = "label2";this.label2.Size = new System.Drawing.Size(65, 12);this.label2.TabIndex = 6;this.label2.Text = "2 选择模板";// // label3// this.label3.AutoSize = true;this.label3.Location = new System.Drawing.Point(12, 77);this.label3.Name = "label3";this.label3.Size = new System.Drawing.Size(89, 12);this.label3.TabIndex = 7;this.label3.Text = "3 选择生成目录";// // txtTemplate01// this.txtTemplate01.Location = new System.Drawing.Point(107, 43);this.txtTemplate01.Name = "txtTemplate01";this.txtTemplate01.Size = new System.Drawing.Size(183, 21);this.txtTemplate01.TabIndex = 8;this.txtTemplate01.DoubleClick += new System.EventHandler(this.txtTemplate01_DoubleClick);// // txtOutputPath// this.txtOutputPath.Location = new System.Drawing.Point(107, 74);this.txtOutputPath.Name = "txtOutputPath";this.txtOutputPath.Size = new System.Drawing.Size(380, 21);this.txtOutputPath.TabIndex = 9;this.txtOutputPath.DoubleClick += new System.EventHandler(this.txtOutputPath_DoubleClick);// // txtTemplate02// this.txtTemplate02.Location = new System.Drawing.Point(296, 43);this.txtTemplate02.Name = "txtTemplate02";this.txtTemplate02.Size = new System.Drawing.Size(191, 21);this.txtTemplate02.TabIndex = 10;this.txtTemplate02.DoubleClick += new System.EventHandler(this.txtTemplate02_DoubleClick);// // btnGenerate// this.btnGenerate.Location = new System.Drawing.Point(134, 188);this.btnGenerate.Name = "btnGenerate";this.btnGenerate.Size = new System.Drawing.Size(116, 23);this.btnGenerate.TabIndex = 11;this.btnGenerate.Text = "开始生成";this.btnGenerate.UseVisualStyleBackColor = true;this.btnGenerate.Click += new System.EventHandler(this.btnGenerate_Click);// // btnPreview// this.btnPreview.Location = new System.Drawing.Point(256, 188);this.btnPreview.Name = "btnPreview";this.btnPreview.Size = new System.Drawing.Size(116, 23);this.btnPreview.TabIndex = 12;this.btnPreview.Text = "预览结构";this.btnPreview.UseVisualStyleBackColor = true;this.btnPreview.Click += new System.EventHandler(this.btnPreview_Click);// // btnClear// this.btnClear.Location = new System.Drawing.Point(378, 188);this.btnClear.Name = "btnClear";this.btnClear.Size = new System.Drawing.Size(116, 23);this.btnClear.TabIndex = 13;this.btnClear.Text = "清空选择";this.btnClear.UseVisualStyleBackColor = true;this.btnClear.Click += new System.EventHandler(this.btnClear_Click);// // lblStatus// this.lblStatus.AutoSize = true;this.lblStatus.Location = new System.Drawing.Point(12, 220);this.lblStatus.Name = "lblStatus";this.lblStatus.Size = new System.Drawing.Size(29, 12);this.lblStatus.TabIndex = 14;this.lblStatus.Text = "就绪";// // label4// this.label4.AutoSize = true;this.label4.Location = new System.Drawing.Point(14, 111);this.label4.Name = "label4";this.label4.Size = new System.Drawing.Size(41, 12);this.label4.TabIndex = 15;this.label4.Text = "收件人";// // label5// this.label5.AutoSize = true;this.label5.Location = new System.Drawing.Point(125, 111);this.label5.Name = "label5";this.label5.Size = new System.Drawing.Size(53, 12);this.label5.TabIndex = 16;this.label5.Text = "收件日期";// // textBox1// this.textBox1.Location = new System.Drawing.Point(63, 107);this.textBox1.Name = "textBox1";this.textBox1.Size = new System.Drawing.Size(51, 21);this.textBox1.TabIndex = 17;this.textBox1.Text = "陈XX";// // textBox2// this.textBox2.Location = new System.Drawing.Point(184, 107);this.textBox2.Name = "textBox2";this.textBox2.Size = new System.Drawing.Size(77, 21);this.textBox2.TabIndex = 18;this.textBox2.Text = "2024.7.15";// // label6// this.label6.AutoSize = true;this.label6.Location = new System.Drawing.Point(267, 111);this.label6.Name = "label6";this.label6.Size = new System.Drawing.Size(53, 12);this.label6.TabIndex = 19;this.label6.Text = "笔录时间";// // textBox3// this.textBox3.Location = new System.Drawing.Point(326, 107);this.textBox3.Name = "textBox3";this.textBox3.Size = new System.Drawing.Size(77, 21);this.textBox3.TabIndex = 20;this.textBox3.Text = "2024.10.15";// // label7// this.label7.AutoSize = true;this.label7.Location = new System.Drawing.Point(410, 111);this.label7.Name = "label7";this.label7.Size = new System.Drawing.Size(77, 12);this.label7.TabIndex = 21;this.label7.Text = "村指界人签字";// // textBox4// this.textBox4.Location = new System.Drawing.Point(493, 107);this.textBox4.Name = "textBox4";this.textBox4.Size = new System.Drawing.Size(77, 21);this.textBox4.TabIndex = 22;this.textBox4.Text = "彭XX";// // textBox5// this.textBox5.Location = new System.Drawing.Point(97, 140);this.textBox5.Name = "textBox5";this.textBox5.Size = new System.Drawing.Size(77, 21);this.textBox5.TabIndex = 24;this.textBox5.Text = "彭XX";// // label8// this.label8.AutoSize = true;this.label8.Location = new System.Drawing.Point(14, 144);this.label8.Name = "label8";this.label8.Size = new System.Drawing.Size(77, 12);this.label8.TabIndex = 23;this.label8.Text = "村指界人签字";// // textBox6// this.textBox6.Location = new System.Drawing.Point(195, 141);this.textBox6.Name = "textBox6";this.textBox6.Size = new System.Drawing.Size(115, 21);this.textBox6.TabIndex = 25;this.textBox6.Text = "XXX镇XXX村";// // Form1// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(667, 323);this.Controls.Add(this.textBox6);this.Controls.Add(this.textBox5);this.Controls.Add(this.label8);this.Controls.Add(this.textBox4);this.Controls.Add(this.label7);this.Controls.Add(this.textBox3);this.Controls.Add(this.label6);this.Controls.Add(this.textBox2);this.Controls.Add(this.textBox1);this.Controls.Add(this.label5);this.Controls.Add(this.label4);this.Controls.Add(this.lblStatus);this.Controls.Add(this.btnClear);this.Controls.Add(this.btnPreview);this.Controls.Add(this.btnGenerate);this.Controls.Add(this.txtTemplate02);this.Controls.Add(this.txtOutputPath);this.Controls.Add(this.txtTemplate01);this.Controls.Add(this.label3);this.Controls.Add(this.label2);this.Controls.Add(this.label1);this.Controls.Add(this.txtExcelPath);this.Controls.Add(this.button1);this.Name = "Form1";this.Text = "收件单-通知单生成";this.ResumeLayout(false);this.PerformLayout();}#endregionprivate System.Windows.Forms.Button button1;private System.Windows.Forms.TextBox txtExcelPath;private System.Windows.Forms.Label label1;private System.Windows.Forms.Label label2;private System.Windows.Forms.Label label3;private System.Windows.Forms.TextBox txtTemplate01;private System.Windows.Forms.TextBox txtOutputPath;private System.Windows.Forms.TextBox txtTemplate02;private System.Windows.Forms.Button btnGenerate;private System.Windows.Forms.Button btnPreview;private System.Windows.Forms.Button btnClear;private System.Windows.Forms.Label lblStatus;private System.Windows.Forms.Label label4;private System.Windows.Forms.Label label5;private System.Windows.Forms.TextBox textBox1;private System.Windows.Forms.TextBox textBox2;private System.Windows.Forms.Label label6;private System.Windows.Forms.TextBox textBox3;private System.Windows.Forms.Label label7;private System.Windows.Forms.TextBox textBox4;private System.Windows.Forms.TextBox textBox5;private System.Windows.Forms.Label label8;private System.Windows.Forms.TextBox textBox6;}
}核心模块功能划分
1. 界面层 (UI Layer)
- 主窗体: 用户交互界面 
- 操作对话框: 功能选择界面 
- 状态显示: 实时进度反馈 
2. 业务逻辑层 (Business Logic Layer)
// 数据读取模块
- ReadExcelData(): 读取Excel数据// 文档处理模块  
- ReplaceInDocument(): 文档内容替换
- GenerateDocumentsInternal(): 文档生成逻辑// 文件管理模块
- CreateOutputDirectory(): 目录结构创建
- SetDefaultPaths(): 路径初始化3. 数据层 (Data Layer)
// 数据结构
Dictionary<string, string> // 单行数据
List<Dictionary<string, string>> // 所有数据行类关系图
Form1 (主窗体)
├── 界面控件
│   ├── 文件路径控件 (txtExcelPath, txtTemplate01, txtTemplate02, txtOutputPath)
│   ├── 输入控件 (textBox1-4, textBox6)
│   └── 功能按钮 (button1, btnGenerate, btnPreview, btnClear)
├── 业务逻辑
│   ├── 数据读取器 (ReadExcelData)
│   ├── 文档生成器 (GenerateDocumentsInternal)
│   └── 文档替换器 (ReplaceInDocument)
└── 工具方法├── 状态管理 (UpdateStatus, UpdateGenerateButtonState)└── 文件管理 (CreateOutputDirectory, SetDefaultPaths)数据流架构
用户操作 → 界面事件 → 业务逻辑 → 文件输出↓          ↓          ↓         ↓
选择文件 → 读取Excel → 处理数据 → 生成Word↓          ↓          ↓         ↓
设置参数 → 模板替换 → 格式处理 → 保存文档依赖关系
Form1
├── 依赖于 OfficeOpenXml (EPPlus) ← Excel数据处理
├── 依赖于 Aspose.Words ← Word文档处理  
├── 依赖于 System.IO ← 文件操作
├── 依赖于 System.Windows.Forms ← 用户界面
└── 依赖于 System.Collections.Generic ← 数据结构配置文件
App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration><startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/></startup>
</configuration>项目文件 (收件单通知单.csproj)
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"><Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" /><PropertyGroup><Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration><Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform><ProjectGuid>{...}</ProjectGuid><OutputType>WinExe</OutputType><RootNamespace>收件单通知单</RootNamespace><AssemblyName>收件单通知单</AssemblyName><TargetFrameworkVersion>v4.8</TargetFrameworkVersion><!-- 其他项目配置 --></PropertyGroup><ItemGroup><Reference Include="Aspose.Words" /><Reference Include="EPPlus" /><!-- 其他程序集引用 --></ItemGroup>
</Project>输出结构
Z:\0000\                              # 基础输出目录
└── 02大胡村家庭成员\                  # Excel文件名命名的目录├── 调查工作笔录\                  # 模板1输出目录│   ├── 1234567_张三_调查工作笔录.docx│   └── 1234568_李四_调查工作笔录.docx└── 收件单\                       # 模板2输出目录├── 1234567_张三_收件单.docx└── 1234568_李四_收件单.docx这个项目结构清晰,模块划分合理,便于维护和扩展。采用经典的三层架构模式,将界面、业务逻辑和数据访问分离,具有良好的可读性和可维护性。
