使用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(153, 204, 0);
                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, 0, 150);
                }
                wb.Worksheets[0].FreezePanes(1, 0, 1, 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(0, 0, 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報表內容進行進一步的實戰分析探討。

應讀者要求,放上一個操作例子:http://files.cnblogs.com/wuhuacong/TestAposeCell.rar

轉載自:http://www.cnblogs.com/wuhuacong/archive/2011/02/23/1962147.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章