轉帖|其它|編輯:郝浩|2011-02-24 11:14:30.000|閱讀 1824 次
概述:本文章主要介紹報表的生成,基于Aspose.Cell控件的報表生成。談到報表,估計大家都有所領悟以及個人的理解,總的來說,一般的報表生成,基本上是基于以下幾種方式:一種是基于微軟Excel內置的引擎來實現;一種是構造HTML格式的Excle報表;一種是基于控件的方式來處理,基于控件有很多種方式,個人認為比較有名的是Aspose.Cell(收費破解)和NPOI(開源)。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
時光飛逝,生活、工作、業余研究總是在不停忙碌著,轉眼快到月底,該月的博客文章任務未完,停頓回憶一下,總結一些經驗以及好的東西出來,大家一起分享一下。本文章主要介紹報表的生成,基于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方式引用,非常直觀方便:
成的效果如下所示(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報表內容進行進一步的實戰分析探討。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:網絡轉載