分享我基於NPOI+ExcelReport實現的導入與導出EXCEL類庫:ExcelUtility (續2篇-模板導出綜合示例)

来源:http://www.cnblogs.com/zuowj/archive/2016/01/28/5165921.html
-Advertisement-
Play Games

自ExcelUtility類推出以來,經過項目中的實際使用與不斷完善,現在又做了許多的優化並增加了許多的功能,本篇不再講述原理,直接貼出示例代碼以及相關的模板、結果圖,以便大家快速掌握,另外這些示例說明我也已同步到GIT中,大家可以下載與學習,不足之處,敬請見諒,謝謝! 一、ExcelUtility


自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));
        }

模板如下:

導出結果如下:

 

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));

        }

模板同上一個模板

導出結果如下:

 

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));
        }

模板如下:

導出結果如下:

 

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));

        }

模板如下:

導出結果如下:

 

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));

        }

模板如下:

導出結果如下:

 

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));

        }

模板如下:

    

導出結果如下:

   

 

二、ExcelUtility類庫操作說明(嵌入圖片示例)

一、 製作模板(含圖片)
1. 製作模板的文件格式需為相容格式,即:xls或xlt;
2. 模板變數(或稱為占位符)定義與之前相同,即:$[變數名];
3. 圖片變數定義如下:
a) 繪製一個圖形,圖形形狀儘可能的與要顯示的圖片相同,比如:印章,則可繪製一個圓形;
b) 圖形必需是透明背景,邊框可要可不要,建議留著,這樣後續調整比較方便,如下圖中的藍色透明背景圓形:

c) 圖形大小儘可能與要顯示的圖片大小相同,如下圖示:

 

由於EXCEL上大小預設採用釐米,而圖片一般採用像素,所以需要自己換算一下像素對應的釐米數(也可將EXCEL計算單位設為像素,方法自行網上查找);也可網上下載單位轉換工具
另外圖形屬性建議設置成如下圖:

溫馨提示:圖形形狀、屬性若未設置一般不影響導出效果,但不排除其它異常情況,圖形大小是一定要設置,且儘可能與要顯示圖形大小(高、寬)相同,否則有可能造成導出變形

代碼示例:

    /// <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));
        }

模板如下:

註意圖片若需要為透明背景格式,則必需使用PNG格式,NPOI支持的圖片主要格式有:PNG,JPG

導出結果如下:

溫馨提示:
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 (續篇)

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 不知道有沒有朋友像我一樣會遇到這樣一個問題: 在網上購買 .NET 空間,由於虛擬主機的限制,你並不能把某個目錄設為一個獨立的應用,或者一些價格比較高的空間,雖然可以設置,但數量也是有限的。這個問題導致了在給網站擴展獨立功能的時候,比較被動,或者想在一個網站下跑幾個不同功能的應用,也很麻煩。 不過,
  • 一列數的規則如下: 1、1、2、3、5、8、13、21、34...... 求第30位數是多少, 用遞歸演算法實現。 代碼: public class MainClass { public static void Main() { Console.WriteLine(Foo(30)); } public
  • 在寫一個客戶的B/S結構應用程式時,突然發現一個技巧,不知道是否是MS的一個BUG,給相關的有研究的朋友原先考慮寫一個檢查Session的類,Session失效後,必須轉向登陸頁面,可每一個調用該類的頁面,在不同的WEB路徑下,所以轉到登陸頁面的URL都不同,每個頁面都要調用和設置登陸頁面路徑,所以
  • 在TextBox控制項中使用快捷鍵,一般要求按下快捷鍵立刻產生效果,KeyUp事件顯然不符合我們的要求,而KeyPress事件中不支持使用組合件,所以我們選用KeyDown事件,具體代碼實現如下: private void tBBefore_KeyDown(object sender, KeyEven...
  • 一、asp:Repeater <div class="bd"> <ul> <asp:Repeater ID="rept_slide" runat="server"> <ItemTemplate> <li><a href='<%#Eval("LinkUrl").ToString() %>' targe
  • 1.0 創建Attribute using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace LSUnion.Site.WebHelper { [AttributeUsag
  • .NET之死是JAVA引起的嗎?.NET為什麼會死?.NET之死預示著什麼?
  • 一.基礎篇 C#不像C++,他本身是沒有聯合Union的,但是可以通過手動控制結構體每個元素的位置來實現,這需要結合使用StructLayoutAttribute、LayoutKind以及FieldOffsetAttribute。使用它們的時候必須引用System.Runtime.InteropSe
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...