将多个DataGridView导出至Excel工作簿不同工作表的实现求助
嘿,作为Visual Studio新手要搞定这个多窗体DataGridView导出到同个Excel多工作表的需求确实有点头大,不过我给你整理了一套实用的方案,你可以一步步跟着来实现,应该能解决你的问题!
解决方案步骤
1. 准备工作:安装EPPlus库
首先我们需要一个好用的Excel操作库,推荐用EPPlus——它免费、轻量,而且对WinForms项目很友好。你可以通过NuGet安装:
- 打开Visual Studio的「NuGet包管理器控制台」
- 输入命令:
Install-Package EPPlus -Version 4.5.3.3(这个版本无需商用许可证,适合非商业场景)
2. 封装每个楼层窗体的数据获取方法
为了让主窗体能轻松拿到各个楼层窗体的DataGridView数据,我们在每个楼层窗体(比如Floor1Form、Floor2Form)里写一个公共方法,把DataGridView的数据转换成DataTable:
// 以一楼窗体为例,其他楼层窗体同理 public DataTable GetCheckListData() { DataTable dataTable = new DataTable(); // 先添加列(对应DataGridView的表头) foreach (DataGridViewColumn col in dgvFloor1.Columns) { dataTable.Columns.Add(col.HeaderText); } // 再添加行数据 foreach (DataGridViewRow row in dgvFloor1.Rows) { if (!row.IsNewRow) // 跳过DataGridView的空行 { DataRow dataRow = dataTable.NewRow(); for (int i = 0; i < dgvFloor1.Columns.Count; i++) { dataRow[i] = row.Cells[i].Value ?? DBNull.Value; // 处理空值 } dataTable.Rows.Add(dataRow); } } return dataTable; }
3. 主窗体实现多工作表导出逻辑
在你的主窗体(包含CheckedListBox的那个)里,添加一个导出按钮,编写点击事件逻辑:
private void btnExportMultiFloors_Click(object sender, EventArgs e) { // 先判断有没有勾选楼层 if (checkedListBoxFloors.CheckedItems.Count == 0) { MessageBox.Show("请至少勾选一个楼层哦!"); return; } // 让用户选择Excel保存路径 SaveFileDialog saveDialog = new SaveFileDialog(); saveDialog.Filter = "Excel文件 (*.xlsx)|*.xlsx"; saveDialog.Title = "导出多楼层检查表"; if (saveDialog.ShowDialog() != DialogResult.OK) { return; } // 创建Excel工作簿 using (ExcelPackage excelPackage = new ExcelPackage()) { // 遍历每个勾选的楼层 foreach (var checkedItem in checkedListBoxFloors.CheckedItems) { string floorName = checkedItem.ToString(); // 为当前楼层创建一个工作表 ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets.Add(floorName); // 获取对应楼层窗体的数据 DataTable floorData = GetFloorDataTable(floorName); if (floorData == null || floorData.Rows.Count == 0) { worksheet.Cells["A1"].Value = $"{floorName}暂无检查数据"; continue; } // 将DataTable数据填充到工作表 worksheet.Cells["A1"].LoadFromDataTable(floorData, true); // 自动调整列宽,让内容更美观 worksheet.Cells.AutoFitColumns(); } // 保存Excel文件 excelPackage.SaveAs(new FileInfo(saveDialog.FileName)); MessageBox.Show("多楼层检查表导出成功!"); } } // 根据楼层名称匹配对应的窗体,获取数据 private DataTable GetFloorDataTable(string floorName) { switch (floorName) { case "一楼": // 优先用已打开的窗体实例,避免重复创建 Floor1Form floor1Form = Application.OpenForms.OfType<Floor1Form>().FirstOrDefault() ?? new Floor1Form(); return floor1Form.GetCheckListData(); case "二楼": Floor2Form floor2Form = Application.OpenForms.OfType<Floor2Form>().FirstOrDefault() ?? new Floor2Form(); return floor2Form.GetCheckListData(); // 其他楼层依次添加case default: return null; } }
4. 单个楼层窗体的单独导出逻辑
如果要实现每个楼层窗体单独导出的功能,直接在对应窗体里添加导出按钮,编写如下逻辑:
private void btnExportSingleFloor_Click(object sender, EventArgs e) { SaveFileDialog saveDialog = new SaveFileDialog(); saveDialog.Filter = "Excel文件 (*.xlsx)|*.xlsx"; saveDialog.Title = $"导出{this.Text}检查表"; if (saveDialog.ShowDialog() != DialogResult.OK) { return; } using (ExcelPackage excelPackage = new ExcelPackage()) { ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets.Add(this.Text); DataTable floorData = GetCheckListData(); if (floorData == null || floorData.Rows.Count == 0) { worksheet.Cells["A1"].Value = "暂无检查数据"; } else { worksheet.Cells["A1"].LoadFromDataTable(floorData, true); worksheet.Cells.AutoFitColumns(); } excelPackage.SaveAs(new FileInfo(saveDialog.FileName)); MessageBox.Show("检查表导出成功!"); } }
5. 几个关键注意事项
- 窗体实例化问题:代码里用
Application.OpenForms获取已打开的窗体,避免重复创建新窗体导致数据不一致 - 空值处理:用
?? DBNull.Value处理DataGridView里的空单元格,避免导出时出错 - EPPlus版本:如果使用5.x及以上版本,商用场景需要购买许可证,非商用可以免费使用;嫌麻烦就直接用4.5.3.3版本
内容的提问来源于stack exchange,提问作者shine




