• 使用Aspose.Cell控件实现Excel高难度报表的生成(一)导出表格控件


    时光飞逝,生活、工作、业余研究总是在不停忙碌着,转眼快到月底,该月的博客文章任务未完,停顿回忆一下,总结一些经验以及好的东西出来,大家一起分享一下。本文章主要介绍报表的生成,基于Aspose.Cell控件的报表生成。谈到报表,估计大家都有所领悟以及个人的理解,总的来说,一般的报表生成,基本上是基于以下几种方式:一种是基于微软Excel内置的引擎来实现;一种是构造HTML格式的Excle报表;一种是基于控件的方式来处理,基于控件有很多种方式,个人认为比较有名的是Aspose.Cell(收费破解)和NPOI(开源)。

    而报表的表现方式大致可以分为两种:

    一种是通用的二维表导出的Excel格式,这种方式通过封装一个操作类,传递一个DataTable参数,把数据导出就可以了。这种报表特点是操作方便,通用,能应付一般常用的数据报表,如下所示;

     

    由于这种报表,一般是在一个数据表格中显示,通常的做法是把这个东西做成控件,一个可以解决分页问题,一个可以解决导出、打印问题等,如我的随笔文章《WinForm界面开发之“分页控件”》 介绍的解决办法。

    当然,也可以把导入导出Excel的操作封装成一个公用的辅助来调用,如我封装的Aspose.Cell的导入导出处理函数如下所示:

    代码
        public class AsposeExcelTools
        {

            
    public static bool DataTableToExcel(DataTable datatable, string filepath, out string error)
            {
                error 
    = "";
                
    try
                {
                    
    if (datatable == null)
                    {
                        error 
    = "DataTableToExcel:datatable 为空";
                        
    return false;
                    }

                    Aspose.Cells.Workbook workbook 
    = new Aspose.Cells.Workbook();
                    Aspose.Cells.Worksheet sheet 
    = workbook.Worksheets[0];
                    Aspose.Cells.Cells cells 
    = sheet.Cells;

                    
    int nRow = 0;
                    
    foreach (DataRow row in datatable.Rows)
                    {
                        nRow
    ++;
                        
    try
                        {
                            
    for (int i = 0; i < datatable.Columns.Count; i++)
                            {                           
                                
    if (row[i].GetType().ToString() == "System.Drawing.Bitmap")
                                {
                                    
    //------插入图片数据-------
                                    System.Drawing.Image image = (System.Drawing.Image)row[i];
                                    MemoryStream mstream 
    = new MemoryStream();
                                    image.Save(mstream, System.Drawing.Imaging.ImageFormat.Jpeg);
                                    sheet.Pictures.Add(nRow, i, mstream);
                                }
                                
    else
                                {
                                    cells[nRow, i].PutValue(row[i]);
                                }
                            }
                        }
                        
    catch (System.Exception e)
                        {
                            error 
    = error + " DataTableToExcel: " + e.Message;
                        }
                    }

                    workbook.Save(filepath);
                    
    return true;
                }
                
    catch (System.Exception e)
                {
                    error 
    = error + " DataTableToExcel: " + e.Message;
                    
    return false;
                }
            }

            
    public static bool DataTableToExcel2(DataTable datatable, string filepath, out string error)
            {
                error 
    = "";
                Aspose.Cells.Workbook wb 
    = new Aspose.Cells.Workbook();

                
    try
                {
                    
    if (datatable == null)
                    {
                        error 
    = "DataTableToExcel:datatable 为空";
                        
    return false;
                    }

                    
    //为单元格添加样式    
                    Aspose.Cells.Style style = wb.Styles[wb.Styles.Add()];
                    
    //设置居中
                    style.HorizontalAlignment = Aspose.Cells.TextAlignmentType.Center;
                    
    //设置背景颜色
                    style.ForegroundColor = System.Drawing.Color.FromArgb(1532040);
                    style.Pattern 
    = BackgroundType.Solid;
                    style.Font.IsBold 
    = true;

                    
    int rowIndex = 0;
                    
    for (int i = 0; i < datatable.Columns.Count; i++)
                    {
                        DataColumn col 
    = datatable.Columns[i];
                        
    string columnName = col.Caption ?? col.ColumnName;
                        wb.Worksheets[
    0].Cells[rowIndex, i].PutValue(columnName);
                        wb.Worksheets[
    0].Cells[rowIndex, i].Style = style;
                    }
                    rowIndex
    ++;

                    
    foreach (DataRow row in datatable.Rows)
                    {
                        
    for (int i = 0; i < datatable.Columns.Count; i++)
                        {
                            wb.Worksheets[
    0].Cells[rowIndex, i].PutValue(row[i].ToString());
                        }
                        rowIndex
    ++;
                    }

                    
    for (int k = 0; k < datatable.Columns.Count; k++)
                    {
                        wb.Worksheets[
    0].AutoFitColumn(k, 0150);
                    }
                    wb.Worksheets[
    0].FreezePanes(101, datatable.Columns.Count);
                    wb.Save(filepath);
                    
    return true;
                }
                
    catch (Exception e)
                {
                    error 
    = error + " DataTableToExcel: " + e.Message;
                    
    return false;
                }

            }

            
    /// <summary>
            
    /// Excel文件转换为DataTable.
            
    /// </summary>
            
    /// <param name="filepath">Excel文件的全路径</param>
            
    /// <param name="datatable">DataTable:返回值</param>
            
    /// <param name="error">错误信息:返回错误信息,没有错误返回""</param>
            
    /// <returns>true:函数正确执行 false:函数执行错误</returns>
            public static bool ExcelFileToDataTable(string filepath, out DataTable datatable, out string error)
            {
                error 
    = "";
                datatable 
    = null;
                
    try
                {
                    
    if (File.Exists(filepath) == false)
                    {
                        error 
    = "文件不存在";
                        datatable 
    = null;
                        
    return false;
                    }
                    Aspose.Cells.Workbook workbook 
    = new Aspose.Cells.Workbook();
                    workbook.Open(filepath);
                    Aspose.Cells.Worksheet worksheet 
    = workbook.Worksheets[0];
                    datatable 
    = worksheet.Cells.ExportDataTable(00, worksheet.Cells.MaxRow + 1, worksheet.Cells.MaxColumn + 1);
                    
    //-------------图片处理-------------
                    Aspose.Cells.Pictures pictures = worksheet.Pictures;
                    
    if (pictures.Count > 0)
                    {
                        
    string error2 = "";
                        
    if (InsertPicturesIntoDataTable(pictures, datatable, out datatable, out error2) == false)
                        {
                            error 
    = error + error2;
                        }
                    }
                    
    return true;
                }
                
    catch (System.Exception e)
                {
                    error 
    = e.Message;
                    
    return false;
                }

            }



            
    public static bool ExcelFileToLists(string filepath, out IList[] lists, out string error)
            {
                error 
    = "";
                lists 
    = null;
                DataTable datatable 
    = new DataTable();
                IList list 
    = new ArrayList();
                Pictures[] pictures;
                
    if (ExcelFileToDataTable(filepath, out datatable, out error) && GetPicturesFromExcelFile(filepath, out pictures, out error))
                {
                    lists 
    = new ArrayList[datatable.Rows.Count];
                    
    //------------DataTable转换成IList[]--------------
                    
    //数据
                    int nRow = 0;
                    
    foreach (DataRow row in datatable.Rows)
                    {
                        lists[nRow] 
    = new ArrayList(datatable.Columns.Count);
                        
    for (int i = 0; i <= datatable.Columns.Count - 1; i++)
                        {
                            lists[nRow].Add(row[i]);
                        }
                        nRow
    ++;
                    }
                    
    //图片
                    for (int i = 0; i < pictures.Length; i++)
                    {
                        
    foreach (Picture picture in pictures[i])
                        {
                            
    try
                            {
                                
    //----把图片转换成System.Drawing.Image----
                                
    //MemoryStream mstream = new MemoryStream();
                                
    //mstream.Write(picture.Data, 0, picture.Data.Length);
                                
    //System.Drawing.Image image = System.Drawing.Image.FromStream(mstream);
                                
    //----Image放入IList------
                                
    //图片有可能越界
                                if (picture.UpperLeftRow <= datatable.Rows.Count && picture.UpperLeftColumn <= datatable.Columns.Count)
                                {
                                    lists[picture.UpperLeftRow][picture.UpperLeftColumn] 
    = picture.Data;
                                }

                            }
                            
    catch (System.Exception e)
                            {
                                error 
    = error + e.Message;
                            }

                        }
                    }

                }
                
    else
                {

                    
    return false;
                }
                
    return true;
            }

            
    public static bool ListsToExcelFile(string filepath, IList[] lists, out string error)
            {
                error 
    = "";
                
    //----------Aspose变量初始化----------------
                Aspose.Cells.Workbook workbook = new Aspose.Cells.Workbook();
                Aspose.Cells.Worksheet sheet 
    = workbook.Worksheets[0];
                Aspose.Cells.Cells cells 
    = sheet.Cells;
                
    //-------------输入数据-------------
                int nRow = 0;
                sheet.Pictures.Clear();
                cells.Clear();
                
    foreach (IList list in lists)
                {

                    
    for (int i = 0; i <= list.Count - 1; i++)
                    {
                        
    try
                        {
                            System.Console.WriteLine(i.ToString() 
    + "  " + list[i].GetType());
                            
    if (list[i].GetType().ToString() == "System.Drawing.Bitmap")
                            {
                                
    //插入图片数据
                                System.Drawing.Image image = (System.Drawing.Image)list[i];

                                MemoryStream mstream 
    = new MemoryStream();

                                image.Save(mstream, System.Drawing.Imaging.ImageFormat.Jpeg);

                                sheet.Pictures.Add(nRow, i, mstream);
                            }
                            
    else
                            {
                                cells[nRow, i].PutValue(list[i]);
                            }
                        }
                        
    catch (System.Exception e)
                        {
                            error 
    = error + e.Message;
                        }

                    }

                    nRow
    ++;
                }
                
    //-------------保存-------------
                workbook.Save(filepath);

                
    return true;
            }

     

     

     这样封装了Aspose.Cell的操作,每次生成Excel文件或者导入Excel内容,就非常方便,只需要如下调用方式即可完成:

            private void button1_Click(object sender, EventArgs e)
            {
                DataTable dt 
    = CreateTable("测试1,测试2,Test1,Test2""testTable");
                
    for (int i = 0; i < 100; i++)
                {
                    DataRow dr 
    = dt.NewRow();
                    
    for (int j = 0; j < dt.Columns.Count; j++)
                    {
                        dr[j] 
    = i.ToString();
                    }
                    dt.Rows.Add(dr);
                }

                
    string outError = "";
                
    string fileName = @"C:\test.xls";
                AsposeExcelTools.DataTableToExcel2(dt, fileName, 
    out outError);


                
    if (!string.IsNullOrEmpty(outError))
                {
                    MessageBox.Show(outError);
                }
                
    else
                {
                    Process.Start(fileName);
                }
            }


            
    public DataTable CreateTable(string nameString, string tableName)
            {
                
    string[] nameArray = nameString.Split(new char[] { ','';' });
                List
    <string> nameList = new List<string>();
                
    foreach (string item in nameArray)
                {
                    
    if (!string.IsNullOrEmpty(item))
                    {
                        nameList.Add(item);
                    }
                }

                
    return CreateTable(nameList, tableName);
            }

     

    另外一种是以Excel文件作为模板,然后填入必要的内容,形成比较综合性,复杂性较高的报表,这种报表一般比较专业、比较规范好看,在一些特殊的场合,必须使用这些固定格式的报表,如下所示:

     

     或者这样的报表格式

     

     这些报表,基本上就是用到了变量、函数等的概念才能处理好这些数据,如上面的出库单,里面的成本中心、部门、库房编号等,这些通过变量绑定应该就可以了,而里面的列表,则可以通过集合绑定实现,Aspose.Cell控件功能非常强大,很好支持这些操作,下面一步步介绍该控件制作这类报表的实现代码。

    Aspose.Cell控件支持多种参数变量的绑定操作,如支持DataSet、Datatable、IList集合,实体类集合、类对象等。

                DataSet ds = LoadDataSet();//使用DataSet对象
                List<Customers> entity = GetCustomers();//使用实体类对象
                DataTable dt = GetCustomersTable();//使用DataTable对象

                
    //创建一个workbookdesigner对象
                WorkbookDesigner designer = new WorkbookDesigner();

                
    //制定报表模板
                string path = System.IO.Path.Combine(Application.StartupPath,"SmartMarkerDesigner.xls");
                designer.Open(path);

                
    //设置DataSet对象
                
    //designer.SetDataSource(ds);

                
    //设置实体类对象
                
    //designer.SetDataSource("Customers", entity);

                //设置Datatable对象
                designer.SetDataSource(dt);
                designer.SetDataSource(ds.Tables["Order Details"]);

                
    //设置变量对象
                designer.SetDataSource("Variable""Single Variable");
                
    //设置集合变量
                designer.SetDataSource("MultiVariable"new string[] { "Variable 1""Variable 2""Variable 3" });
                
    //设置集合变量
                designer.SetDataSource("MultiVariable2"new string[] { "Skip 1""Skip 2""Skip 3" });

                
    //根据数据源处理生成报表内容
                designer.Process();

                
    //保存Excel文件
                string fileToSave = System.IO.Path.Combine(Application.StartupPath, "SmartMarker.xls");
                
    if (File.Exists(fileToSave))
                {
                    File.Delete(fileToSave);
                }

                designer.Save(fileToSave, FileFormatType.Excel2003);
                //打开Excel文件
                Process.Start(fileToSave);

     

     以上的代码说明了改控件支持的各种参数变量,我们先看看报表的模板,然后看看报表的生成内容,对比一下就更直观了。

    报表1模板如下所示(其中通过引用集合的对象是通过&=来引用,对象的属性或者列名,通过如&=Customer.City方式引用,非常直观方便:

     报表1生成的效果如下所示(Customers可以使DataTable对象,也可以List<Customer>实体对象集合。

     

     

     报表2的模板如下所示,对象也可以通过&=[Order Detail]方式引用,另外模板支持一些参数,其中{r}为当行的变量,翻译到实际的报表可能就是C4*D4这样的格式了,其中两个&=表示动态公式引用,区别于普通的变量和字符,如&=&=C{r}*D{r}后者汇总函数&=&=Sum(C{r}:D{r})等等。

     

    报表2的生成效果如下所示 

     

     

     报表3的模板如下所示,这个报表模板使用了对象变量,对象变量引用方式如&=$Variable这样格式,比集合对象或者DataTable对象多了一个$符号,其中集合支持一些遍历参数,如Skip,Horiontal等等。

     

    报表3的生成效果如下所示  

     

    综上所述,模板报表的变量绑定方式有以下几种方式:

     &=DataSource.FieldName

    &=[Data Source].[Field Name]
    &=$VariableName
    &=$VariableArray
    &==DynamicFormula
    &=&=RepeatDynamicFormula

     

     另外,模板报表支持一些参数进行辅助使用,如下所示:

    noadd
    适应数据而不添加额外的行(不知道是不是这样表达)
     
    skip:n
    每行记录跳过的数量,n=1代表依次遍历N=2则跳一个遍历
     
    ascending:n / descending:n
    排序数据供. 如果n=1,那么该列就是排序的第一个关键字,例子: &=Table1.Field3(ascending:1)
     
    horizontal
    默认是上下垂直方式输出,如果设置为horizontal,则是横着输出内容,见上面的例子
     

    动态公式变量 

    另外,上面模板中看到&=&=C{r}*D{r}这样的动态公式,用于对列的应用,动态公式支持下面的引用变量:

    {r} - 当前行变量

    {2}, {-1} - 当前行的偏移位置 

     如果要汇总一些行列,可以使用&=&=Sum(C{r}:F{r})这样的动态变量来实现。

    那如果是对同一列,不同行的字段进行汇总呢?,那样就更方便,不用这么复杂了,你只要使用普通的汇总函数如=Sum(C3:C4)这样的格式,就可以了,如果行动态增加,Excel会自动调整Sum函数里面的行列引用了,可能最后输出会变为=Sum(C3:C11)这样了。 

     

    汇总格式变量

     可以通过group:normal/merge/repeat 来控制汇总合并等格式的输出,如使用两者的例子:

    &=Customers.CustomerID(group:merge)

    &=Employees.EmployeeID(group:normal,skip:1) 

    出来的报表如下所示: 

     

     

     

    subtotalN函数

    分别代表1=AVERAGE, 2=COUNT,3=COUNTA, 4=MAX, 5=MIN,...9=SUM等等 
    该函数是用来执行一系列汇总计算的函数,N从1~11subtotalN:Ref,其中Ref代表汇总的指定列

     

    例如,&=Products.Units(subtotal9:Products.ProductID) 表示基于Units列进行数据汇总统计,统计到ProductID上来。

    例如,&=Table1.ColumnD(subtotal9:Table1.ColumnA&Table1.ColumnB) ,则表示基于ColumnD列进行汇总统计,统计到ColumnA和ColumnB的分组条件上。

     

    本篇由于篇幅原因,介绍到这里,下篇继续探讨基于模板生成的报表内容,包括利用对象动态创建行列以及公式,使用Style等方面,并结合实际复杂的报表例子,对基于Aspose.Cell报表内容进行进一步的实战分析探讨。 

     

     应读者要求,放上一个操作例子:https://files.cnblogs.com/wuhuacong/TestAposeCell.rar 

  • 相关阅读:
    HTML5拖动画布/拖放
    随着通信和编程,它是一门艺术系列6(技术的情况)
    POJ 3652 &amp; ZOJ 2934 &amp; HDU 2721 Persistent Bits(数学 元)
    使用注解实现 bean 转 csv
    hdu4956 Poor Hanamichi
    教你如何赚你的第一桶金
    【Java 它 JVM】对象的创建过程
    c#控制台应用程序-“进入指定日期检查出星期几”
    迎接和书,这是一个很好的满足
    bloom filter与dawgdic(一种trie树)
  • 原文地址:https://www.cnblogs.com/xiaofengfeng/p/2706213.html
Copyright © 2020-2023  润新知