分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility(续2篇-模板导出综合示例)

王朝学院·作者佚名  2016-08-28
窄屏简体版  字體: 小  |  中  |  大  |  超大  

自ExcelUtility类推出以来,经过项目中的实际使用与不断完善,现在又做了许多的优化并增加了许多的功能,本篇不再讲述原理,直接贴出示例代码以及相关的模板、结果图,以便大家快速掌握,另外这些示例说明我也已同步到GIT中,大家可以下载与学习,不足之处,敬请见谅,谢谢!

一、ExcelUtility类库操作说明(模板导出示例)

1.

/// <summary>

/// 测试方法:测试依据模板+DataTable来生成EXCEL

/// </summary>

[TestMethod]

public void TestExportToExcelWithTemplateByDataTable()

{

DataTable dt = GetDataTable();//获取数据

string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel.xlsx"; //获得EXCEL模板路径

SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器

PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();//实例化一个局部元素格式化器

partFormatterBuilder.AddFormatter("Title", "跨越IT学员");//将模板表格中Title的值设置为跨越IT学员

formatterContainers.AppendFormatterBuilder(partFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

CellFormatterBuilder cellFormatterBuilder = new CellFormatterBuilder();//实例化一个单元格格式化器

cellFormatterBuilder.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//将模板表格中rptdate的值设置为当前日期

formatterContainers.AppendFormatterBuilder(cellFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

//实例化一个表格格式化器,dt.Select()是将DataTable转换成DataRow[],name表示的模板表格中第一行第一个单元格要填充的数据参数名

TableFormatterBuilder<DataRow> tableFormatterBuilder = new TableFormatterBuilder<DataRow>(dt.Select(), "name");

tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>{

{"name",r=>r["Col1"]},//将模板表格中name对应DataTable中的列Col1

{"sex",r=>r["Col2"]},//将模板表格中sex对应DataTable中的列Col2

{"km",r=>r["Col3"]},//将模板表格中km对应DataTable中的列Col3

{"score",r=>r["Col4"]},//将模板表格中score对应DataTable中的列Col4

{"result",r=>r["Col5"]}//将模板表格中result对应DataTable中的列Co5

});

formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "table", formatterContainers);

Assert.IsTrue(File.Exists(excelPath));

}

模板如下:

[flash=500,400]http://s1.knowsky.com/20160211/fwxs3lavfym17.png[/flash]

导出结果如下:

[flash=500,400]http://s1.knowsky.com/20160211/2oausn3lsj417.png[/flash]

2.

/// <summary>

/// 测试方法:测试依据模板+List来生成EXCEL

/// </summary>

[TestMethod]

public void TestExportToExcelWithTemplateByList()

{

List<Student> studentList = GetStudentList();//获取数据

string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel.xlsx"; //获得EXCEL模板路径

SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器

PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();//实例化一个局部元素格式化器

partFormatterBuilder.AddFormatter("Title", "跨越IT学员");//将模板表格中Title的值设置为跨越IT学员

formatterContainers.AppendFormatterBuilder(partFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

CellFormatterBuilder cellFormatterBuilder = new CellFormatterBuilder();//实例化一个单元格格式化器

cellFormatterBuilder.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//将模板表格中rptdate的值设置为当前日期

formatterContainers.AppendFormatterBuilder(cellFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

//实例化一个表格格式化器,studentList本身就是可枚举的无需转换,name表示的模板表格中第一行第一个单元格要填充的数据参数名

TableFormatterBuilder<Student> tableFormatterBuilder = new TableFormatterBuilder<Student>(studentList, "name");

tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<Student, object>>{

{"name",r=>r.Name},//将模板表格中name对应Student对象中的属性Name

{"sex",r=>r.Sex},//将模板表格中sex对应Student对象中的属性Sex

{"km",r=>r.KM},//将模板表格中km对应Student对象中的属性KM

{"score",r=>r.Score},//将模板表格中score对应Student对象中的属性Score

{"result",r=>r.Result}//将模板表格中result对应Student对象中的属性Result

});

formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);

string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "table", formatterContainers);

Assert.IsTrue(File.Exists(excelPath));

}

模板同上一个模板

导出结果如下:

[flash=500,400]http://s1.knowsky.com/20160211/uvrbb5xxu4j18.png[/flash]

3.

/// <summary>

/// 测试方法:测试依据模板+DataTable来生成多表格EXCEL(注意:由于ExcelReport框架限制,目前仅支持模板文件格式为:xls)

/// </summary>

[TestMethod]

public void TestExportToRepeaterExcelWithTemplateByDataTable()

{

DataTable dt = GetDataTable();//获取数据

string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel2.xls"; //获得EXCEL模板路径

SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器

//实例化一个可重复表格格式化器,dt.Select()是将DataTable转换成DataRow[],rpt_begin表示的模板表格开始位置参数名,rpt_end表示的模板表格结束位置参数名

RepeaterFormatterBuilder<DataRow> tableFormatterBuilder = new RepeaterFormatterBuilder<DataRow>(dt.Select(), "rpt_begin", "rpt_end");

tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>{

{"sex",r=>r["Col2"]},//将模板表格中sex对应DataTable中的列Col2

{"km",r=>r["Col3"]},//将模板表格中km对应DataTable中的列Col3

{"score",r=>r["Col4"]},//将模板表格中score对应DataTable中的列Col4

{"result",r=>r["Col5"]}//将模板表格中result对应DataTable中的列Co5

});

PartFormatterBuilder<DataRow> partFormatterBuilder2 = new PartFormatterBuilder<DataRow>();//实例化一个可嵌套的局部元素格式化器

partFormatterBuilder2.AddFormatter("name", r => r["Col1"]);//将模板表格中name对应DataTable中的列Col1

tableFormatterBuilder.AppendFormatterBuilder(partFormatterBuilder2);//添加到可重复表格格式化器中,作为其子格式化器

CellFormatterBuilder<DataRow> cellFormatterBuilder = new CellFormatterBuilder<DataRow>();//实例化一个可嵌套的单元格格式化器

cellFormatterBuilder.AddFormatter("rptdate", r => DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//将模板表格中rptdate的值设置为当前日期

tableFormatterBuilder.AppendFormatterBuilder(cellFormatterBuilder);//添加到可重复表格格式化器中,作为其子格式化器

formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "multtable", formatterContainers);

Assert.IsTrue(File.Exists(excelPath));

}

模板如下:

[flash=500,400]http://s1.knowsky.com/20160211/jkgq2plfqko18.png[/flash]

导出结果如下:

[flash=500,400]http://s1.knowsky.com/20160211/0ukutm1cxvw18.png[/flash]

4.

/// <summary>

/// 测试方法:测试依据复杂模板(含固定表格,可重复表格)+DataTable来生成EXCEL (注意:由于ExcelReport框架限制,目前仅支持模板文件格式为:xls)

/// </summary>

[TestMethod]

public void TestExportToExcelWithTemplateByList2()

{

var schoolLevelList = SchoolLevel.GetList();

var classList = ClassInfo.GetList();

string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/mb.xls"; //获得EXCEL模板路径

SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器

PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();

partFormatterBuilder.AddFormatter("school", "跨越小学");

formatterContainers.AppendFormatterBuilder(partFormatterBuilder);

TableFormatterBuilder<SchoolLevel> tableFormatterBuilder = new TableFormatterBuilder<SchoolLevel>(schoolLevelList, "lv");//实例化一个表格格式化器

tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<SchoolLevel, object>>

{

{"lv",r=>r.LevelName}, //模板参数与数据源SchoolLevel属性对应关系,下同

{"clscount",r=>r.ClassCount},

{"lvmaster",r=>r.Master}

});

formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

RepeaterFormatterBuilder<ClassInfo> repeaterFormatterBuilder = new RepeaterFormatterBuilder<ClassInfo>(classList, "lv_begin", "lv_end");//实例化一个可重复表格格式化器

repeaterFormatterBuilder.AddFormatters(new Dictionary<string, Func<ClassInfo, object>> {

{"class",r=>r.ClassName}, //模板参数与数据源ClassInfo属性对应关系,下同

{"stucount",r=>r.StudentCount},

{"clsmaster",r=>r.Master},

{"lvitem",r=>r.LevelName}

});

formatterContainers.AppendFormatterBuilder(repeaterFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "school", formatterContainers);

Assert.IsTrue(File.Exists(excelPath));

}

模板如下:

[flash=500,400]http://s1.knowsky.com/20160211/khitn1f3kek18.png[/flash]

导出结果如下:

[flash=500,400]http://s1.knowsky.com/20160211/dsiriet1nau18.png[/flash]

5.

/// <summary>

/// 测试方法:测试依据复杂模板(含固定表格,可重复表格中嵌套表格)+DataTable来生成EXCEL (注意:由于ExcelReport框架限制,目前仅支持模板文件格式为:xls)

/// </summary>

[TestMethod]

public void TestExportToExcelWithTemplateByList3()

{

var schoolLevelList = SchoolLevel.GetList();

var classList = ClassInfo.GetListWithLevels();

string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/mb1.xls"; //获得EXCEL模板路径

SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器

PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();

partFormatterBuilder.AddFormatter("school", "跨越小学");

formatterContainers.AppendFormatterBuilder(partFormatterBuilder);

TableFormatterBuilder<SchoolLevel> tableFormatterBuilder = new TableFormatterBuilder<SchoolLevel>(schoolLevelList, "lv");//实例化一个表格格式化器

tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<SchoolLevel, object>>

{

{"lv",r=>r.LevelName}, //模板参数与数据源SchoolLevel属性对应关系,下同

{"clscount",r=>r.ClassCount},

{"lvmaster",r=>r.Master}

});

formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

RepeaterFormatterBuilder<KeyValuePair<string, List<ClassInfo>>> repeaterFormatterBuilder = new RepeaterFormatterBuilder<KeyValuePair<string, List<ClassInfo>>>(classList, "lv_begin", "lv_end");

repeaterFormatterBuilder.AddFormatter("lvitem",r=>r.Key);

TableFormatterBuilder<KeyValuePair<string, List<ClassInfo>>,ClassInfo> tableFormatterBuilder2=new TableFormatterBuilder<KeyValuePair<string, List<ClassInfo>>,ClassInfo>(r=>r.Value,"class");

tableFormatterBuilder2.AddFormatter("class",r=>r.ClassName);

tableFormatterBuilder2.AddFormatter("stucount",r=>r.StudentCount);

tableFormatterBuilder2.AddFormatter("clsmaster",r=>r.Master);

repeaterFormatterBuilder.AppendFormatterBuilder(tableFormatterBuilder2);

formatterContainers.AppendFormatterBuilder(repeaterFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "school", formatterContainers);

Assert.IsTrue(File.Exists(excelPath));

}

模板如下:

[flash=500,400]http://s1.knowsky.com/20160211/2wuqdsk114y18.png[/flash]

导出结果如下:

[flash=500,400]http://s1.knowsky.com/20160211/ydmim1wwgzc18.png[/flash]

6.

/// <summary>

/// 测试方法:测试依据复杂模板(多工作薄,且含固定表格,可重复表格)+DataSet来生成EXCEL,只支持XLS

/// </summary>

[TestMethod]

public void TestExportToExcelWithTemplateByDataSet()

{

var ds = GetDataSet();

string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/mb2.xls"; //获得EXCEL模板路径

Dictionary<string, SheetFormatterContainer> formatterContainerDic = new Dictionary<string, SheetFormatterContainer>(); //实例化一个模板数据格式化容器数组,包含两个SheetFormatterContainer用于格式化两个工作薄

#region 创建第一个工作薄格式化容器,并设置相关参数对应关系

SheetFormatterContainer formatterContainer1 = new SheetFormatterContainer();

PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();

partFormatterBuilder.AddFormatter("school", "跨越小学");

formatterContainer1.AppendFormatterBuilder(partFormatterBuilder);

TableFormatterBuilder<DataRow> tableFormatterBuilder = new TableFormatterBuilder<DataRow>(ds.Tables[0].Select(), "lv");//实例化一个表格格式化器

tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>

{

{"lv",r=>r["Col1"]}, //模板参数与数据源DataTable属性对应关系,下同

{"clscount",r=>r["Col2"]},

{"lvmaster",r=>r["Col3"]}

});

formatterContainer1.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

RepeaterFormatterBuilder<DataRow> repeaterFormatterBuilder = new RepeaterFormatterBuilder<DataRow>(ds.Tables[1].Select(), "lv_begin", "lv_end");//实例化一个可重复表格格式化器

repeaterFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>> {

{"class",r=>r["Col1"]}, //模板参数与数据源ClassInfo属性对应关系,下同

{"stucount",r=>r["Col2"]},

{"clsmaster",r=>r["Col3"]},

{"lvitem",r=>r["Col4"]}

});

formatterContainer1.AppendFormatterBuilder(repeaterFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

formatterContainerDic.Add("table1", formatterContainer1);//添加到工作薄格式容器数组中,注意此处的Key值为模板上工作薄的名称,此处即为:table1

#endregion

#region 创建第二个工作薄格式化容器,并设置相关参数对应关系

SheetFormatterContainer formatterContainer2 = new SheetFormatterContainer(); //实例化一个模板数据格式化容器

PartFormatterBuilder partFormatterBuilder2 = new PartFormatterBuilder();//实例化一个局部元素格式化器

partFormatterBuilder2.AddFormatter("Title", "跨越IT学员");//将模板表格中Title的值设置为跨越IT学员

formatterContainer2.AppendFormatterBuilder(partFormatterBuilder2);//添加到工作薄格式容器中,注意只有添加进去了才会生效

CellFormatterBuilder cellFormatterBuilder2 = new CellFormatterBuilder();//实例化一个单元格格式化器

cellFormatterBuilder2.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//将模板表格中rptdate的值设置为当前日期

formatterContainer2.AppendFormatterBuilder(cellFormatterBuilder2);//添加到工作薄格式容器中,注意只有添加进去了才会生效

//实例化一个表格格式化器,dt.Select()是将DataTable转换成DataRow[],name表示的模板表格中第一行第一个单元格要填充的数据参数名

TableFormatterBuilder<DataRow> tableFormatterBuilder2 = new TableFormatterBuilder<DataRow>(ds.Tables[2].Select(), "name");

tableFormatterBuilder2.AddFormatters(new Dictionary<string, Func<DataRow, object>>{

{"name",r=>r["Col1"]},//将模板表格中name对应DataTable中的列Col1

{"sex",r=>r["Col2"]},//将模板表格中sex对应DataTable中的列Col2

{"km",r=>r["Col3"]},//将模板表格中km对应DataTable中的列Col3

{"score",r=>r["Col4"]},//将模板表格中score对应DataTable中的列Col4

{"result",r=>r["Col5"]}//将模板表格中result对应DataTable中的列Co5

});

formatterContainer2.AppendFormatterBuilder(tableFormatterBuilder2);//添加到工作薄格式容器中,注意只有添加进去了才会生效

formatterContainerDic.Add("table2", formatterContainer2);//添加到工作薄格式容器数组中,注意此处的Key值为模板上工作薄的名称,此处即为:table2

#endregion

string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, formatterContainerDic);

Assert.IsTrue(File.Exists(excelPath));

}

模板如下:

[flash=500,400]http://s1.knowsky.com/20160211/1cvz1says3118.png[/flash] [flash=500,400]http://s1.knowsky.com/20160211/rkpg03dfk2518.png[/flash]

导出结果如下:

[flash=500,400]http://s1.knowsky.com/20160211/trxbifjodcc19.png[/flash] [flash=500,400]http://s1.knowsky.com/20160211/ji21q5d3bhl19.png[/flash]

二、ExcelUtility类库操作说明(嵌入图片示例)

一、 制作模板(含图片)

1.制作模板的文件格式需为兼容格式,即:xls或xlt;

2.模板变量(或称为占位符)定义与之前相同,即:$[变量名];

3.图片变量定义如下:

a)绘制一个图形,图形形状尽可能的与要显示的图片相同,比如:印章,则可绘制一个圆形;

b)图形必需是透明背景,边框可要可不要,建议留着,这样后续调整比较方便,如下图中的蓝色透明背景圆形:

[flash=500,400]http://s1.knowsky.com/20160211/11ogh3jmkjm19.png[/flash]

c)图形大小尽可能与要显示的图片大小相同,如下图示:

[flash=500,400]http://s1.knowsky.com/20160211/kjwszziizwf19.png[/flash]

由于EXCEL上大小默认采用厘米,而图片一般采用像素,所以需要自己换算一下像素对应的厘米数(也可将EXCEL计算单位设为像素,方法自行网上查找);也可网上下载单位转换工具

另外图形属性建议设置成如下图:

[flash=500,400]http://s1.knowsky.com/20160211/xvnvsskzpxq19.png[/flash]

温馨提示:图形形状、属性若未设置一般不影响导出效果,但不排除其它异常情况,图形大小是一定要设置,且尽可能与要显示图形大小(高、宽)相同,否则有可能造成导出变形

代码示例:

/// <summary>

/// 测试方法:测试依据模板+DataTable+图片来生成包含图片的EXCEL,只支持XLS

/// </summary>

[TestMethod]

public void TestInsertPic()

{

DataTable dt = GetDataTable();//获取数据

string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel.xls"; //获得EXCEL模板路径

SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器

PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();//实例化一个局部元素格式化器

partFormatterBuilder.AddFormatter("Title", "跨越IT学员");//将模板表格中Title的值设置为跨越IT学员d

formatterContainers.AppendFormatterBuilder(partFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

CellFormatterBuilder cellFormatterBuilder = new CellFormatterBuilder();//实例化一个单元格格式化器

cellFormatterBuilder.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//将模板表格中rptdate的值设置为当前日期

formatterContainers.AppendFormatterBuilder(cellFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

//实例化一个表格格式化器,dt.Select()是将DataTable转换成DataRow[],name表示的模板表格中第一行第一个单元格要填充的数据参数名

TableFormatterBuilder<DataRow> tableFormatterBuilder = new TableFormatterBuilder<DataRow>(dt.Select(), "name");

tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>{

{"name",r=>r["Col1"]},//将模板表格中name对应DataTable中的列Col1

{"sex",r=>r["Col2"]},//将模板表格中sex对应DataTable中的列Col2

{"km",r=>r["Col3"]},//将模板表格中km对应DataTable中的列Col3

{"score",r=>r["Col4"]},//将模板表格中score对应DataTable中的列Col4

{"result",r=>r["Col5"]}//将模板表格中result对应DataTable中的列Co5

});

formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效

string picPath = AppDomain.CurrentDomain.BaseDirectory + "\\tz.png";//图片路径

PictureWithShapeFormatterBuilder pictureBuilder = new PictureWithShapeFormatterBuilder();//实例化一个图片关联图形格式化器

//pictureBuilder.AddFormatter(picPath);//当sheet中只有一个图形时,我们可以省略指定区域,那么默认就是把整个工作薄区域当成一个寻找图形区域,若sheet中包含多个,则应指定区域,替换成如下语句

pictureBuilder.AddFormatter(picPath,5,60000, 0, 3, false);//第一个参数为图片路径,中间4个参数为数字型指定图形寻找的工作薄区域(行索引,列索引,索引从0开始计),最后一个为是否自适应大小,一般不建议使用,除非压缩图片

formatterContainers.AppendFormatterBuilder(pictureBuilder);

string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "table", formatterContainers);

Assert.IsTrue(File.Exists(excelPath));

}

模板如下:

[flash=500,400]http://s1.knowsky.com/20160211/evac3y4f3ba19.png[/flash]

注意图片若需要为透明背景格式,则必需使用PNG格式,NPOI支持的图片主要格式有:PNG,JPG

导出结果如下:

[flash=500,400]http://s1.knowsky.com/20160211/vp3vuodh54g19.png[/flash]

温馨提示:

pictureBuilder.AddFormatter(picPath);//当sheet中只有一个图形时,我们可以省略指定区域,那么默认就是把整个工作薄区域当成一个寻找图形区域,若sheet中包含多个,则应指定区域,替换成如下语句

pictureBuilder.AddFormatter(picPath,5,60000, 0, 3, false);//第一个参数为图片路径,中间4个参数为数字型指定图形寻找的工作薄区域(行索引(起止),列索引(起止),索引从0开始计),最后一个为是否自适应大小,一般不建议使用,除非压缩图片

如果图形可能随单元格进行位置调整,那么在指定图形区域时需注意,如果图形会随单元格下移,那么结束行索引(MinRow)就需要指定一个可能的最大值或不指定,如果图形会随单元格右移,那么结束列索引(MinColumn)就需要指定一个可能的最大值或不指定,如果存在多个图形区域,则上述情况都必需给定具体值(可能的最大值),以免造成区域交叉,从而导致图片显示不正确,如下示例:

//图形可能下移,可能右移,那么将结束行设为可能最大值:60000,结束列设为可能最大值:255

pictureBuilder.AddFormatter(picPath, 5, 60000, 0, 255, false);

//此处只指定开始行与开始列,与上面差不多,但建议使用上面的用法

pictureBuilder.AddFormatter(new PictureWithShapeInfo(picPath, new SheetRange() {MinRow=5,MinColumn=0 },false));

特别说明:

1.本类库是基于NPOI+ExcelReport,所有功能凡我的类库能够实现的,NPOI与ExcelReport都可以实现,只是用法及复杂程度不同而矣,我封装的目的就是为了降低大家的学习难度,提高使用效率,免费且开源,源代码同步更新至开源社区的GIT目录中,具体地址请看我该系列之前的文章有列出,在此就不再说明。

2.上述图片关联图形显示功能我是在ExcelReport基础上增加了一个PictureWithShapeFormatter类及其相关的类:PictureWithShapeInfo、SheetRange,因没有关联GIT,所以是在本地更新的,这几个类的代码如下:

PictureWithShapeFormatter:

using NPOI.Extend;

using NPOI.HSSF.UserModel;

using NPOI.SS.UserModel;

using NPOI.XSSF.UserModel;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace ExcelReport

{

public class PictureWithShapeFormatter : ElementFormatter

{PRivate PictureWithShapeInfo PictureInfo = null;

public PictureWithShapeFormatter(PictureWithShapeInfo pictureInfo)

{

this.PictureInfo = pictureInfo;

}

public override void Format(SheetAdapter sheetAdapter)

{

var sheet = sheetAdapter.CurrentSheet;

var shapes = PictureInfo.GetShapes(sheet);

bool isCompatible = false;

if (sheet is HSSFSheet)

{

isCompatible = true;

}

if (shapes == null || shapes.Count <= 0)

{

throw new Exception(string.Format("未能获取到工作薄[{0}]指定区域的图形对象列表!", sheet.SheetName));

}

byte[] bytes = System.IO.File.ReadAllBytes(PictureInfo.FilePath);

int pictureIdx = -1;

IDrawing drawing = null;

IClientAnchor anchor = null;

if (isCompatible)

{

var shape = shapes[0] as HSSFShape;

anchor = shape.Anchor as IClientAnchor;

drawing = shape.Patriarch;

shape.LineStyle = LineStyle.None;

}

else

{

var shape = shapes[0] as XSSFShape;

anchor = shape.GetAnchor() as IClientAnchor;

drawing = shape.GetDrawing();

shape.LineStyle = LineStyle.None;

}

pictureIdx = sheet.Workbook.AddPicture(bytes, PictureInfo.PictureType);

var picture = drawing.CreatePicture(anchor, pictureIdx);

if (PictureInfo.AutoSize)

{

picture.Resize();

}

}

}

}

PictureWithShapeInfo、SheetRange:

using NPOI.SS.UserModel;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

using NPOI.HSSF.UserModel;

using NPOI.XSSF.UserModel;

using NPOI.Extend;

namespace ExcelReport

{

/// <summary>

/// 图片关联图形信息

/// 作者:Zuowenjun

/// </summary>

public class PictureWithShapeInfo

{

private SheetRange _SheetRange = new SheetRange();

public string FilePath { get; set; }

public PictureType PictureType { get; set; }

public SheetRange ShapeRange

{

get { return _SheetRange; }

set

{

if (value != null)

{

_SheetRange = value;

}

}

}

public bool AutoSize { get; set; }

public PictureWithShapeInfo()

{ }

public PictureWithShapeInfo(string filePath, SheetRange shapeRange = null, bool autoSize = false)

{

this.FilePath = filePath;

this.ShapeRange = shapeRange;

this.AutoSize = autoSize;

this.PictureType = GetPictureType(filePath);

}

public List<object> GetShapes(ISheet sheet)

{

List<object> shapeAllList = new List<object>();

var shapeContainer = sheet.DrawingPatriarch;

if (sheet is HSSFSheet)

{

var shapeContainerHSSF = sheet.DrawingPatriarch as HSSFShapeContainer;

if (null != shapeContainer)

{

var shapeList = shapeContainerHSSF.Children;

foreach (var shape in shapeList)

{

if (shape is HSSFShape && shape.Anchor is HSSFClientAnchor)

{

var anchor = shape.Anchor as HSSFClientAnchor;

if (IsInternalOrIntersect(ShapeRange.MinRow, ShapeRange.MaxRow, ShapeRange.MinColumn, ShapeRange.MaxColumn, anchor.Row1, anchor.Row2, anchor.Col1, anchor.Col2, true))

{

shapeAllList.Add(shape);

}

}

}

}

}

else

{

var documentPartList = (sheet as XSSFSheet).GetRelations();

foreach (var documentPart in documentPartList)

{

if (documentPart is XSSFDrawing)

{

var drawing = (XSSFDrawing)documentPart;

var shapeList = drawing.GetShapes();

foreach (var shape in shapeList)

{

var anchorResult = shape.GetAnchor();

if (shape is XSSFShape && anchorResult is XSSFClientAnchor)

{

var anchor = anchorResult as XSSFClientAnchor;

if (IsInternalOrIntersect(ShapeRange.MinRow, ShapeRange.MaxRow, ShapeRange.MinColumn, ShapeRange.MaxColumn, anchor.Row1, anchor.Row2, anchor.Col1, anchor.Col2, true))

{

shapeAllList.Add(shape);

}

}

}

}

}

}

return shapeAllList;

}

private PictureType GetPictureType(string filePath)

{

string ext = Path.GetExtension(filePath).ToUpper();

switch (ext)

{

case ".JPG": { return PictureType.JPEG; }

case ".PNG": { return PictureType.PNG; }

default: { return PictureType.None; }

}

}

private bool IsInternalOrIntersect(int? rangeMinRow, int? rangeMaxRow, int? rangeMinCol, int? rangeMaxCol,

int pictureMinRow, int pictureMaxRow, int pictureMinCol, int pictureMaxCol, bool onlyInternal)

{

int _rangeMinRow = rangeMinRow ?? pictureMinRow;

int _rangeMaxRow = rangeMaxRow ?? pictureMaxRow;

int _rangeMinCol = rangeMinCol ?? pictureMinCol;

int _rangeMaxCol = rangeMaxCol ?? pictureMaxCol;

if (onlyInternal)

{

return (_rangeMinRow <= pictureMinRow && _rangeMaxRow >= pictureMaxRow &&

_rangeMinCol <= pictureMinCol && _rangeMaxCol >= pictureMaxCol);

}

else

{

return ((Math.Abs(_rangeMaxRow - _rangeMinRow) + Math.Abs(pictureMaxRow - pictureMinRow) >= Math.Abs(_rangeMaxRow + _rangeMinRow - pictureMaxRow - pictureMinRow)) &&

(Math.Abs(_rangeMaxCol - _rangeMinCol) + Math.Abs(pictureMaxCol - pictureMinCol) >= Math.Abs(_rangeMaxCol + _rangeMinCol - pictureMaxCol - pictureMinCol)));

}

}

}

/// <summary>

/// 工作薄区域

/// 作者:Zuowenjun

/// </summary>

public class SheetRange

{

public int? MinRow { get; set; }

public int? MaxRow { get; set; }

public int? MinColumn { get; set; }

public int? MaxColumn { get; set; }

public SheetRange()

{ }

public SheetRange(int minRow, int maxRow, int minColumn, int maxColumn)

{

this.MinRow = minRow;

this.MaxRow = maxRow;

this.MinColumn = minColumn;

this.MaxColumn = maxColumn;

}

public override bool Equals(object obj)

{

bool equalResult = false;

equalResult = base.Equals(obj);

if (!equalResult)

{

var otherSheetRange = obj as SheetRange;

if (otherSheetRange != null)

{

equalResult = (this.MinRow <= otherSheetRange.MinRow && this.MaxRow >= otherSheetRange.MaxRow

&& this.MinColumn <= otherSheetRange.MinColumn && this.MaxColumn >= otherSheetRange.MaxColumn);

}

}

return equalResult;

}

public override int GetHashCode()

{

return this.ToString().GetHashCode();

}

public override string ToString()

{

return string.Format("MinRow:{0},MaxRow:{1},MinColumn:{2},MaxColumn:{3}", this.MinRow, this.MaxRow, this.MinColumn, this.MaxColumn);

}

}

}

分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility 其它相关文章链接:

分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility

分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续篇)

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航