NPOI 导出 Excel

最终效果图

环境:Revit,WPF,NPOI 2.5.6,.Net Framework 4.7.2

一、引用 NPOI

  右击项目引用,选择 "管理NuGet程序包",在浏览搜索 NPOI ,选择版本(我这里是2.5.6),安装

  

 

  

  安装成功后,引用里会出现这四个引用(NPOI,NPOI.OOXML,NPOI.OpenXml4Net,NPOI.OpenXmlFormats)

  在NuGet程序包里会多出来这两个(Portable.BouncyCastle,SharpZipLib)这是 NPOI 2.5.6 的依赖项;

  2.6.0的依赖的项会多,同时扩展了很多方法。我的需求只是导出Excel,所以这块我选择依赖项相对较少的 2.5.6 版本

二、实现导出Excle方法

  我这里粗略的封装了一个类,主要由以下几个方法组成

  创建表格()实现,创建列名,创建行

  设置单元格样式()在创建列名,创建行时会用到

  获取保存文件绝对路径()

  保存文件()

  我这里有两个导出方法,分别 “导出”,“自定义框架导出”。

  自定义框架导出,大概逻辑就是,在外层,创建好顶部和底部,再调用导出创建出红色区域

  导出的效果就是,没有前两行的标题和副标题,也没有最后一行的总计,就是红色区域

  

  1. using Microsoft.Win32;
  2. using NPOI.SS.UserModel;
  3. using NPOI.XSSF.UserModel;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Data;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11.  
  12. namespace FormWork.Draft.ViewModels
  13. {
  14. public class FileHelper
  15. {
  16. /// <summary>
  17. /// Excel行高,Height的单位是1/20个点。例:设置高度为25个点
  18. /// </summary>
  19. private static short rowHeight = 25 * 20;
  20.  
  21. #region 导出Excel
  22.  
  23. #region 导出
  24.  
  25. /// <summary>
  26. /// 导出
  27. /// </summary>
  28. /// <param name="dt">数据源</param>
  29. /// <param name="strHeader">列名</param>
  30. /// <param name="fileName">绝对路径</param>
  31. /// <param name="sheetName">sheet页名</param>
  32. public static void Export(DataTable dt, string strHeader, string fileName, string sheetName = "Sheet1")
  33. {
  34. // 使用 NPOI 组件导出 Excel 文件
  35.  
  36. //XSSFWorkbook:是操作Excel2007的版本,扩展名是.xlsx
  37. XSSFWorkbook workbook = new XSSFWorkbook();
  38.  
  39. //HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls
  40. //HSSFWorkbook workbook = new HSSFWorkbook();
  41.  
  42. //创建Sheet
  43. ISheet sheet = workbook.CreateSheet(sheetName);
  44.  
  45. //对列名拆分
  46. string[] strArry = strHeader.Split(',');
  47.  
  48. //设置单元格样式
  49. ICellStyle style = SetCellStyle(workbook);
  50.  
  51. //创建表格
  52. NPOICreateTable(dt, strArry, sheet, style, 0);
  53.  
  54. // 将 Excel 文件保存到磁盘
  55. NPOISaveFile(workbook, fileName);
  56.  
  57. // 释放资源
  58. //workbook.Dispose();
  59. }
  60. #endregion
  61.  
  62. #region 自定义框架,导出
  63.  
  64. /// <summary>
  65. /// 自定义顶部,导出
  66. /// </summary>
  67. /// <param name="dt">数据源</param>
  68. /// <param name="strArry">拆分后列名</param>
  69. /// <param name="fileName">绝对路径,路径+文件名+后缀</param>
  70. /// <param name="num">新一行索引,开始</param>
  71. /// <param name="workbook"></param>
  72. /// <param name="sheet"></param>
  73. public static void Export(DataTable dt, string[] strArry, string fileName, int num, XSSFWorkbook workbook, ISheet sheet)
  74. {
  75. //设置单元格样式
  76. ICellStyle style = SetCellStyle(workbook);
  77.  
  78. //创建表格
  79. NPOICreateTable(dt, strArry, sheet, style, num);
  80.  
  81. // 将 Excel 文件保存到磁盘
  82. NPOISaveFile(workbook, fileName);
  83.  
  84. // 释放资源
  85. //workbook.Dispose();
  86. }
  87. #endregion
  88.  
  89. #endregion
  90.  
  91. #region 获取用户选择保存路径
  92.  
  93. /// <summary>
  94. /// 获取让用户选择保存文件的绝对路径
  95. /// </summary>
  96. /// <returns></returns>
  97. public static string GetSaveFileRoute(string filter, string fileName)
  98. {
  99. SaveFileDialog dialog = new SaveFileDialog();
  100. dialog.Filter = filter;
  101. dialog.FileName = fileName;
  102. if (dialog.ShowDialog() == true)
  103. {
  104. return dialog.FileName;
  105. }
  106. return "";
  107. }
  108.  
  109. #endregion
  110.  
  111. #region 保存文件
  112.  
  113. private static string NPOISaveFile(XSSFWorkbook workbook, string fileName)
  114. {
  115. try
  116. {
  117. // 将 Excel 文件保存到磁盘
  118. using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
  119. {
  120. workbook.Write(fs);
  121. }
  122.  
  123. return "";
  124. }
  125. catch (Exception err)
  126. {
  127. return err.Message;
  128. }
  129. }
  130.  
  131. #endregion
  132.  
  133. #region 创建表格
  134.  
  135. /// <summary>
  136. /// 创建表格
  137. /// </summary>
  138. /// <param name="dt">数据源</param>
  139. /// <param name="strArry">拆分后的列名</param>
  140. /// <param name="sheet">Sheet页</param>
  141. /// <param name="style">样式</param>
  142. /// <param name="num">行索引</param>
  143. private static void NPOICreateTable(DataTable dt, string[] strArry, ISheet sheet, ICellStyle style, int num)
  144. {
  145. IRow row = null;//声明行
  146.  
  147. #region 创建列名
  148.  
  149. //在索引 num 的位置 创建一行
  150. row = sheet.CreateRow(num);
  151. row.Height = rowHeight;//设置行高
  152.  
  153. //循环列名数组,创建单元格并赋值、样式
  154. for (int i = 0; i < strArry.Length; i++)
  155. {
  156. row.CreateCell(i).SetCellValue(strArry[i]);
  157. row.GetCell(i).CellStyle = style;
  158. }
  159.  
  160. #endregion
  161.  
  162. #region 创建行
  163.  
  164. //循环数据源 创建行
  165. for (int i = 0; i < dt.Rows.Count; i++)
  166. {
  167. //创建行
  168. row = sheet.CreateRow(num + 1);
  169. row.Height = rowHeight;//设置行高
  170. num++;//行索引自增
  171.  
  172. //循环数据源列集合,创建单元格
  173. for (int j = 0; j < dt.Columns.Count; j++)
  174. {
  175. string ValueType = "";//值类型
  176. string Value = "";//值
  177. //类型 和 值,赋值
  178. if (dt.Rows[i][j].ToString() != null)
  179. {
  180. ValueType = dt.Rows[i][j].GetType().ToString();
  181. Value = dt.Rows[i][j].ToString();
  182. }
  183. //根据不同数据类型,对数据处理。处理后创建单元格并赋值 和 样式
  184. switch (ValueType)
  185. {
  186. case "System.String"://字符串类型
  187. row.CreateCell(j).SetCellValue(Value);
  188. break;
  189. case "System.DateTime"://日期类型
  190. System.DateTime dateV;
  191. System.DateTime.TryParse(Value, out dateV);
  192. row.CreateCell(j).SetCellValue(dateV.ToString("yyyy-MM-dd"));
  193. break;
  194. case "System.Boolean"://布尔型
  195. bool boolV = false;
  196. bool.TryParse(Value, out boolV);
  197. row.CreateCell(j).SetCellValue(boolV);
  198. break;
  199. case "System.Int16"://整型
  200. case "System.Int32":
  201. case "System.Int64":
  202. case "System.Byte":
  203. int intV = 0;
  204. int.TryParse(Value, out intV);
  205. row.CreateCell(j).SetCellValue(intV);
  206. break;
  207. case "System.Decimal"://浮点型
  208. case "System.Double":
  209. double doubV = 0;
  210. double.TryParse(Value, out doubV);
  211. row.CreateCell(j).SetCellValue(doubV);
  212. break;
  213. case "System.DBNull"://空值处理
  214. row.CreateCell(j).SetCellValue("");
  215. break;
  216. default:
  217. row.CreateCell(j).SetCellValue("");
  218. break;
  219. }
  220. row.GetCell(j).CellStyle = style;
  221. //设置宽度
  222. //sheet.SetColumnWidth(j, (Value.Length + 10) * 256);
  223. }
  224. }
  225.  
  226. #endregion
  227.  
  228. //循环列名数组,多所有列 设置 自动列宽
  229. for (int i = 0; i < strArry.Length; i++)
  230. {
  231. sheet.AutoSizeColumn(i);
  232. }
  233. }
  234.  
  235. #endregion
  236.  
  237. #region 设置单元格样式
  238.  
  239. public static ICellStyle SetCellStyle(XSSFWorkbook workbook)
  240. {
  241. #region 单元格样式
  242.  
  243. //创建一个样式
  244. ICellStyle style = workbook.CreateCellStyle();
  245. style.Alignment = HorizontalAlignment.Center;//水平对齐
  246. style.VerticalAlignment = VerticalAlignment.Center;//垂直对齐
  247.  
  248. style.BorderBottom = BorderStyle.Thin;//下边框为细线边框
  249. style.BorderLeft = BorderStyle.Thin;//左边框
  250. style.BorderRight = BorderStyle.Thin;//上边框
  251. style.BorderTop = BorderStyle.Thin;//右边框
  252.  
  253. #endregion
  254.  
  255. return style;
  256. }
  257.  
  258. #endregion
  259. }
  260. }

三、调用导出

  OnExportCommand 此方法我是写在 ViewModel 里的。MVVM 模式,通过Command 绑定的事件。

  这个方法就相当于是 按钮的 Click事件

  1. /// <summary>
  2. /// 导出
  3. /// </summary>
  4. public void OnExportCommand()
  5. {
  6. try
  7. {
  8. //获取 DataGrid 控件的 数据源
  9. List<VisualList> visualLists = (List<VisualList>)view.gridVisualList.ItemsSource;
  10.  
  11. //将 集合 转换为 DaTable
  12. DataTable dt = visualLists.toDataTable();
  13. dt.Columns.Remove("Id");//删除不需要导出的列
  14.  
  15. //获取要将文件保存到 哪里 的绝对路径 (保存类型,默认文件名)
  16. string fileName = ViewModelHelper.GetSaveFileRoute("Excel文件|*.xlsx", "可视化清单.xlsx");
  17. if (fileName != "")
  18. {
  19. ViewModelHelper.Export(dt, "序号,规格,类型,单个面积m²,数量,合计面积m²", fileName);
  20.  
  21. //自定义框架导出↓↓↓
  22. //Export(dt, "序号,规格,类型,单个面积m²,数量,合计面积m²", fileName);
  23. }
  24. }
  25. catch (Exception err)
  26. {
  27. MessageBox.Show(err.Message, "错误");
  28. }
  29. }
  30.  
  31. /// <summary>
  32. /// 自定义框架,导出
  33. /// </summary>
  34. /// <param name="dt"></param>
  35. /// <param name="strHeader"></param>
  36. /// <param name="fileName"></param>
  37. /// <param name="sheetName"></param>
  38. public void Export(DataTable dt, string strHeader, string fileName, string sheetName = "Sheet1")
  39. {
  40. string[] strArry = strHeader.Split(',');
  41.  
  42. XSSFWorkbook workbook = new XSSFWorkbook();
  43. ISheet sheet = workbook.CreateSheet(sheetName);
  44. IRow row = null;
  45. ICellStyle style = null;
  46. IFont font = null;
  47.  
  48. #region 第一行/标题
  49.  
  50. //创建第一行
  51. row = sheet.CreateRow(0);
  52. row.Height = 25 * 20;
  53.  
  54. //样式
  55. style = workbook.CreateCellStyle();
  56. style.Alignment = HorizontalAlignment.Center;
  57. style.VerticalAlignment = VerticalAlignment.Center;
  58. font = workbook.CreateFont();
  59. font.IsBold = true;
  60. font.FontHeightInPoints = 15;
  61. style.SetFont(font);
  62.  
  63. //创建单元格,并赋 值 和 样式
  64. row.CreateCell(0).SetCellValue("可视化清单");
  65. row.GetCell(0).CellStyle = style;
  66. //合并单元格
  67. CellRangeAddress region = new CellRangeAddress(0, 0, 0, strArry.Length - 1);
  68. sheet.AddMergedRegion(region);
  69.  
  70. #endregion
  71.  
  72. #region 第二行/副标题
  73.  
  74. row = sheet.CreateRow(1);
  75. row.Height = 25 * 20;
  76.  
  77. //样式
  78. style = workbook.CreateCellStyle();
  79. style.VerticalAlignment = VerticalAlignment.Center;
  80. font = workbook.CreateFont();
  81. font.IsBold = true;
  82. style.SetFont(font);
  83.  
  84. row.CreateCell(0).SetCellValue("工程名称:项目名称");
  85. row.GetCell(0).CellStyle = style;
  86. region = new CellRangeAddress(1, 1, 0, strArry.Length / 2 - 1);
  87. sheet.AddMergedRegion(region);
  88.  
  89. row.CreateCell(strArry.Length / 2).SetCellValue("编号:项目编号");
  90. row.GetCell(strArry.Length / 2).CellStyle = style;
  91. region = new CellRangeAddress(1, 1, strArry.Length / 2, strArry.Length - 1);
  92. sheet.AddMergedRegion(region);
  93.  
  94. #endregion
  95.  
  96. #region 最后一行,总计
  97.  
  98. row = sheet.CreateRow(2 + 1 + dt.Rows.Count);//标题副标题+列名+数据行数
  99. row.Height = 25 * 20;
  100. row.CreateCell(0).SetCellValue("总计:");
  101.  
  102. int count = dt.Columns.IndexOf("Count");
  103. row.CreateCell(count).SetCellValue(SumAllCount);
  104.  
  105. int area = dt.Columns.IndexOf("SumArea");
  106. row.CreateCell(area).SetCellValue(SumAllArea);
  107.  
  108. for (int i = 0; i < strArry.Length; i++)
  109. {
  110. if (row.GetCell(i) == null)
  111. {
  112. row.CreateCell(i);
  113. }
  114. row.GetCell(i).CellStyle = ViewModelHelper.SetCellStyle(workbook);
  115. }
  116.  
  117. #endregion
  118.  
  119. ViewModelHelper.Export(dt, strArry, fileName, 2, workbook, sheet);
  120. }

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8.  
  9. namespace FormWork.Draft.Extension
  10. {
  11. /// <summary>
  12. /// 数据转换扩展类
  13. /// </summary>
  14. public static class DataConversionExtend
  15. {
  16. /// <summary>
  17. /// 转DataTable
  18. /// </summary>
  19. /// <param name="obj"></param>
  20. /// <param name="_tName"></param>
  21. /// <returns></returns>
  22. public static DataTable toDataTable(this object obj, string _tName = null)
  23. {
  24. Type t = obj.GetType();
  25. dynamic ts = obj;
  26. object tf = ts[0];
  27.  
  28. PropertyInfo[] pi = tf.GetType().GetProperties(BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
  29. DataTable DT = new DataTable();
  30. DT.TableName = _tName == null ? tf.GetType().ToString() : _tName;
  31. foreach (PropertyInfo p in pi)
  32. {
  33. DT.Columns.Add(p.Name, p.PropertyType);
  34. }
  35.  
  36. DataRow dr = null;
  37. foreach (var v in ts)
  38. {
  39. dr = DT.NewRow();
  40. foreach (PropertyInfo p in pi)
  41. {
  42. dr[p.Name] = p.GetValue(v, null);
  43. }
  44. DT.Rows.Add(dr);
  45. }
  46. return DT;
  47. }
  48. }
  49. }

List转DataTable 扩展方法

四、Revit 启用 WPF窗体,WPF 导出

  在这里我遇到个问题,就是

  在Revit 命令类中,可以直接通过NPOI导出到excel,但命令打开WPF无法导出 会报错

  未能加载文件或程序集"NPOI,Version=2.5.6.0,Culture=neutral,PublicKeyToken=0df73ec7942b34e1"或它的某一个依赖项,系统找不到指定的文件

  我目前尚未了解其真正原因,只是通过不断测试,发现在 Execute 方法内 导出一次,便不会报错

  我现在的理解就是在Execute结束前不导出一次,便不会加载NPOI程序集。未知其原理与原因。

  如有遇到此问题的小伙伴,欢迎留言

  1. public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
  2. {
  3. try
  4. {
  5. baseClass = new CmdBaseClass(commandData);
  6.  
  7. VisualListView view = VisualListView.Load(this);
  8.  
  9. //窗口一直显示在主程序之前
  10. System.Windows.Interop.WindowInteropHelper mainUI = new System.Windows.Interop.WindowInteropHelper(view);
  11. mainUI.Owner = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
  12. //打开非模态视图
  13. view.Show();
  14.  
  15. #region NPOI/导出
  16.  
  17. //未能加载文件或程序集"NPOI,Version=2.5.6.0,Culture=neutral,PublicKeyToken=0df73ec7942b34e1"或它的某一个依赖项,系统找不到指定的文件
  18. //此句勿删,在WPF中通过NPOI导出excel,如果不在此导出一次,就会报上面错误↑↑↑
  19. //在命令类中,可以直接通过NPOI导出到excel,但命令打开的WPF无法导出 会报错
  20. //目前尚未了解其真正原因,只是通过不断测试,发现在 Execute 方法内 导出一次,便不会报错
  21. //在Execute结束前不导出一次,便不会加载NPOI程序集
  22. Export();
  23.  
  24. #endregion
  25.  
  26. return Result.Succeeded;
  27. }
  28. catch (Exception err)
  29. {
  30. MessageBox.Show(err.Message, "错误");
  31. return Result.Failed;
  32. }
  33. }
  34.  
  35. private void Export()
  36. {
  37. IWorkbook workbook = new XSSFWorkbook();
  38. ISheet worksheet = workbook.CreateSheet("Sheet1");
  39.  
  40. // 将 Excel 文件保存到磁盘
  41. string fileName = @"D:\可视化清单" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xls";
  42. using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
  43. {
  44. workbook.Write(fs);
  45. }
  46. File.Delete(fileName);
  47. }

Revit

.Net NPOI Excel 导出的更多相关文章

  1. winform NPOI excel 导出并选择保存文件路径

    public void ExcelOp(DataGridView gdv,ArrayList selHead) { if (selHead.Count==0) { MessageBox.Show(&q ...

  2. NPOI excel导出快速构建

    直接上代码,这个是一个在webFrom中的例子,要请求的页面是ashx public void ExportVisaFeeAll(HttpContext context) { try { string ...

  3. c# .Net :Excel NPOI导入导出操作教程之读取Excel文件信息及输出

    c# .Net :Excel NPOI导入导出操作教程之读取Excel文件信息及输出 using NPOI.HSSF.UserModel;using NPOI.SS.UserModel;using S ...

  4. NPOI 导入导出excel 支持 03 07

    因为微软的office成本太高了,所以开发项目的时候电脑上没安装office,而是安装了wps.但开发语言用的是C#,所以直接调用微软的office组件是很方便的,但一方面慢,一方面成本高,所以从网上 ...

  5. NPOI导入导出EXCEL通用类,供参考,可直接使用在WinForm项目中

    以下是NPOI导入导出EXCEL通用类,是在别人的代码上进行优化的,兼容xls与xlsx文件格式,供参考,可直接使用在WinForm项目中,由于XSSFWorkbook类型的Write方法限制,Wri ...

  6. 使用NPOI完成导出Excel文件

    参考网址:http://blog.csdn.net/tiemufeng1122/article/details/6732588 能够实现  点击按钮弹出下载框    的功能,如图: HTML代码: & ...

  7. NPOI导入导出Excel

    .net mvc利用NPOI导入导出excel 注意:如何导出的提交方式ajax导出是失效的! 解决方案是:js处理l两个表单的提交  代码:  第一步. 在页面里面加入2个隐藏的iframe, 如下 ...

  8. C#中用NPOI的excel导出

    //机构表导出 private static List<User2> amininf = new BLL.Bll().GetUser2s(); //定义数据源导出对象 #region 导出 ...

  9. NPOI导入导出Excel数据

    代码: using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; usi ...

  10. .Net core NPOI导入导出Excel

    最近在想.net core NPOI 导入导出Excel,一开始感觉挺简单的,后来真的遇到很多坑.所以还是写一篇博客让其他人少走一些弯路,也方便忘记了再重温一遍.好了,多的不说,直接开始吧. 在.Ne ...

随机推荐

  1. Redis 缓存雪崩 |击穿 |穿透 概念及解决方案

    一.雪崩 1.概念  指某一时间段,缓存集中过期失效,无数的请求绕开缓存,直接访问数据库. 2.解决方案 让redis数据永不过期,这种方式最可靠的.最安全的,但占用空间,内存消耗大,并且不能保持数据 ...

  2. 安装Windows10后电脑整体速度变慢

    是不是觉得从旧版本Windows系统比如(Windows 7)升级到Windows10以后,感觉什么操作都变慢了.譬如打开文件夹,游戏加载速度变缓慢.尤其是腾讯WeGame软件进入游戏前的检测速度明显 ...

  3. SpringCloud微服务实战——搭建企业级开发框架(五十二):第三方登录-微信小程序授权登录流程设计和实现

      在前面的设计和实现中,我们的微服务开发平台通过JustAuth来实现第三方授权登录,通过集成公共组件,着实减少了很多工作量,大多数的第三方登录直接通过配置就可以实现.而在第三方授权登录中,微信小程 ...

  4. Chrome浏览器插件:CrxMouse(鼠标手势控制浏览器)

    CrxMouse是一款谷歌浏览器插件,它可以通过手势来控制您的浏览器,在您的日常网络浏览中提高效率和速度. 插件介绍 CrxMouse是一个非常流行的谷歌浏览器插件,它允许您通过鼠标手势来控制您的浏览 ...

  5. pysimplegui之读写配置项操作

    用户设置 API 在 4.30.0 版中,有一组新的 API 调用可用于帮助"用户设置".将用户设置视为自动写入硬盘的字典.基本上就是这样. 在 4.50.0 版中,除了现有的 J ...

  6. 全网最详细中英文ChatGPT-GPT-4示例文档-食谱智能生成从0到1快速入门——官网推荐的48种最佳应用场景(附python/node.js/curl命令源代码,小白也能学)

    目录 Introduce 简介 setting 设置 Prompt 提示 Sample response 回复样本 API request 接口请求 python接口请求示例 node.js接口请求示 ...

  7. 【书籍阅读】【Spring实战】二 装配Bean

    Spring配置的可选方案 ①自动化装配Bean:@Component ②Java代码装配Bean:@Bean ③XML装配Bean 自动化装配Bean Spring从两个角度实现对 @Compone ...

  8. 快速上手Linux核心命令(一):核心命令简介

    前言 众所周知,Linux在服务器中占用不可替代的位置.大多数互联网公司,服务器都是采用的Linux操作系统.而Linux是一个主要通过命令行来进行管理的操作系统.只有熟练掌握Linux核心命令,在使 ...

  9. gradle下载

    gradle下载:https://services.gradle.org/distributions/src.zip源码 .bin.zip安装文件.all.zip源码+安装文件 配置环境变量.

  10. 获取电脑的网络连接状态(五)WebClient

    网络连接判断,使用WebClient测试获取: 1 public static bool IsWebClientConnected() 2 { 3 try 4 { 5 using (var clien ...