Visual Studio.Net 自2001年2月問世以來,受到越來越多人的喜愛,C#做爲主力軍,集VB、Delphi的簡單和VC的簡煉與強大於一體,更是讓許多人愛不釋手,紛紛倒向它的懷抱。通常的軟件都要用到數據庫,數據庫中必然要用到報表,在Visual Studio.Net中自帶了一個水晶報表,雖然功能十分強大,但市面上相關資料非常缺乏,網上全面介紹其使用的文章也屈指可數。Excel是微軟公司辦公自動化套件中的一個軟件,主要是用來處理電子表格。Excel以其功能強大,界面友好等受到了許多用戶的歡迎,幾乎每一臺機器都安裝了它,因此,我們可以將數據導入Excel進行排版。
由於Excel的格式是封閉的,無法直接創建一個Excel文件然後來排版,只有藉助Com組件來完成,同樣,介紹用C#操作Excel的文章也就那麼幾篇,基本上都是告訴你如何新建一個Excel文件,然後,將數據寫入某單元格,最多再零星告訴你如何合併單元格,真正使用起來根本無法用C#做出漂亮報表。本文巧妙利用Excel的宏來自動排版,大大減少了工作量,而且可以隨時修改模板而無須修改程序,非常實用。
本人使用的是Office 2000,操作系統爲windows 2000 professinal,爲使問題簡單化,這裏不介紹數據庫的知識,我一個二維數組來代表一個數據庫中的表,我們的目的是將該數組放到Excel中,並排版成需要的格式,數組如下:
車牌號 類 型 品 牌 型 號 顏 色 附加費證號 車架號 浙KA3676 危險品 貨車 鐵風SZG9220YY 白 1110708900 022836 浙KA4109 危險品 貨車 解放CA4110P1K2 白 223132 010898 浙KA0001A 危險品 貨車 南明LSY9190WS 白 1110205458 0474636 浙KA0493 上普貨 貨車 解放LSY9190WS 白 1110255971 0094327 浙KA1045 普貨 貨車 解放LSY9171WCD 藍 1110391226 0516003 浙KA1313 普貨 貨車 解放9190WCD 藍 1110315027 0538701 浙KA1322 普貨 貨車 解放LSY9190WS 藍 24323332 0538716 浙KA1575 普貨 貨車 解放LSY9181WCD 藍 1110314149 0113018 浙KA1925 普貨 貨車 解放LSY9220WCD 藍 1110390626 00268729 浙KA2258 普貨 貨車 解放LSY9220WSP 藍 1110481542 00320
爲了在C#中使用Excel,我們要先做一點準備工作,通過查找(前提是你安裝Visual Studio.Net和Excel 2000),在你的計算機中找到TlbImp和Excel9.olb,將他們複製到一個文件夾中,在DOS窗口中執行 TlbImp Excel9.olb,這時會產生以下三個文件:Excel.dll、Office.dll和VBIDE.dll。
我們來完成兩項任務,一是按網上文章介紹的方法,增加將數據寫入一個Excel文件,也就是做一個簡單報表,二是用Excel創建一個文件,然後以此文件爲模板生成高級報表。
打開Visual Studio.Net,新建一個C#的windows應用程序,取名爲MyExcel。根據個人愛好,對窗口做一些美化工作,然後放兩個按鈕:btnNormal和btnAdvance,Caption分別爲“普通報表”和“高級報表”。
打開Visual Studio.Net,新建一個C#的windows應用程序,取名爲MyExcel。根據個人愛好,對窗口做一些美化工作,然後放兩個按鈕:btnNormal和btnAdvance,Caption分別爲“普通報表”和“高級報表”。
點“打開”按鈕,再點“確定”按鈕。
切換到代碼窗口中,在文件頭添加下面兩個引用:
using System.IO; using System.Reflection;
|
再添加一個二維數組來表示數據表:
private string [,] myData=
{
{"車牌號","類型","品 牌","型 號","顏 色","附加費證號","車架號"},
{"浙KA3676","危險品","貨車","鐵風SZG9220YY","白","1110708900","022836"},
{"浙KA4109","危險品","貨車","解放CA4110P1K2","白","223132","010898"},
{"浙KA0001A","危險品","貨車","南明LSY9190WS","白","1110205458","0474636"},
{"浙KA0493","上普貨","貨車","解放LSY9190WS","白","1110255971","0094327"},
{"浙KA1045","普貨","貨車","解放LSY9171WCD","藍","1110391226","0516003"},
{"浙KA1313","普貨","貨車","解放9190WCD","藍","1110315027","0538701"},
{"浙KA1322","普貨","貨車","解放LSY9190WS","藍","24323332","0538716"},
{"浙KA1575","普貨","貨車","解放LSY9181WCD","藍","1110314149","0113018"},
{"浙KA1925","普貨","貨車","解放LSY9220WCD","藍","1110390626","00268729"},
{"浙KA2258","普貨","貨車","解放LSY9220WSP","藍","111048152","00320"}
};
|
切換回設計窗口,雙擊“普通報表”按鈕,設計普通報表,代碼如下:
private void btnNormal_Click(object sender, System.EventArgs e) { //創建一個Excel文件
Excel.Application myExcel = new Excel.Application ( ) ;
myExcel.Application.Workbooks.Add ( true ) ;
//讓Excel文件可見
myExcel.Visible=true;
//第一行爲報表名稱
myExcel.Cells[1,4]="普通報表";
//逐行寫入數據,
for(int i=0;i<11;i++) { for(int j=0;j<7;j++) { //以單引號開頭,表示該單元格爲純文本 myExcel.Cells[2+i,1+j]="’"+myData[i,j]; } } }
|
說明一下,Cells[2,1]指第2行第1個單元格,是以1爲基準的,而在C#中的數組是以0爲基準的,另外,我們還發現,對於編號之類的數據,實際是文本,而Excel將它認成了數字,由於太長,自動換成了科學計數,這不是我們要求的,在Excel中,如果某單元格以單引號“’”開頭,表示該單元格爲純文本,因此,我們在每個單元格前面加單引號。
運行結果如下:
可以看出,該報表非常簡陋,標題行沒有合併局,字體大小也不合適,連表格線都沒有。當然,我們可以寫代碼來設置單元格字體、大小等等工作,這類技巧網上很多,但如果真要用C#來完成,是一件非常難的事情,還有個辦法就是將想要的操作錄製成宏,研究一下宏代碼,但宏是用VBA寫的,要轉換成果C#可不是件容易的事情。
第一種辦法不是本文的重點,就到此爲止
下面進行高級報表設計,該方法的原理爲:首先打開Excel,按照要求排好版,保存爲一個文件做爲模板,然後在C#中將該文件複製爲一個新文件,在指定位置填入數據就可以了,爲了添加表格線,我們錄製了一個宏,在C#中執行該宏即可。
參考模板如下:
當然,你還可以排得更漂亮,因爲是單純的Excel操作,不需要特殊說明。如果記錄很多,往往一頁無法打印完成,我們要求在每一頁都顯示報表標題和小標題,也就是上圖中的第1、2行,這裏有一個技巧:選擇Excel的菜單“文件”→“頁面設置”,選擇“工作表”,在“頂端標題行”後的框中輸入“$1:$2”,也就是1~2行,當然,你也點右邊的紅箭頭,然後用鼠標選擇。當你的記錄超過一頁時,會自動在下一頁加入標題,非常方便。
表格中目前還沒有表格線,因爲我們不知道到底有多少數據,因此,也無法知道爲多少單元格設置邊框,我們藉助宏來完成。
按下面步驟錄製一個宏:
1、隨便選擇幾個單元格; 2、選擇菜單“工具”→“宏”→“錄製新宏”,輸入宏的名稱,就用默認的“宏1”吧,點確定; 3、選擇菜單“格式”→“單元格”,在對話框中選擇“邊框”,將內邊框和外邊框均選中,按確定; 4、此時,剛纔選擇的單元格就有了邊框,再點工具欄中的“停止錄製宏”按鈕 來結束宏錄製。
剛纔的操作目的是錄製宏而不是加邊框,因此,我們按“Ctrl+Z”來撤消剛纔的操作,通過按Alt+F8來調出宏,選擇“宏1”,選擇編輯,看到的代碼應該如下:
Sub 宏1() ’ 宏1 Macro ’ xx 記錄的宏 2003-5-1
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
With Selection.Borders(xlEdgeLeft)
.LineStyle = xlContinuous
.Weight = xlThin
.ColorIndex = xlAutomatic
End With
With Selection.Borders(xlEdgeTop)
.LineStyle = xlContinuous
.Weight = xlThin
.ColorIndex = xlAutomatic
End With
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.Weight = xlThin
.ColorIndex = xlAutomatic
End With
With Selection.Borders(xlEdgeRight)
.LineStyle = xlContinuous
.Weight = xlThin
.ColorIndex = xlAutomatic
End With
With Selection.Borders(xlInsideVertical)
.LineStyle = xlContinuous
.Weight = xlThin
.ColorIndex = xlAutomatic
End With
With Selection.Borders(xlInsideHorizontal)
.LineStyle = xlContinuous
.Weight = xlThin
.ColorIndex = xlAutomatic
End With
End Sub
|
圖中表的數據都是供排版參考用的,結束前將實際內容刪除掉,即只留下排好版的格式,包括標題、列標題等,將實際內容去掉。將文件保存到一個地方,如D:/Normal.xls,當然,實際開發時,可以放到執行文件所在目錄下,爲了防止用戶隨便修改,可以將文件名改爲normal.rpt之類。
有了上面的準備,我們就可以在C#中使用了,添加“高級報表”按鈕的響應代碼。下面是全部代碼清單。
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Reflection;
namespace MyExcel
{
/// <summary>
/// Form1 的摘要說明。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnNormal;
private System.Windows.Forms.Button btnAdvace;
/// <summary>
/// 必需的設計器變量。
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Windows 窗體設計器支持所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 調用後添加任何構造函數代碼
//
}
/// <summary>
/// 清理所有正在使用的資源。
/// </summary>
protected override void Dispose( bool disposing ) {
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// 設計器支持所需的方法 - 不要使用代碼編輯器修改
/// 此方法的內容。
/// </summary>
private void InitializeComponent()
{
this.btnNormal = new System.Windows.Forms.Button();
this.btnAdvace = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnNormal
//
this.btnNormal.Location = new System.Drawing.Point(49, 55);
this.btnNormal.Name = "btnNormal";
this.btnNormal.TabIndex = 0;
this.btnNormal.Text = "普通報表";
this.btnNormal.Click += new System.EventHandler(this.btnNormal_Click);
//
// btnAdvace
//
this.btnAdvace.Location = new System.Drawing.Point(169, 55);
this.btnAdvace.Name = "btnAdvace";
this.btnAdvace.TabIndex = 1;
this.btnAdvace.Text = "高級報表";
this.btnAdvace.Click += new System.EventHandler(this.btnAdvace_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(292, 133);
this.Controls.AddRange(new System.Windows.Forms.Control[] { this.btnAdvace,this.btnNormal});
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// 應用程序的主入口點。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private string [,] myData=
{
{"車牌號","類型","品 牌","型 號","顏 色","附加費證號","車架號"},
{"浙KA3676","危險品","貨車","鐵風SZG9220YY","白","1110708900","022836"},
{"浙KA4109","危險品","貨車","解放CA4110P1K2","白","223132","010898"},
{"浙KA0001A","危險品","貨車","南明LSY9190WS","白","1110205458","0474636"},
{"浙KA0493","上普貨","貨車","解放LSY9190WS","白","1110255971","0094327"},
{"浙KA1045","普貨","貨車","解放LSY9171WCD","藍","1110391226","0516003"},
{"浙KA1313","普貨","貨車","解放9190WCD","藍","1110315027","0538701"},
{"浙KA1322","普貨","貨車","解放LSY9190WS","藍","24323332","0538716"},
{"浙KA1575","普貨","貨車","解放LSY9181WCD","藍","1110314149","0113018"},
{"浙KA1925","普貨","貨車","解放LSY9220WCD","藍","1110390626","00268729"},
{"浙KA2258","普貨","貨車","解放LSY9220WSP","藍","111048152","00320"}
};
//普通報表,即單純的文件導出功能
private void btnNormal_Click(object sender, System.EventArgs e)
{
//創建一個Excel文件
Excel.Application myExcel = new Excel.Application ( ) ;
myExcel.Application.Workbooks.Add ( true ) ;
//讓Excel文件可見
myExcel.Visible=true;
//第一行爲報表名稱
myExcel.Cells[1,4]="普通報表";
//逐行寫入數據,
for(int i=0;i<11;i++) { for(int j=0;j<7;j++) { //以單引號開頭,表示該單元格爲純文本 myExcel.Cells[2+i,1+j]="’"+myData[i,j]; } } }
//高級報表,根據模板生成的報表
private void btnAdvace_Click(object sender, System.EventArgs e) {
string filename="";
//將模板文件複製到一個新文件中
SaveFileDialog mySave=new SaveFileDialog();
mySave.Filter="Excel文件(*.XLS)|*.xls|所有文件(*.*)|*.*";
if(mySave.ShowDialog()!=DialogResult.OK)
{
return;
}
else
{
filename=mySave.FileName;
//將模板文件copy到新位置,建議實際開發時用相對路徑,如 //Application.StartupPath.Trim()+"//report//normal.xls"
string filenameold=mySave.FileName;
FileInfo mode=new FileInfo("d://normal.xls");
try
{
mode.CopyTo(filename,true);
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
return;
}
}
//打開復制後的文件
object missing=Missing.Value;
Excel.Application myExcel=new Excel.Application ( );
//打開新文件
myExcel.Application.Workbooks.Open(filename,missing,missing,missing,missing, missing,missing,missing,missing,missing,missing, missing,missing);
//將Excel顯示出來
myExcel.Visible=true; //逐行寫入數據,數組中第一行我列標題,忽略
for(int i=1;i<11;i++) { for(int j=0;j<7;j++) { //以單引號開頭,表示該單元格爲純文本
myExcel.Cells[4+i,1+j]="’"+myData[i,j];
}
}
//將列標題和實際內容選中
Excel.Workbook myBook=myExcel.Workbooks[1];
Excel.Worksheet mySheet=(Excel.Worksheet)myBook.Worksheets[1];
Excel.Range r=mySheet.get_Range(mySheet.Cells[3,1],mySheet.Cells[14,7]);
r.Select();
//=====通過執行宏來格表格加邊框=======//
try
{
myExcel.Run("宏1",missing,missing,
missing,missing,missing,missing,missing,missing,missing,
missing,missing,missing,missing,missing,missing,missing,
missing,missing,missing,missing,missing,missing,missing,
missing,missing,missing,missing,missing,missing,missing);
}
catch
{
}
//保存修改
myBook.Save(); }
}//end of form }
|
在上述代碼中,我們指定了選定範圍:
Excel.Range r=mySheet.get_Range(mySheet.Cells[3,1],mySheet.Cells[14,7]);
|
具體開發時,我們可以根據數據庫中的實際數據來計算範圍,我們的列標題是從.Cells[3,1]開始的,在程序中定死了,爲靈活使用,我們完全可以在模板的Cells[1,1]或者其他單元格填入一些基本信息,如實際數據起始位置等等,操作時,從該單元格讀入數據,然後將該單元格內容替換成需要的內容。還有個問題,我們往單元格中寫內容時假設某列應該放什麼內容,爲靈活起見,我們在得到了列標題起始位置後,讀入該單元格內容(即該列應該是什麼字段),再從數據庫中找到相應的字段來填充該列,可以保證所填內容與設計的報表對應起來,還可以忽略數據庫中無用的字段,也就是說同一個數據庫表可以有許多種報表,只要有相應的模板就可以了,讀入某單元格內容的代碼如下:
Excel.Range r; r=mySheet.get_Range(mySheet.Cells[2,1],mySheet.Cells[2,1]); //取得值存放的區域 string strValue=r.Value.ToString();
|
一次只能讀一個單元格,否則得不到相應的數據,即=mySheet.get_Range(mySheet.Cells[2,1],mySheet.Cells[2,1])中兩個參數都必須是同一個單元格,本例中爲mySheet.Cells[2,1]。
有了上面的知識,再做報表就簡單多了,本軟件運行結果如下:
|