目录html
1 概要 1git
2 磨刀不误砍柴工——先学会Excel中的操做 2github
博客使用Word发博,发布后,排版会出现不少问题,敬请谅解。另外Word发博代码格式显示凌乱,所以相关代码均使用图片替代。可加群(.NET 1群:85318032)获取原始文档。 orm
好久没发博客了,由于实在是太忙了(请容许我找个借口)。最近沉淀了不少内容,固然不少都差很少忘记了,不过我仍是会在有时间的前提下逐步一一道来吧。最近作了一个批量下单的模板导出,由于订单中有商品大类和小类的概念,并且类型很是多,为了方便用户选择以及确保数据的合法性,所以级联选择势在必行。不过,在此以前,本人就算是在Excel中操做都不会设置下拉,跟别说级联下拉了,而且关于使用代码生成级联下拉这块,网上并无相关的能够值得借鉴的内容,可是不管如何,Excel小白仍是要挑战挑战的。折腾了一下午,总算搞定,并且顺便学会了Excel中的序列和级联。仍是挺有成就感的。鉴于网上这块有价值的内容很少,因而在此分享此内容以及相关核心代码。htm
官方博客:http://www.cnblogs.com/codelove/
相关开源库地址:https://github.com/xin-lai
交流QQ群(.NET 1群):85318032
交流QQ群(Magicodes开源库交流群):346487194
Nuget包地址:https://www.nuget.org/packages?q=magicodes
首先,咱们能够参考这个教程(来自百度经验):
http://jingyan.baidu.com/article/5553fa82035ce565a23934ba.html
这里有一点须要特别注意的,由于开发人员用的Excel版本都比较高,好比个人是2016,估计通常也是2013吧,特别坑爹的是,网上大部分教程是2010或者如下版本的,而在2013或以上版本微软将某个菜单的文字改了,以下图所示的地方:
这个有效性菜单你会发如今高版本没法找到,我找了半天,终于找到了:
就是这个图标!!!如今叫"数据验证"!!!
经过以上教程,咱们能够学会配置了Excel级联列表:
数据源以下:
名称管理以下:
级联效果以下:
搞定了Excel,咱们学到了如下几个概念:
其实这个级联的实现的思路颇有意思,经过INDIRECT获取到关联单元格的值,而后这个值就是关联列表的序列名称。
搞懂了以上理论,而后咱们再开车。没有理论,不少时候就是瞎折腾!因此老司机开车不能瞎开,得有理论。
其实用NPOI仍是用Aspose.Cells,这个都不要紧。毕竟咱们掌握了理论,咱们有理由相信,这两位都是好同志。在有RMB的前提下,咱们愿意支持商业的,没RMB,开源的也能玩得飞起。好了,至于为何选择NPOI,很简单,由于咱们没钱,并且不喜欢盗版。
如今我来讲说思路(思路是高于开发的,不少时候若是作一个东西没有思路,那就很容易"做死",在开发过程当中要有意识的培养本身的思路,一方面是思路的造成能够在不少场景迁移借鉴,另外一方面是既保障灵活性、扩展性和严谨性的前提下,又少走弯路。最后,思路是本身的,代码是靠抄的。):
NOPI操做Workbook和Sheet的代码网上不少,我这里就不过多搬运了,核心代码为:
HSSFWorkbook workbook = new HSSFWorkbook();//建立workbook
ISheet sheet = workbook.CreateSheet("sheet1");//建立sheet
IRow row = sheet.CreateRow(0);//添加行
row.CreateCell(0).SetCellValue("Test");//单元格写值
根据上面的代码,咱们根据咱们的业务逻辑很容易生成如下内容:
注意这个逻辑!必定要正确,并且对应上!
核心代码为:
IName range = workbook.CreateName();//建立名称
range.NameName = bigCategory.CategoryName;//设置名称
var colName = GetExcelColumnName(colIndex);//根据序号获取列名,具体代码见下文
range.RefersToFormula = string.Format("{0}!${3}${2}:${3}${1}",
sheetName,
smallList.Count.ToString(),
2,
colName);
//设置引用位置
//参数1为引用的Sheet名称
//参数2为行数(数据行数)
//参数3为起始行数(从第二行开始,忽略列头,列头是给咱们看的)
//参数4为列名(好比A、B、AA、AB这种)
获取列名的代码为:
/// <summary>
/// 获取Excel列名
/// </summary>
/// <param name="columnNumber">列的序号</param>
/// <returns></returns>
private string GetExcelColumnName(int columnNumber)
{
int dividend = columnNumber;
string columnName = String.Empty;
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (int)((dividend - modulo) / 26);
}
return columnName;
}
经过以上代码,就能够定义Excel中的名称了,对应如图所示:
基于咱们的理解,而后结合NPOI的API,咱们很快就能够写出一下代码了:
//定义Cell范围,参数1:起始行数,参数2:结束行数,参数3:起始列数,参数4:结束列数
CellRangeAddressList regions = new CellRangeAddressList(1, 65535, lastBigIndex, lastBigIndex);
//绑定序列地址
DVConstraint constraint = DVConstraint.CreateFormulaListConstraint("产品大类");
//定义数据验证
HSSFDataValidation dataValidate = new HSSFDataValidation(regions, constraint);
//添加数据验证
sheet.AddValidationData(dataValidate);
如上面代码所示,这里是设置大类的数据验证。如图:
效果:
设置级联的数据验证:
var smallColIndex = i - 1;
//与大类关联
var colName = GetExcelColumnName(lastBigIndex + 1);
//这里只设置了该列的500行,能够按本身的状况来写入
for (int j = 1; j <= 500; j++)
{
//定义Cell范围,参数1:起始行数,参数2:结束行数,参数3:起始列数,参数4:结束列数
//这里的范围是单个单元格,由于咱们的公式用到了具体的单元格地址
CellRangeAddressList regions = new CellRangeAddressList(j, j, smallColIndex, smallColIndex);
//使用INDIRECT函数,这里指定了具体地址
DVConstraint constraint = DVConstraint.CreateFormulaListConstraint(string.Format("INDIRECT(${0}${1})", colName, j + 1));
HSSFDataValidation dataValidate = new HSSFDataValidation(regions, constraint);
sheet.AddValidationData(dataValidate);
}
效果如图:
好了,整个导出的主要逻辑就是这些。理解了思想,再结合官方API就能够很快搞定了。
整个分享就到这里了,如此看来,Excel仍是大有可为的,不经过宏就能够作不少事情。并且Excel还能够直接链接外部数据源,包括OData服务等,有兴趣的小伙伴能够研究研究。
本次开车到此结束。