本文章主要介紹報表的生成,基於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
另外,模板報表支持一些參數進行輔助使用,如下所示:
動態公式變量
另外,上面模板中看到&=&=C{r}*D{r}這樣的動態公式,用於對列的應用,動態公式支持下面的引用變量:
{2}, {-1} - 當前行的偏移位置
如果要彙總一些行列,可以使用&=&=Sum(C{r}:F{r})這樣的動態變量來實現。
那如果是對同一列,不同行的字段進行彙總呢?,那樣就更方便,不用這麼複雜了,你只要使用普通的彙總函數如=Sum(C3:C4)這樣的格式,就可以了,如果行動態增加,Excel會自動調整Sum函數裏面的行列引用了,可能最後輸出會變爲=Sum(C3:C11)這樣了。
彙總格式變量
可以通過group:normal/merge/repeat 來控制彙總合併等格式的輸出,如使用兩者的例子:
&=Employees.EmployeeID(group:normal,skip:1)
subtotalN函數
該函數是用來執行一系列彙總計算的函數,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