第5章物件導向

Download Report

Transcript 第5章物件導向

第五章 物件導向
ASP.NET程式不論是採用VB或C#語法來開發,都脫離
不了物件與類別,因為代表網頁的本身就是一個類別、
而每一種控制項的定義也都是一個類別。
雖然本書大部分採用單一檔案模式開發,不會看到繼承
使用的Inherits關鍵字,並且我們也不自行開發類別,但
本書仍將利用.NET Framework提供的眾多類別來開發
ASP.NET程式,故在本章中,我們將介紹VB的物件導
向語法,並且介紹Web Form網頁最基本的Page類別。
1
大綱
• (本章為電子檔PDF,可直接以PDF教學)
• 5.1 物件導向程式設計(若時程允許,建議教學)
– 5.1.1
– 5.1.2
類別與物件
繼承與實作
• 5.2 命名空間(若時程允許,建議教學)
– 5.2.1
– 5.2.2
– 5.2.3
.NET Framework的類別
Microsoft.VisualBasic命名空間
引入命名空間
• 5.3 傳統VB常用函式(請學生參考書附光碟檔自學)
2
大綱
• 5.4 System的常用類別(請學生參考書附光碟檔自學)
–
–
–
–
–
–
–
5.4.1
5.4.2
5.4.3
5.4.4
5.4.5
5.4.6
5.4.7
System.Object類別
System.String類別
System.Math類別
System.DateTime結構
System.Random類別
System.Array類別
線上說明
• 5.5 網頁生命週期與Page物件(若時程允許,建議教學)
–
–
–
–
5.5.1
5.5.2
5.5.3
5.5.4
ASP.NET生命週期
Page物件
Response屬性
Request屬性
• 5.6 共用事件程序(請學生參考書附光碟檔自學)
• 5.7 本章回顧
3
第五章 物件導向
• 本章將介紹Web Form網頁最基本的Page類別,以及具有各
種用途的特定類別(例如可用來進行數學計算、字串轉換)
– 由於篇幅有限,我們無法提供所有類別與方法的使用範例,僅將方法
列於表格說明,您若需要使用該方法,可以查閱msdn線上說明。
– 為了讓讀者更容易了解msdn線上說明,因此,我們必須先介紹VB的
物件導向術語,並適時地介紹ASP.NET可能使用到的類別。
4
5.1 物件導向程式設計
• 物件導向包含三大特性(封裝、繼承、多型),在本節中,
我們將說明VB.NET與ASP.NET的物件導向觀念,有了這些
觀念,當您在閱讀線上說明文件時,就能理解其中相關術語
的意義。
• 5.1.1
類別與物件
– VB.NET是一個物件導向程式語言,程式是由各式各樣的類別所構成。
而物件則是類別的實體。
• 舉例來說,Button按鈕是一個類別(Class),而視窗或網頁上的每
一個按鈕都是一個物件(Object)。
5
類別與物件
5.1.1
• 定義類別與宣告物件
– 若不使用系統提供的類別,使用者可以自行定義類別,簡略的語法如下:
[修飾字] Class 類別名稱
[繼承類別]
[實作介面]
'若需繼承自其他類別時才需使用
'若需實作某些介面時才需使用
定義類別的屬性
定義類別的欄位
定義類別的建構函式
定義類別的方法
定義類別的其他資料,例如常數、事件、運算子
End Class
6
5.1.1
類別與物件
• 封裝
– 封裝性是物件導向的特性之一,它使用於定義類別成員時,例如定義類別的
「欄位」和「方法」。
– 封裝是代表該成員是否可被外部(其他類別)使用,常用的封裝層級為Public、
Private、Protected等,分別代表公開、私用、可繼承使用。
• 本書並不需要自行宣告類別,有興趣的讀者可自行參閱VB專書或線上說
明。在本章中,我們會提示許多相關名詞,以便讀者在閱讀線上說明時不
致產生困惑。
• 宣告物件及產生物件實體
– 當類別定義完成後(不論是自行定義或使用.NET Framework提供的現成類
別),我們就可以將類別當作一種資料型別來宣告變數。
– 此型別是一種參考型別(Reference Type),也就是變數存放的將是參考。而我
們將這種變數稱之為物件變數。
– 當宣告物件變數之後,我們可以利用New關鍵字產生物件實體(instance),物
件實體是類別的一個複本,擁有類別的所有成員。
7
5.1.1
類別與物件
– 宣告物件與產生物件實體(兩者可合併)的語法如下:
Dim 物件變數1 As 類別名稱
物件變數1 = New 類別名稱(傳入建構函式的引數)
'宣告物件變數
'產生物件實體
Dim 物件變數2 As New 類別名稱(傳入建構函式的引數) '宣告物件變數並產生實體
– 【範例】
Class Rect
Public Length As Integer
Public Width As Integer
Private Area As Integer
Public Sub CalArea()
Area = Length * Width
End Sub
'宣告Length欄位為公用
'宣告Width欄位為公用
'宣告Area欄位為私用
'宣告公用CalArea方法
Public Function GetArea() As Integer
Return Area
End Function
End Class
8
'宣告公用GetArea方法
5.1.1
類別與物件
Class 其他類別名稱
Sub 某個方法名稱
'例如Button_OnClick方法
Dim var As Integer
Dim objA As New Rect() '宣告物件變數objA並產生實體,可改寫如下兩行
'Dim objA As Rect
'宣告物件變數objA
'objA = New Rect()
'產生物件實體
objA.Length = 10
objA.Width = 5
objA.CalArea()
var = objA.GetArea()
'設定objA物件的Length 欄位為10
'設定objA物件的Width 欄位為5
'執行objA物件的CalArea方法
'執行objA物件的GetArea方法
End Sub
End Class
• 【範例說明】
– (1) 前半部的Class Rect ~~ End Class為自行定義的Rect類別(它擁有3個欄
位與兩個方法)。後半部我們在另一個類別的某個方法中使用了自行定義的
Rect類別。
9
5.1.1
類別與物件
– (2)Dim objA As New Rect(),代表objA為物件變數,它會參考到Rect
類別的物件實體。
• 您可以將宣告與產生物件實體改寫為後面兩行。
– (3)objA.Length= 10與objA.Width = 5都是設定物件的欄位值。
• 但我們無法設定Area欄位值,因為它被宣告為Private私用等級,
而我們目前是在另一個類別中撰寫程式,故無法存取Area欄位值。
– (4)請注意,不論是哪一種等級的欄位,都可以在類別內的方法中使用,
故Area欄位可以在GetArea()與CalArea()中使用。
– (5) 想要設定Area欄位值,可以透過CalArea()來達成,想要取得Area
欄位值,可以透過GetArea()來達成,因為這兩個方法都被設定為
Public公用等級,故其他類別的程式也可以要求執行它。
10
5.1.1
類別與物件
• 上述程式執行後,var的值應該是50,因為它是GetArea()的回傳值。
但請注意,只有objA的Length為10、Width為5、Area為50,若宣
告其他物件並產生實體(例如objB),則其內的欄位值並不會相
同,因為物件之間是獨立的。
11
5.1.1
類別與物件
• 欄位(Field)、屬性(Property)和方法(Method)
– 請回顧1.5節,我們對於物件導向設計的介紹,當時我們說明了在物件導向設
計中,類別包含了屬性與方法,而類別的物件實體也同樣擁有這些屬性與方
法。
– 對於VB而言,方法與1.5節介紹的方法是完全相同的,方法是在類別內宣告的
Sub或Function程序,屬於該類別與其生成之物件實體專有,並且依照封裝等
級決定是否可被其他類別呼叫。
• 除了共用方法之外,方法應該由該類別的實體物件來執行,其功能代表的
是物件可採取的行動。
• 例如上述範例中,Rect類別的CalArea()與GetArea()都是Rect類別的方法。
– 而我們是透過實體物件objA來執行它們。
– 但對於VB而言,1.5節所說明的屬性,在VB中稱之為欄位,它可以視為類別
或物件的項目,同樣地,它也有封裝等級,並可由封裝等級決定是否可被其
他類別存取其值。
12
5.1.1
類別與物件
– 然而VB的屬性與1.5節所介紹的屬性有一點點的不同,VB的屬性是介
於欄位與方法的綜合體。
• 對於VB而言,屬性仍是一種程序,但其主要目的是存取欄位值。
– VB的屬性藉由Set與Get程序來存取欄位值,那麼存取哪一個欄位值呢?
• 在VB2008之前,使用者應該設定一個以上的欄位值以供Set與Get程序存
取,並且可以在Set與Get程序內動一些手腳,使得屬性值的設定可以有更
多的限制。
– 例如,如果我們將某一個身高設定為人物類別的欄位,則我們只能透
過=運算子,指定一個數值給該欄位,並且無法設定其為只能讀不能
寫或只能寫不能讀。
• 但如果我們將其宣告為身高屬性而非身高欄位,則我們可以透過Set與Get
設定其讀寫特性(例如唯讀或唯寫)
– 並且在Set程序中,加入條件判斷,就可以使得當要設定身高屬性時,
將其對照的欄位值規範在150~200之間。
13
5.1.1
類別與物件
– 在VB2010之後,屬性更像是欄位了,或可視為增強版的欄位,因為
VB2010提供了「自動實作屬性」的功能
• 也就是當您將一個類別的項目宣告為屬性時,不再需要提供其他欄位或
Set與Get程序,就可以透過=運算子,指定一個數值給該屬性。
• 這是因為編譯器會自動幫這個屬性實作出Set與Get程序,並且宣告一個
「_屬性名稱」的欄位,作為實際存放資料的所在。如下範例:
V
B
2
0
1
0
程
式
碼
Class Person
...............
Public Property height As Integer '宣告height屬性
End Class
...............
Dim objP As New Person()
objP.height=180
'設定height屬性為180,它會自動執行編譯器產
'生的Set程序,使得_height欄位值變成180
...............
14
5.1.1
類別與物件
– 編譯器處理上述新版VB程式碼時,會產生如下的同等效力之程式碼
同
等
效
力
的
舊
版
V
B
2
0
0
8
程
式
碼
Class Person
...............
Private _height As Integer
'宣告_height欄位
Public Property height As Integer '宣告height屬性
Get
Return _height
End Get
Set(ByVal value As Integer)
_height = value
End Set
End Property
End Class
...............
Dim objP As New Person()
objP.height=180
'設定height屬性為180,它會自動執行對應的Set程序,
'使得_height欄位值變成180
15
...............
5.1.1
類別與物件
– 當然,如果您想在VB2010版使用舊的語法,並且提供了Get/Set程序,
則不一定要使用「_屬性名稱」欄位作為其存放資料處。
• 但請注意,若您使用的是「自動實作屬性」功能,則不可以再一次自行定
義一個「_屬性名稱」欄位,否則編譯時會出現錯誤。
– 由於將項目宣告為屬性,比將項目宣告為欄位更可以有效管控,因此,
VB的控制項之資料項(例如Button的Text),都是宣告為屬性,並且
可以在屬性窗格中進行初始的靜態設定。
– 由於VB2010已經提供了「自動實作屬性」功能
• 因此建議,若資料項目是不想公開的,通常會宣告為欄位,並採用Private
封裝等級宣告;
• 而若是需要對外公開的,則可宣告為屬性,因為Property程序的封裝等級
是Public。
16
5.1.1
•
類別與物件
字串類別
– 事實上,為了達到跨語言的目的,.Net Framework定義了許多基本資料型別
(如表4-1的CLR資料型別),用以對照VB、C#、J#等多種語言所提供的資
料型別。
• 例如System.String、System.Int32分別都是一個類別或結構,可以對應
VB的String字串型別與Integer整數型別。
【結構(Structure)】
結構是VB提供的另一種定義參考型別的方式,與類別幾乎相同(也具有欄位與方法),
可以將內部定義的項目封裝起來。但結構無法使用繼承,故只能使用於不需要擴充時使
用。
– 因此,VB的String字串在編譯時,會被視為一個類別,而VB允許我們省略
New關鍵字來產生實體而能夠直接設定它
– 事實上,String類別的字串是一個內容固定而無法改變的字串,當您試圖改變
字串內容時,只不過是產生一個新的字串物件實體,並將字串變數參考到新
的字串物件實體而已,而原本的字串將在一段時間後被系統自動回收。
17
5.1.1
類別與物件
– Net Framework之所以將String類別的字串設定為不可變,主要原因是
為了在多執行緒環境時避免造成同步問題。
– 下列範例將使用較正式的宣告物件與產生實體的語法來使用物件。
• String類別擁有一個Insert(n,s)方法,實際上它是一個Function程序。
當String物件執行它之後,可以在String物件的第n個位置插入一個
子字串s,並且回傳其結果,如下範例。
Dim s1 As New String("abcxyz")
Dim s2 As New String("")
s2=s1.Insert(3,"ttt")
'執行後s1內容為 "abcxyz"
'執行後s2內容為 "" 空字串
'執行後s2內容為 "abctttxyz"
18
5.1.1
類別與物件
• 共用方法(Shared Method)
– 上述範例在執行Insert方法時,必須透過String的物件實體s1來執行。
有時為了方便方法被使用,因此,VB允許我們定義共用方法(Shared
Method),
– 而共用方法並不需要產生物件實體,只需要使用「類別名稱.方法名稱
()」來執行即可。
• 例如Strings字串類別(不是String類別)有一個LCase(s)方法,可
以將s字串的內容全部轉換為小寫後回傳,如下範例。
Dim s3 As New String("ABC")
Dim s4 As New String("")
s4 = Strings.LCase(s3)
'執行後s3內容為 "ABC"
'執行後s4內容為 ""空字串
'執行Strings的共用方法LCase後s4內容為 "abc"
【共用方法與靜態方法】
VB的共用方法在其他語言(例如Java)中,一般稱之為靜態方法(static method)。
19
5.1.1
類別與物件
• 共用欄位(Shared Filed)
– 同理,除了可定義共用方法外,我們也可以在類別內定義共用欄位,
如此一來,所有由該類別產生的物件將共用此欄位。
– 並且即使物件消失了,該欄位值也不會消失,因為它必須保留,使得
之後產生的物件能夠繼續共用。
– 而定義共用欄位與方法都是使用Shared關鍵字來修飾。
【模組】
類別 (Class) 和模組都是將內部定義的項目封裝起來的參考型別,但類別可實
體化 (Instantiated) 為物件實體,而標準模組不行。因為標準模組資料只有一
個共用複本,故在模組中所宣告的方法是隱含共用的方法,不必使用Shared
關鍵字來宣告。並且類別可以實作介面但標準模組則不行。
20
5.1.1
類別與物件
• 建構函式(Constructor)
– 這是當類別產生實體物件時會馬上自動執行的函式,通常用以初始化
物件的內容,而其名稱為Sub New程序。(不會是Function,因為它
不能回傳任何值)
• 事件驅動與事件程序(event-handling method)
– 事件驅動是視窗程式的新觀念。事件是由物件傳送用以表示發生某個
動作的訊息。而動作可能是由使用者操作 (例如按一下) 所造成,也可
能是由程式邏輯來觸發 (Trigger)。
– 引發事件的物件稱為事件來源者(Event Source),捕捉事件並且回應
它的物件稱為事件接收者(event receiver),所謂「回應」也就是執行
某個特定的程序。
21
5.1.1
類別與物件
– 程式中必須提供事件處理程序(event-handling method)來回應事件,
並且必須將事件處理程序向事件來源者註冊。如此才能使事件來源者
與事件接收者產生關聯,這個動作稱之為事件連接(event wiring)。
– VWD與VB IDE都提供了簡化或隱藏事件連接詳細資料的RAD工具。
• 而在本書中,我們使用的事件來源者為Web Form本身或各種控制
項,故只需要在屬性窗格中透過選取事件處理程序的方式就能夠
完成事件連接,完全不需要學習其詳細機制,只需要了解事件驅
動的意義即可。
– 舉例來說,在網頁中若按下按鈕Button1,則按鈕Button1(事件來源
者)會產生一個Click事件,而由於IDE已經幫我們完成了事件連接,
因此在接收到按鈕Button1的Click事件後會自動執行Button1_Click()事
件程序。
22
5.1.1
類別與物件
• 多載(Overloading)
– 有些時候我們會希望建立一些名稱相同但參數數量或型別不同的多個
方法,此時,您可以透過多載(Overloading)機制來達成。
• 例如想要建立一個計算面積的程式,您可以宣告
Area(Integer,Integer)與Area(Double,Double)兩個同名的方法,但
宣告方法時,必須在Sub或Function前方使用Overloads關鍵字來
修飾。
• 除了方法之外,建構函式與類別屬性也可以使用多載機制。
【運算子(Operator)】
當您查閱線上說明時,有時候會在類別內見到運算子(Operator),例如String類別中,
有一個Equality運算子,這也是多載化的一種應用,運算子多載化使得運算子可以進
行更多型別的運算,例如String字串「=」運算子,可以用來判斷兩個指定的String物
件是否具有相同的值。
23
5.1.2
繼承與實作
• 繼承也是物件導向的特性之一,它使得原有的類別得以擴充
為更多功能的類別。
– 例如我們有一個滑鼠類別,此時若希望開發一個滾輪滑鼠類別,只需
要繼承滑鼠類別,然後加上一個滾輪欄位,以及一個滾輪滑動方法即
可。
• ASP.NET的網頁繼承
– 在VB中,繼承使用的關鍵字是Inherits,被繼承者稱之為基底類別,
繼承者稱之為衍生類別。
– 我們所開發的網頁,在ASP.NET中稱之為Web Form,它事實上是一
個Page類別的衍生類別。
• 如果您使用的是程式碼後置模式開發ASP.NET的Web Form網頁,
並且在網頁上配置一個Button1按鈕,然後按兩下產生其Click事件
的處理程序,則可以在「Default.aspx.vb」檔案中看到下列程式碼:
24
5.1.2
繼承與實作
Partial Class _Default
Inherits System.Web.UI.Page
'類別名稱為_Default
'繼承自System.Web.UI.Page
Protected Sub Button1_Click(sender As Object,
e As System.EventArgs) Handles Button1.Click
'事件程序撰寫處
End Sub
End Class
• 【說明】
– (1)您會看到一個類別宣告,名稱為「_Default」,而第二行則會看到
這個類別衍生自(繼承了)System.Web.UI.Page類別。它包含一個事
件程序(Button1_Click),事件程序後方的「Handles Button1.Click」
則代表它要處理Button1的Click事件。
25
5.1.2
繼承與實作
– (2)至於「_Default」類別前方的Partial 關鍵字,則代表此處的類別定
義僅限於類別的一部分,
• 換句話說,類別的定義並不完全包含在單一檔案中。因此,當網
頁執行時,編譯器會讀取 .aspx 網頁以及在『@ Page 指示詞中
CodeFile參考的檔案』,並將其組成為單一類別然後進行編譯。
而這個組合起來完整的類別就是網頁本身。
26
5.1.2
繼承與實作
– (3)類別的另一部分被記載在.aspx檔案中,但若您觀察該檔案並不會
看到相關的資料,事實上,每一個控制項都代表著該類別的一個成員。
• 例如<asp:Button ID="Button1" runat="server"
Text="Button"></asp:Button>控制項,會使得編譯器產生下列的部
分類別中的Button1欄位。
• 由此可知,控制項將會成為網頁類別中的欄位,事實上,我們在
範例4-13的第7行所定義的num,也是網頁類別的一個欄位,因為
它定義於所有程序之外。
Partial Class _Default
Inherits System.Web.UI.Page
Protected Button1 As Button
'成員(欄位)
End Class
– (4)整體的網頁編譯過程如圖5-1:
27
圖5-1
程式碼後置的網頁編譯過程
28
5.1.2
繼承與實作
• 至於如果您使用的是單一檔案模式開發ASP.NET網頁,則由
於標籤、控制項及事件處理程序的程式碼都已放置在單
一.aspx檔中。故在編譯網頁時,編譯器會產生及編譯新類別,
該類別衍生自基底 Page 類別(未設定Inherits屬性時)
–
–
–
–
類別名稱將會是「ASP<Page>_aspx」或「<Page>_aspx」
其中<Page>為檔案的主檔名
一般我們將代表網頁的類別稱為<Page>類別
整體的網頁編譯過程如圖5-2:
29
圖5-2
單一檔案的網頁編譯過程
30
5.1.2
繼承與實作
• 值得注意的是,網頁的生命週期代表著<Page>物件的生成與消滅,
<Page>物件是<Page>類別的一個實體
– 當一個網頁的要求產生時,首先ASP.NET會判斷是否需要剖析和編譯網頁 (因
此開始網頁的生命週期),或者使用網頁的快取版本。接著網頁會經過一連串
的事件 (其中包含PreInit、Load、PreRender等等),最後產生XHTML回傳給
客戶端
– 回傳給客戶端之後,還會執行Unload事件程序,然後就會被捨棄(discarded)。
– 網頁被捨棄,代表<Page>物件已經消滅。故當您按下【按鈕】而將表單資料
送往同一個網頁時(送往網頁就是代表一個網頁的要求產生),代表著另一
個新的網頁生命週期即將展開。
– 而兩次的網頁要求執行的是不同的<Page>物件
• 所以在範例4-13中,num雖然是<Page>類別的欄位,但由於並未設定為
共用欄位,故無法保存資料到下一次網頁要求執行時。
31
5.1.2
繼承與實作
– 關於使用最大容器保存資料,ASP.NET的Web Form與VB的WindowsForm之
效果有些差異,因為VB視窗的Form1類別(繼承自
System.Windows.Forms.Form)所產生的<Form>物件,從程式開始到結束的
過程中都不會被消滅(除非您開發的是多Form程式),故其內的欄位值可以
一直保存,但ASP.NET卻不行,因為ASP.NET的網頁物件是不斷在重複「生
成、經歷事件、消滅」的過程。
– 要讓ASP.NET的網頁具有記憶資料的功能,可以將資料宣告為<Page>類別的
共用欄位,如此,不論是哪個新的網頁物件實體都可以與其共用,故而達到
資料記憶的能力
• (不過這並不是一個好辦法,較佳的作法請見第10章)。
32
5.1.2
繼承與實作
• 【範例5-1】
– 改寫範例4-13,使用共用欄位解決資料記憶問題。
• 範例5-1:
– 網站目錄 ASPNET\ch05\ch05_01\(檔案ch05_01.aspx)
– Step1:網頁介面設計【略,請自行參閱檔案】:
• 當中包含一個Button按鈕控制項,名稱為Button1及一個Label標籤
控制項,名稱為Label1。
– Step2:撰寫<script>內的程式碼如下:
33
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script runat="server">
Private Shared num As Integer
Sub Addk(ByVal k As Integer)
num = num + k
End Sub
'定義私用的共用欄位num
'可將此程序看作是Page類別的方法
Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
Addk(3)
Addk(3)
num = num + 1
Label1.Text = "num=" & CStr(num)
End Sub
</script>
– 範例說明:
• (1)第7行:整個程式與範例4-13完全相同,只有在第7行,我們將num欄
位改為私用且為共用欄位(使用Shared的效果)。
• (2)請您按下【在瀏覽器中檢視】鈕來執行,執行後每按一次【執行】鈕,
num的值都會累加7。
34
5.1.2
繼承與實作
• (3) 請重新按下瀏覽器捷徑,開啟另一個瀏覽器(非開啟瀏覽分頁或新索
引標籤),並將前一個執行ch05_01.aspx的瀏覽器之網址(例如
http://localhost:4890/ch05_01/ch05_01.aspx)複製到新開啟的瀏覽器網
址列中,按下【Enter】鍵,此時會讀取同一個網頁,並且您在新瀏覽器
中按下【執行】鈕,也會進行num的累加。
– 請切換兩個瀏覽器,並多按幾次【執行】鈕,就可以發現此一現象。
• (4)為何未發生上述的現象呢?
– 事實上,不論您是按下哪一個瀏覽器中的【執行】鈕,都代表著一個
網頁要求的產生,也就是一個新的網頁生命週期的開始,但當您看到
網頁在瀏覽器中顯示的結果時,該網頁生命週期已經結束。
– 所以如果一個網頁的生命週期是由一個<Page>物件來執行,則每按
一下【執行】鈕,代表產生一個新的<Page>物件,並且該物件執行
完畢後就消失了。
– 而雖然這些<Page>物件是不同的物件,但仍可共用<Page>類別的
num共用欄位。所以還是能夠達到記憶的功能(但也會因此造成兩個
瀏覽器間相互的影響,我們將在範例6-2、6-3解決這個問題,之後也
會改以ViewState等其他機制,達到資料跨網頁共用的目的)。
35
5.1.2
繼承與實作
– Step3:執行程式。
36
5.1.2
繼承與實作
• 多型與覆寫
– 多型(Polymorphism)也是物件導向的特色之一,代表能夠在執行階段,
執行不同功能但名稱完全相同的方法。實現多型的方式之一可透過覆
寫方法來完成。
• 舉例來說,我們有一個矩形類別(包含兩個長、寬欄位及一個計
算周長方法),而今天想要開發一個正方形類別,則同樣可以繼
承自矩形類別,並且不需要增加任何新的欄位與方法。
• 而雖然我們不增加新的方法,但可能舊的(繼承而來的)計算周
長方法之程式執行速度較慢(甚至可能已經不敷使用),此時我
們可以在衍生類別中,覆寫原本的方法。
– 舉例來說,我們可以在衍生的正方形類別中覆寫原本的計算周
長方法。例如原本為(長+寬)*2,而覆寫時,則改為(長*4),以
便不使用加法。
37
5.1.2
繼承與實作
– 覆寫並不代表原本基底類別的計算周長方法消失了,而是編譯器能夠
將其正確處理,使得正方形物件在執行計算周長方法時,能夠執行到
覆寫後的計算周長方法。
• 在VB中,要使用覆寫功能來覆寫某一個方法時,使用的關鍵字是
Overridable。
38
5.1.2
繼承與實作
• 多型與介面
– 介面和類別很相似,但介面僅定義了欄位與方法,並不提供方法的細
節程式碼(只定義了方法的名稱)。因此,介面無法產生物件(否則
物件執行方法時,不知道要執行什麼程式碼)。
– 要讓介面產生作用,仍必須以某個類別實作該介面,在VB實作介面時,
採用的是Implements關鍵字。
– 實作介面和繼承類別很相似,不過實作介面時,必須將所有已定義的
方法重新撰寫一份細節程式碼。(而繼承類別時,除非有覆寫之必要,
否則可以直接繼承方法來使用。)
• 換句話說,我們也可以將實作時撰寫的程式碼看作是覆寫,因此
介面也是多型的一種方式,只不過在VB中,實作介面定義的方法
時,不是使用Overridable關鍵字。
39
5.1.2
繼承與實作
• 【註】以上介紹的類別、物件、繼承等相關物件導向語法,大多數在本書
中並不會使用。之所以在此說明,是基於下列理由:
– 1. 讓讀者了解,ASP.NET網頁本身將被視為一個<Page>類別來編譯。
而該類別繼承自System.Web.UI.Page類別。
– 2.讓讀者了解,即使您在撰寫VB時將String視為一種資料型別,但在
編譯為中間檔時,仍會對應到.NET Framework的String類別,故我們
可以在程式中直接使用字串物件的方法。
– 3. 讓讀者了解,Label控制項是一個類別。而我們產生的Label1控制
項事實上是<Page>類別的一個欄位。故可以在<Page>類別中橫跨多
個事件程序自由使用,因為所有的事件程序都是<Page>類別的方法。
– 4. 讓讀者了解,如果您有一些變數想要橫跨多個程序來使用,可以將
之宣告在程序之外,此時該變數就會變成是網頁類別的一個欄位(因
為整個網頁是被包含在一個<Page>類別內)。
40
5.1.2
繼承與實作
– 5. 若您不滿意某個控制項的某個方法,可以透過繼承,然後覆寫該方
法來達到修改控制項的目的(因為每個控制項都是一個類別)。
– 6.後面介紹常用類別與方法時,並不會完全列出語法細節,若讀者在
查閱線上說明時,遇到相關術語,能夠由本節之說明進行理解。如下:
• 您可能會查到某個類別的方法,名稱相同,但參數型別不同,這
就是因為使用多載功能的緣故。
• 您可能在查閱某個控制項的欄位時,會發現是屬性,但實際使用
上,您可以將屬性當作欄位來使用,但屬性可能被宣告為唯讀或
唯寫。
• 有些方法不必產生物件就可以使用,這是因為它被宣告為共用方
法。
41
5.2 命名空間
• 雖然在上一節中,我們介紹了如何撰寫類別,但本書的重點
仍然是使用系統提供的現成類別來開發程式。
– 而現成的類別非常多,尤其是.NET Framework還可以跨語言開發,
因此,類別需要被管理,.NET Framework將管理類別的工作交由命
名空間來負責。
• 許多程式語言都面臨類別管理的問題,例如Java利用目錄與檔案
的唯一性來作為根據,意即在檔案系統中,任何一個檔案的「完
整路徑+檔名」不會重複,完整路徑代表類別庫,而檔名代表類別,
並且將目錄階層相隔之符號「\」改為「.」,就可以避免類別名稱
的重複。
– 而.NET Framework則是採用命名空間(namespace)來區隔,命名空
間也是以階層方式進行區隔,並且階層符號為「.」,最後一個「.」右
方為類別名稱,而左方則為該類別的命名空間,在此命名空間中,保
證不會有相同的類別。
42
5.2 命名空間
– 舉例來說,我們常用的Button按鈕類別,在屬性窗格中您會發現其完整的名稱
為System.Web.UI.WebControls.Button
• 最右方的Button為類別名稱
• 左方的System.Web.UI.WebControls為命名空間的名稱
• 並且在System.Web.UI.WebControls命名空間中,只會有一個Button類別。
• 微軟建議,若公司或個人想要開發類別庫,應該採用「公司名稱.技術名
稱」作為命名空間,若類別庫較大,可以將「技術名稱」分為更多層級。
– 舉例來說,微軟(公司名稱)有C#與VB兩種技術,故規劃了兩個命名空間如
下,當中各包含了許多的類別。
• Microsoft.CSharp 命名空間
• Microsoft.VisualBasic 命名空間
43
5.2 命名空間
– 但單純如此規劃,可能會發現有些類別會在Microsoft.VisualBasic 命
名空間中重複或因為要突顯某些類別的特殊用途,故而又出現下列幾
個命名空間。
• Microsoft.VisualBasic.FileIO 命名空間
• Microsoft.VisualBasic.Logging 命名空間
– 在Microsoft.VisualBasic命名空間與Microsoft.VisualBasic.FileIO命名
空間中若有類別名稱相同,是允許的,因為編譯器可以由完整名稱判
斷出目前使用的是哪一個類別。
– 但在同一命名空間中則不允許出現相同名稱的類別。
– 事實上,在.NET Framework中允許以完整名稱宣告物件變數的型別,
如此可以避免類別名稱相同。但大多數時候,為了方便,我們並不會
這樣做。
44
5.2 命名空間
• 【註】請注意,微軟會將類別編譯為組件,在Java中,類別庫
是以目錄為單位,但.NET Framework並非如此
– 因此,一個命名空間的所有類別可能被切割到不同的組件。而一個組
件也可能包含了多個命名空間的類別。
– 因此當您在線上說明查閱某個命名空間時,它並不會說明該命名空間
被分配到哪一個組件,而是當您查閱某個類別時,它才會說明該類別
屬於哪一個命名空間及該類別被分配到哪一個組件中。
• 例如System.Web.UI.WebControls.Button類別被分配到System.Web(也就
是System.Web.dll檔)組件中,而System.Web.UI.PostBackOptions類別也
被分配到System.Web(System.Web.dll檔) 組件中,但這兩個類別並非屬
於同一個命名空間。
• 至於System.Web.dll檔一般位於
\WINDOWS\Microsoft.NET\Framework\v4.0.30319\目錄中
– (最後一層子目錄會因版本而不同)。
45
5.2.1
.NET Framework的類別
• 使用命名空間的類別時,應該要先引入命名空間或類
別,.NET Framework包含了許多的命名空間,並且在開發
ASP.NET時,會自動引入的命名空間如下表
– 這代表我們不需要引入下列命名空間,就可以直接使用其內的所有類
別:
46
47
5.2.1
.NET Framework的類別
48
5.2.1
.NET Framework的類別
• 繼承階層架構的根:Object
– 在.NET Framework的規劃中,所有的類別都應該有一個父類別,對
於沒有父類別的類別而言,它的父類別就是System.Object類別。
• 換句話說,所有的類別都是System.Object類別的子孫類別。
49
5.2.2
名空間
Microsoft.VisualBasic命
• 當我們使用VB語法開發ASP.NET程式時,除了表5-1所列之
命名空間內的類別可使用外,Microsoft.VisualBasic命名空間
內的類別也可以使用。
– 例如我們在第4章中,為了判斷字串內容是否為正整數,使用了
IsNumeric與InStr兩個程序
• 而這兩個程序則分別是Microsoft.VisualBasic.Information類別與
Microsoft.VisualBasic.Strings的共用方法。
– 但是如果您使用的是C#語法開發ASP.NET程式,則無法使用
IsNumeric程序,除非您先明確引入Microsoft.VisualBasic命名空間。
50
5.2.3
引入命名空間
• 除了上述內定的命名空間會被隱含式地引入程式之外,若程
式中想要引入其他命名空間的類別,則必須使用明確引入的
方式。
– 引入時能夠以命名空間為單位,一次引入該命名空間的所有類別。
– 【註】
• 雖然在引入命名空間時,連類別名稱也可以設定,但我們並不建
議這樣做。
51
5.2.3
引入命名空間
• 在ASP.NET中引入命名空間可以分為兩種狀況:
– 1.使用於單一檔案模型時:
• 您只要在網頁第一行,使用@ Import指示詞引入即可。但一次只能引入一
個命名空間,若要引入多個命名空間,則應該使用多次<@ Import >指示
詞分別引入。語法如下:
<%@ Import Namespace="命名空間完整名稱" %>
• 範例:
<%@
Import Namespace="System.Drawing" %> '引入System.Drawing命名空間
<%@ Page Language="VB" %>
……
<script runat="server">
Dim drawObj1 As Bitmap
'可使用System.Drawing命名空間的Bitmap類別
……
</script>
52
5.2.3
引入命名空間
– 2.使用於程式碼後置模型時:
• 由於程式碼後置模型的程式碼放在.aspx.vb檔案內,故您可以
於.aspx.vb第一行引入命名空間,語法如下:
Imports命名空間完整名稱
• 範例:(在.aspx.vb內)
Imports System.Drawing
'引入System.Drawing命名空間
Partial Class _Default
Inherits System.Web.UI.Page
Dim drawObj1 As Bitmap '可使用System.Drawing命名空間的Bitmap類別
End Class
53
5.2.3
引入命名空間
• 類別名稱衝突
– 有時候,由於引入的命名空間中包含了相同名稱的類別,就會發生名
稱衝突的現象。
• 例如,在System.Timers、System.Web.UI、System.Threading等
三個命名空間中都有Timer類別,此時若引入了這幾個命名空間,
並使用Timer類別宣告型別時,會發生模擬兩可的錯誤。
• 要避免錯誤,應該使用類別全名(命名空間+類別)作為類別名稱
來宣告。
– 如果只是使用System.Web.UI.Timer則不需要明確引入,因為
System.Web.UI內定會引入。
– 而如果您想要使用System.Timers.Timer類別,則除了要引入
System.Timers命名空間外,還必須指名要使用的類別為
System.Timers.Timer類別。
54
5.2.3
引入命名空間
– 範例如下:
<%@ Import Namespace="System.Timers" %>
<%@ Import Namespace="System.Web.UI" %>
'內定已經引入,可省略
<%@ Page Language="VB" %>
………
<script runat="server">
Dim Obj1 As System.Timers.Timer
'使用類別全名
Dim Obj2 As System.Web.UI.Timer
'使用類別全名
………
</script>
55
5.3 傳統VB常用函式
• 傳統VB(例如VB6、VBScript)提供了許多的函式,而在VB.NET中,為
了延續這些程式的可用性,也將許多函式建構成一些
Microsoft.VisualBasic命名空間中某類別的共用方法。使得轉換程式時,
舊有的程式不需要更動。
– 但事實上,這些函式在.NET的規劃中,已經有其他類別用以取代。
• 舉例來說,傳統VB要獲得亂數使用的是Rnd()函式,而VB.NET將之列於
Microsoft.VisualBasic命名空間的VBMath類別的Rnd()共用方法。但.NET
Framework則重新規劃亂數為System命名空間的Random類別來負責。
– 在本節中,我們將列出這些舊的VB函式,並列出其命名空間與類別名稱。
– 而下一節將列出新規劃的常用類別與方法。除非是無法找到新規劃的類別與
方法,否則我們並不建議沿用舊的VB函式。
56
5.3 傳統VB常用函式
•
Microsoft.VisualBasic.Strings(Microsoft.VisualBasic為命名空間)的字
串函式
57
5.3 傳統VB常用函式
58
59
5.3 傳統VB常用函式
• Microsoft.VisualBasic.Conversion(Microsoft.VisualBasic為命名空間)
的轉換函式
– 【註】CInt(n)已經改為採內嵌方式編譯,不需要規劃為類別的方法。Val(s),
可以透過表4-1的轉換函式來替代。而Str(n),則可以由CStr(n)來替代。
60
5.3 傳統VB常用函式
• Microsoft.VisualBasic.DateAndTime(Microsoft.VisualBasic
為命名空間)的日期時間函式與屬性
61
5.3 傳統VB常用函式
62
5.3 傳統VB常用函式
• Microsoft.VisualBasic.VBMath(Microsoft.VisualBasic為命
名空間)的亂數函式
63
5.3 傳統VB常用函式
• Microsoft.VisualBasic.Information(Microsoft.VisualBasic為
命名空間)的方法
– 以上幾乎所有的函式,我們都建議改由下一節介紹的System命名空間
中特定的類別方法來取代,只有Microsoft.VisualBasic.Information類
別例外,Microsoft.VisualBasic.Information類別內的方法,大多是用
來測試資料所用,例如之前介紹的IsNumeric(s)可用來檢查字串內容
是否為數字,在實務上就非常好用。
64
– 【註】表5-6傳入的引數有時為字串變數,也就是字串物件,事實上,在方法定義中,
您會發現到參數被宣告為Object型別,而由於String也是Object的子孫類別,故可以相
容而作為引數傳入。
65
5.4 System的常用類別
• Microsoft.VisualBasic命名空間中的類別非常多,而Microsoft.CSharp 命
名空間中的類別則相對少很多。這主要是時代背景所導致。
• 理論上,微軟VB與C#的程式都應盡量使用.NET Framework的類別庫,
並且兩者盡量統一,例如多使用System命名空間的類別,少使用
Microsoft.VisualBasic命名空間中的類別,如此才不會在轉移為C#程式時,
還需要另外引入命名空間。
– 不過,VB.NET由於背負了傳統VB、VBScript的包袱,為了使得這些程式能夠
順利移轉為VB.NET,故微軟提供了Microsoft.VisualBasic命名空間中的眾多
類別,用以對應傳統的內建函式。而C#則無此包袱,因為C#是與.NET
Framework一起推出的。
• 在本節中,我們將介紹System命名空間中許多常用的類別,讀者應該在
選擇類別時,以System為開頭的命名空間為優先,實在找不到適用類別
時,才使用Microsoft.VisualBasic命名空間的類別。
66
5.4.1
System.Object類別
• System.Object類別是.NET Framework中所有類別的祖先,
也就是說,所有的類別都直接或間接繼承自Object類別
– 例如當您查閱線上說明時,您會發現某些方法在不同類別中是重複的,
這可能是因為繼承機制所導致,因此,Object類別的方法會出現在各
種類別中。
• 而即使如此,相同名稱的方法並不代表其細節都是相同的,因為
它可能被衍生類別進行覆寫了。
– Object定義的方法並不多,主要是因為Object本身並無太大的作用,
它只提供了類別的基本功能。
– 而會被繼承後覆寫的方法更少,通常會被覆寫的方法是ToString()。
67
5.4.1
System.Object類別
68
5.4.2
System.String類別
• VB的String資料型別編譯時會對應到.NET Framework的System.String類
別,這種字串是一個不可改變內容的字串。因此,當使用實體方法時,將
不會改變原始字串的內容,但透過回傳值,同樣可以取得一些字串的變化
結果。
• .NET Framework希望以System.String類別完成之前傳統VB提供的各種字
串函式。
• System.String類別提供的方法非常多,有些為共用方法,不必產生物件
即可使用,有些為實體方法,必須產生物件才能使用,常用的方法如下表:
69
5.4.2
System.String類別
70
5.4.2
System.String類別
71
72
5.4.2
System.String類別
• 【範例5-2】
– 使用System.String類別提供的方法進行字串的變化。
• 範例5-2:
– 網站目錄 ASPNET\ch05\ch05_02\(檔案ch05_02.aspx)
– Step1:網頁介面設計【屬性請自行參閱檔案】:當中包含一個Button
按鈕控制項,名稱為Button1及三個Label標籤控制項,名稱為
Label1~Label3。
73
5.4.2
System.String類別
– Step2:撰寫Button1_Click()事件程序碼如下:
• 程式部分內容:
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
Dim str As New String("新竹市大學路1001號")
Dim strLead As New String("交通大學位於")
Dim str1, str2, str3 As String
Dim spaceStr As New String("
")
str1 = str.Substring(0, 3)
'str1=新竹市
str2 = str.Substring(3)
'str2=大學路1001號
str3 = str.Substring(3, 3)
'str3=大學路
str1 = strLead & spaceStr & str1
Label1.Text = str1.Replace(" ", "&nbsp;") '顯示空白必須使用特殊字元
str2 = strLead & spaceStr & str2
Label2.Text = str2.Replace(" ", "&nbsp;")
str3 = strLead & spaceStr & str3
Label3.Text = str3.Replace(" ", "&nbsp;")
End Sub
74
5.4.2
System.String類別
– 範例說明:
• (1)第13~15行:使用str字串實體執行SubString()方法取出子字串。
由於這是一個多載方法,故引數個數可以不同。取出之子字串同
後面註解,請自行對照執行結果
• (2)第17、19、22行:在網頁中無法顯示連續兩個以上的空白,必
須使用特殊字元「&nbsp;」來取代,因此使用Replace方法進行字
元的替換,這是網頁程式常用的技巧之一。
– Step3:執行程式。
75
5.4.3
System.Math類別
• System.Math類別是.Net Framework規劃用來處理各類數學
計算的類別,可取代傳統VB的相關數學函式。
– System.Math類別定義了兩個共用欄位E與PI,用以表達自然指數與圓
周率。
– 而System.Math類別的方法則全部都是共用方法,如下表整理。
76
5.4.3
System.Math類別
77
5.4.3
System.Math類別
78
5.4.4
System.DateTime結構
• System.DateTime結構是對應傳統VB的日期時間函式(之後
被規劃在Microsoft.VisualBasic.DateAndTime類別)。
– 結構可以視為類別一般來使用,只不過它不能夠被繼承。因此,結構
同樣具有欄位、屬性與方法。
– 以下是System.DateTime結構常用的屬性與方法。
79
5.4.4
System.DateTime結構
80
81
5.4.4
System.DateTime結構
• 【範例5-3】
– 觀察System.Math類別提供的各種取整數方法,並印出系統時間。
• 範例5-3:
– 網站目錄 ASPNET\ch05\ch05_03\(檔案ch05_03.aspx)
– Step1:網頁介面設計【採用絕對位置,配置與屬性請自行參閱檔案】:當中
包含一個Button按鈕控制項,名稱為Button1及多個Label標籤控制項。
82
5.4.4
System.DateTime結構
– Step2:撰寫Button1_Click()事件程序碼如下:
• 程式部分內容:
7
8
9
10
11
12
13
14
15
16
17
18
Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
Dim N1() As Double = {3.4, 3.5, 3.6, 8.4, 8.5, 8.6}
Dim N1A(5), N1B(5), N1C(5) As Integer
Dim N2() As Double = {-3.4, -3.5, -3.6, -8.4, -8.5, -8.6}
Dim N2A(5), N2B(5), N2C(5) As Integer
For i As Integer = 0 To N1.Length - 1
N1A(i) = Math.Round(N1(i))
N1B(i) = Math.Floor(N1(i))
N1C(i) = Math.Ceiling(N1(i))
Next
83
'計算後暫時存入陣列
5.4.4
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
System.DateTime結構
For i As Integer = 0 To N2.Length - 1
N2A(i) = Math.Round(N2(i))
N2B(i) = Math.Floor(N2(i))
N2C(i) = Math.Ceiling(N2(i))
Next
'計算後暫時存入陣列
For i As Integer = 0 To N1.Length - 1
'組織輸出字串
Label1.Text = Label1.Text & " 【 " & N1A(i) & " 】"
Label2.Text = Label2.Text & " 【 " & N1B(i) & " 】"
Label3.Text = Label3.Text & " 【 " & N1C(i) & " 】"
Next
For i As Integer = 0 To N2.Length - 1
'組織輸出字串
Label4.Text = Label4.Text & " 【 " & N2A(i) & " 】"
Label5.Text = Label5.Text & " 【 " & N2B(i) & " 】"
Label6.Text = Label6.Text & " 【 " & N2C(i) & " 】"
Next
timeLbl.Text = "製表時間" & DateTime.Now.ToString()
End Sub
84
5.4.4
System.DateTime結構
– 範例說明:
• (1) 第14~16行:由於三個取整數方法都是共用方法,故以「類別
名稱.方法名稱()」執行即可,例如Math.Round(N1(i)),代表要將
傳入之引數N1(i)取整數。各種取整數的結果不同,請自行對照執
行結果與表5-9的說明。
• (2) 第36行,要求取得DateTime類別的共用屬性Now,此時將獲得
一個DateTime物件,在要求此物件執行ToString()方法,就會將內
容轉為字串。
85
5.4.4
System.DateTime結構
– Step3:執行程式。
86
5.4.5
System.Random類別
• 在現實生活中,有許多的現象與隨機亂數有關。在程式設計
中,我們可以使用亂數函式來模擬大量的隨機資料,例如統
計與實驗、電腦遊戲、樂透開獎等等。
– 傳統VB提供的內建亂數函式為Rnd與Randomize(後被規劃在
Microsoft.VisualBasic.VBMath類別),但使用上必須多加注意,以免
出現亂數不斷重複的狀況。
– 而.NET Framework則規劃System.Random類別用來處理亂數。
87
5.4.5
System.Random類別
88
5.4.5
System.Random類別
• 【範例5-4】
– 使用亂數類別,產生7個1~49的整數,最後一個作為特別號(暫時不
要求數字不重複)。
• 範例5-4:
– 網站目錄 ASPNET\ch05\ch05_04\(檔案ch05_04.aspx)
– Step1:網頁介面設計【略,屬性請自行參閱檔案】:當中包含一個
Button按鈕控制項,名稱為Button1及2個Label標籤控制項。
89
5.4.5
System.Random類別
– Step2:撰寫Button1_Click()事件程序碼如下:
• 程式部分內容:
7
8
9
10
11
12
13
14
15
16
17
18
Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
Dim arr(5) As Integer
Dim r As New Random()
'r為亂數物件
Label1.Text = "開獎六球 "
For i As Integer = 0 To arr.Length - 1
arr(i) = r.Next(1, 50)
'亂數將為1~49
Label1.Text &= "【" & CStr(arr(i)) & "】 "
Next
Label2.Text = "特別號 "
Label2.Text &= "【" & CStr(r.Next(1, 50)) & "】 "
End Sub
90
5.4.5
System.Random類別
– 範例說明:
• (1) 第13行:使用r.Next(1,50)取得一個介於1~49的整數。r為Random物
件。
• (2)由於並未檢查每次取出的亂數是否重複,因此可能出現數字重複的現
象,如執行結果中的37。
– Step3:執行程式。
91
5.4.6
System.Array類別
• 陣列是設計程式時常用的資料結構,我們常常需要在陣列中搜尋某些資料,
也可能要求將陣列的元素進行排序,為了這些需求,.NET Framework提
供了System.Array類別以便對陣列進行某些應用。
– 事實上,System.Array類別是CLR實作陣列時的基底類別,當您試圖宣告一
個System.Array類別的物件並透過New產生實體時,編譯器會告知您,這是
一個必須繼承後使用的類別。
– 然而我們仍無法繼承它來使用,因為只有系統與編譯器可以明確地繼承Array
類別來使用。
– 不過您並不用擔心無法使用Array類別的屬性或方法,因為所有的陣列都衍生
自Array類別,因此,所有的陣列都可以使用Array類別的屬性或方法,故我們
只需要透過陣列宣告的語法建立陣列後,就可以將該陣列視為實體,然後直
接要求執行方法或取得屬性。
– 例如之前介紹陣列時,我們曾以arr.Length取得陣列元素個數(假設arr為陣列
名稱),而Length就是繼承自Array類別的屬性。
• Array類別的屬性與方法眾多,以下撷取部分好用的屬性與方法。
92
93
5.4.6
System.Array類別
• 【範例5-5】
– 修改範例5-4,使得7個亂數都不重複。並另外將之排序顯示。
• 範例5-5:
– 網站目錄 ASPNET\ch05\ch05_05\(檔案ch05_05.aspx)
– Step1:網頁介面設計【略,屬性請自行參閱檔案】:當中包含一個
Button按鈕控制項,名稱為Button1及3個Label標籤控制項。
94
5.4.6
System.Array類別
– Step2:撰寫Button1_Click()事件程序碼如下:
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
Const balls As Integer = 6
'不含特別號之總球數
Dim arr(balls - 1) As Integer
Dim arr2(balls - 1) As Integer
'將存放排序後的球
Dim reGenTimes, num As Integer
Dim r As New Random()
'r為亂數物件
Label1.Text = "開獎" & CStr(balls) & "球 "
For i As Integer = 0 To arr.Length - 1
num = r.Next(1, 50)
While (Array.IndexOf(arr, num, 0, i) >= 0) '若重複,則進入迴圈重取
num = r.Next(1, 50)
'重取球號
reGenTimes = reGenTimes + 1
End While
arr(i) = num
Label1.Text &= "【" & CStr(arr(i)) & "】 "
Next
95
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Label2.Text = "特別號 "
num = r.Next(1, 50)
While (Array.IndexOf(arr, num, 0, balls) >= 0)
num = r.Next(1, 50)
reGenTimes = reGenTimes + 1
End While
'最後num存放的是特別號
Label2.Text &= "【" & CStr(num) & "】 "
Label2.Text &= " 已經重複取過" & reGenTimes & "次球"
'以下是排序球號
Array.Copy(arr, arr2, arr.Length)
Array.Sort(arr2)
'複製陣列
'對arr2陣列元素排序
sortLbl.Text = "開獎排序 "
For i As Integer = 0 To arr2.Length - 1
sortLbl.Text &= "【" & CStr(arr2(i)) & "】 "
Next
End Sub
96
5.4.6
System.Array類別
– 範例說明:
• (1)第16~20行:我們在這裡加入了一個迴圈,因為每次產生的球
號可能會與之前的球號重複,故利用Array.IndexOf(arr, num, 0, i)
求出是否陣列中已經有該球號,回傳值為負數者才代表不重複,
而尋找過程是逐漸增加搜尋的陣列範圍。
• (2)第26~30行:取得特別號時同樣必須確保是否重複,不過此時
我們可以確定搜尋的陣列範圍,也就是從索引0開始,搜尋balls個
元素即可,故為Array.IndexOf(arr, num, 0, balls)。
• (3) 第36~42行:此處是為了要將球號進行排序。首先在第36行,
將存放球號的陣列複製到arr2。然後在第37行對arr2陣列進行排序。
97
5.4.6
System.Array類別
• (4)本程式可以將開球數balls最大增加到48球(因為要保留一個特
別號)。您可以試著修改第8行將balls設定為48,就可以很容易由
排序後的結果觀察到球號絕對不會重複。若您將balls設定超過49,
則會由於必定產生重複,而使得迴圈無法停止,此時瀏覽器會一
直等待伺服器的回應(伺服器因迴圈無法停止而無法產生回應),
而導致最後顯示網頁逾時。
– Step3:執行程式。
98
5.4.7
線上說明
• 在本節中,我們介紹了許多的類別與方法,但無法進行全方面的介紹,若
讀者需要查閱相關的資訊,可自行查閱線上說明,網址如下:
– 【中文】http://msdn.microsoft.com/zh-tw/library/default.aspx
– 【英文】http://msdn.microsoft.com/en-us/library/default.aspx
• 線上說明的左方會列出微軟的技術分類,我們要查詢的分類大多位於開發
工具和語言(Development Tools and Languages)或.NET開發(.NET
Development)分支中。
– 或者您也可以於上方的搜尋框中輸入相關的關鍵字進行搜尋。
99
圖 5-4 線上說明網頁
100
5.4.7
線上說明
• 理論上,使用VB.NET開發ASP.NET時,除了以System開頭
的命名空間內的類別可以使用外,Microsoft.VisualBasic命名
空間內的類別也可以使用,但有時候還是會出現一些問題。
– 例如Microsoft.VisualBasic.Interaction類別的MsgBox()方法是在VB程
式中產生一個對話方塊。而若使用於ASP.NET,雖然在VWD開發時
可以使用MsgBox()方法產生一個對話方塊進行測試,但等到實際上線
時可能會無法出現對話方塊
• 這是因為最終網頁是在客戶端瀏覽器中顯示,而瀏覽器要產生對
話方塊應該使用JavaScript的alert()產生。
• 而開發時會產生對話方塊,則是因為該對話方塊是伺服器端產生
的,但它卻不能透過網路傳送到客戶端(除非送出一段包含alert的
JavaScript程式)。
101
5.5 網頁生命週期與Page物件
• 在介紹各類控制項之前,首先我們將說明何謂一個網頁的生
命週期,而在此生命週期中,將會引發一些網頁物件(Page物
件)的事件。
102
5.5.1
ASP.NET生命週期
• 在ASP.NET的程式設計與架構中,談到生命週期有關的技術一共有兩種:
2) ASP.NET Page Life Cycle。
– (1)ASP.NET Application Life Cycle。
– (2) ASP.NET Page Life Cycle。
• ASP.NET Application Life Cycle(ASP.NET應用程式生命週期)
– ASP.NET Application Life Cycle(ASP.NET應用程式生命週期)包含了從客
戶端送出某個.aspx檔的請求直到伺服器回應這個請求為止。
– 其中,IIS 5.x與IIS 6.x對於此要求的處理方式必須使用到aspnet.isapi.dll檔,
這是一個伺服器的ISAPI擴充程式,功能是作為ASP.NET引擎。
– 而IIS 7.0則將之整合為統一的請求處理管線。其內部使用了HttpApplication物
件進行複雜的流程,此流程稱之為HttpApplication管線內的流程
– 通常只有想要擴充HttpApplication類別的開發人員才需要深入了解,初學者並
不需要了解。
103
圖5-4
ASP.NET應用程式生命週期的HttpApplication管線「執行鏈」流程
104
5.5.1
ASP.NET生命週期
• 比較需要注意的是,HttpApplication物件在引發了一連串的事件之後,會
進入一個特殊的編譯階段。
– 此時,它會根據要求資源的副檔名 (對應在組態檔中),選取實作IHttpHandler
介面以處理要求的類別。
– 如果要求是針對衍生自Page類別的物件(也就是網頁),則需要編譯網頁,換
句話說,ASP.NET會在建立網頁的執行實體之前進行編譯。
• 接著繼續引發一些事件,然後會呼叫要求之適當IHttpHandler類別的
ProcessRequest方法。
– 例如,如果是要求網頁,則目前的網頁執行實體就會處理要求。而網頁執行
實體處理要求時,就是開始了ASP.NET Page Life Cycle。
• 而最後則在回送之前,引發一連串的事件後進行回送給客戶端的動作。
– 我們在圖5-4中,這些省略了這些事件的說明,讀者只需要了解圖5-4實體方框
中發生的重要階段即可。
105
5.5.1
ASP.NET生命週期
• ASP.NET Page Life Cycle(ASP.NET網頁生命週期)
– 由圖5-4中,我們可以得知,ASP.NET網頁生命週期是包含在
ASP.NET應用程式生命週期之中。因為ASP.NET網頁生命週期必須
在開始前,已經將網頁的類別編譯完畢,才能夠以實體方式執行網頁。
– 網頁在生命週期內會進行一系列動作,這些動作包含初始化、產生控
制項、還原與維護狀態、執行事件處理程序的程式碼和呈現。
• 若想要開發自訂控制項,則必須了解其細節。
– 而對於一般使用者,則應了解在執行事件處理程序的程式碼之前,網
頁進行了什麼動作,並引發了哪些網頁事件。
• 一般來說,網頁會歷經表5-13中所整理的各種階段(也就是圖5-4
中,右下角【執行網頁】方塊中會歷經的階段)。
106
5.5.1
ASP.NET生命週期
107
5.5.1
ASP.NET生命週期
108
5.5.2
Page物件
• Page物件代表網頁執行時的實體(又稱為網頁執行個體)。
在前面章節中,我們已經知道每一個ASP.NET網頁的內容會
被視為一個類別進行編譯,此類別是Page的衍生類別。
• Page類別的全名是System.Web.UI.Page類別。當您在線上
說明查閱該類別時,會發現除了
CreateHtmlTextWriterFromType方法,其餘該類別的所有方
法與屬性都是非公用方法與屬性。
– 這說明了,要執行或取得這些屬性,必定需要以實體來執行。
– 而網頁執行時,就是代表該實體正在運作。
– 若在程式撰寫階段想要撰寫代表網頁本身的物件,可以使用Me來取代。
109
5.5.2
Page物件
• 一般來說,我們很少會自行要求執行哪個Page物件的方法,但網頁同樣
具有某些內定的事件,並且其對應的事件處理程序名稱也已經固定為
Page_事件名稱(除非您使用@ Page 指示詞更動了 AutoEventWireup的
屬性值)。
– 而這些事件會在網頁生命週期的特定階段中自動按照順序產生,因此,我們
只需要將程式碼撰寫於這些事件處理程序中即可。
• Page類別的事件眾多,但在VWD中,我們能選擇的只有少數幾個,其餘
則需要自行建立。其中最常使用的為PreInit、Init、Load、PreRender、
Unload等五個事件,整理如表5-14:
110
5.5.2
Page物件
111
5.5.2
Page物件
112
5.5.2
Page物件
113
5.5.2
Page物件
114
5.5.2
Page物件
• 【範例5-6】觀察網頁事件的發生順序。
• 範例5-6:
– 網站目錄 ASPNET\ch05\ch05_06\(檔案ch05_06.aspx)
– Step1:網頁介面設計【略,屬性請自行參閱檔案】:當中包含一個Button按
鈕控制項及1個Label標籤控制項(都使用預設名稱)。
– Step2:撰寫<script>程式碼如下:
5
6
7
8
9
10
11
12
13
<script runat="server">
Private str As New String("")
'自訂Page類別的新欄位
Protected Sub Page_PreInit(sender As Object, e As System.EventArgs)
str &= "Page_PreInit執行中 <br/>"
Label1.Text = str
End Sub
115
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Protected Sub Page_Init(sender As Object, e As System.EventArgs)
str &= "Page_Init執行中 <br/>"
Label1.Text = str
End Sub
Protected Sub Page_Load(sender As Object, e As System.EventArgs)
str &= "Page_Load執行中 <br/>"
Label1.Text = str
End Sub
Protected Sub Page_PreRender(sender As Object, e As System.EventArgs)
str &= "Page_PreRender執行中 <br/>"
Label1.Text = str
End Sub
Protected Sub Page_Unload(sender As Object, e As System.EventArgs)
str &= "Page_Unload執行中 <br/>"
Label1.Text = str
End Sub
116
5.5.2
34
35
36
37
38
39
40
41
42
43
Page物件
Protected Sub Page_LoadComplete(sender As Object, e As System.EventArgs)
str &= "Page_LoadComplete執行中 <br/>"
Label1.Text = str
End Sub
Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
str &= "Button1_Click執行中 <br/>"
Label1.Text = str
End Sub
</script>
– 範例說明:
• (1)第19~22行:Page_Load是Page物件的事件程序,要建立
Page_Load事件程序,可以在設計頁籤無控制項的空白處按兩下,
就會自動於原始檔中產生此事件程序。
117
5.5.2
Page物件
• (2)第9~37行:這些程序都是Page物件的事件程序,請直接輸入或
複製Page_Load事件程序的宣告列,然後加以更改名稱。
• (3)在執行結果中,您會發現,當網頁第一次讀取時,並不會出現
「Button1_Click執行中」的字樣,因為該事件程序並未被執行過,
而其他事件程序則會在網頁回傳前就已經執行(Page_Unload除
外)。
– 當瀏覽器第一次收到網頁內容時,Page_Unload也在伺服器端
被執行,但它是在送出資料後才執行的,因此瀏覽器不會收到
「Page_Unload執行中」的字串(如果是將之寫入到伺服器端
的檔案,就可開啟檔案來觀察)。
• (4)第二次要求執行網頁時,是按下【執行】鈕進行的,因此,
Button1_Click事件程序也會被執行,您可以從執行結果中看出,
它是在「Page_PreRender」事件程序之前,「Page_Load」事件
程序之後被執行。而一般我們並不會撰寫Page_LoadComplete事
件程序。故可以將五個常用的事件程序繪製如圖5-6。
118
5.5.2
Page物件
– Step3:執行程式。
119
圖5-5
ASP.NET網頁生命週期執行的事件程序
– 【註】Page類別還有很多方法與屬性、欄位,我們將於後面章節中介紹。
120
5.5.3
Response屬性
• 傳統ASP有五大內建物件可以使用,即Response物件、Request物件、
Session物件、Application物件與Cookies集合物件(或稱
Response.Cookies資料集合)。
– 在ASP.NET中同樣可以使用這五種物件,但方式略有不同。
• 上述類型的物件,在ASP.NET中,變成了Page物件的屬性(Cookies則
為Request、Response屬性的屬性)
– 正如同之前所言,物件可以由小物件組成,亦即類別的欄位或屬性可以宣告
為另一個類別型別,此時,產生實體時,大物件就可以包含許多小物件。
– 例如網頁中若包含眾多控制項,則Page物件的某些欄位就是控制項物件。同
理,在讀取Page物件的這四個屬性時,獲得的將是一個物件,其型別分別為
HttpResponse、HttpRequest、HttpSessionState、HttpApplicationState類別。
– 在本章中,我們將介紹Response屬性與Request屬性,其餘兩個屬性則留待
第10章時再介紹。
121
5.5.3
•
Response屬性
HttpResponse類別
– 讀取Page.Response屬性時,將獲得一個System.Web.HttpResponse類別的
物件。
– 它的功能和傳統ASP的Response物件相同,基本功能是用來傳送資料給客戶
端。相關的方法與屬性整理如表5-15及5-16:
122
5.5.3
Response屬性
– 【註】
– ASP.NET包含兩個內建Cookie集合,分別是Page.Response.Cookies與
Page.Request.Cookies。
• Page.Response.Cookies是用來寫入客戶端瀏覽器的Cookie。
• 而Page.Request.Cookies則是讀取客戶端瀏覽器的Cookie。
123
5.5.3
Response屬性
• 集合(Collection)
– 集合(Collection)或稱資料集合是一種新型態的資料結構。
– 多數新的程式語言都漸漸以類別方式提供集合,其主要目的是為了免
除程式設計師設計常用資料結構(例如佇列、堆疊、串列、雜湊表)
時的麻煩。
– 並且通常集合還支援泛型,也就是集合中的資料項目可以指定為任一
種資料型別。
– 而.NET Framework的集合類別則規劃在System.Collections命名空間
(非泛型)與System.Collections.Generic命名空間(泛型)中。
– 而VB也可以使用Microsoft.VisualBasic命名空間內的Collection類別建
立簡單的集合物件。
124
5.5.3
Response屬性
• 集合一般分為兩大類,Collection與MapCollection。
• 1. Collection集合:
– 可以將此視為單一元素之集合。您可以將之想像為會自動變動長度的陣列,
一般至少會提供新增、移除、「依照索引取出元素」等的操作。其餘則視不
同的集合物件而提供更多的功能。
– 包含在System.Collections命名空間內的類別大多屬於此類。例如
System.Collections.Queue類別。
• 2. MapCollection集合:
– 可以將此視為成對(pair)之集合,每個元素是由兩個值組成,一個為key,另
一個為value,而每一個key至多只能映射(mapping)到一個value。
– 電腦科學中常見的雜湊表(hash table),即為此類。一般會提供「以key查詢對
應之value」的操作。其餘則視不同的集合物件而提供更多的功能。
– 包含在System.Collections.Specialized命名空間內的類別大多屬於此類。例如
System.Collections.Specialized.NameValueCollection類別,其應用請見範例
5-9。
125
5.5.3
Response屬性
– Page.Response.Cookies將回傳一個HttpCookieCollection型別的物件,
而HttpCookieCollection 類別由於繼承自
System.Collections.Specialized.NameObjectCollectionBase類別,故
也屬於此類。關於Cookie的應用,我們等到第10章再進行示範。
• Response的應用
– 在傳統ASP的程式設計中,幾乎無可避免地必須使用Response.Write
來傳送資料,但在ASP.NET中,除了單純輸出資料給網頁的範例之外,
我們並不建議您使用Response.Write來傳送資料。
– 在表5-15中的各方法,在ASP.NET網頁中應用較多的為Redirect (s)方
法,它可以用來進行網頁的自動導向。
– 以下提供兩個範例來說明Response的應用。
126
5.5.3
Response屬性
• 【範例5-7】
– 使用Response.Write回傳資料,並觀察資料出現位置。
• 範例5-7:
– 網站目錄 ASPNET\ch05\ch05_07\(檔案ch05_07.aspx)
– Step1:網頁介面設計【略,屬性請自行參閱檔案】:當中只包含一
個Button按鈕控制項(使用預設名稱)。
– Step2:撰寫<script>內的三個事件程序如下:
• 程式部分內容:
127
5.5.3
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Response屬性
<script runat="server">
Protected Sub Page_Load(sender As Object, e As System.EventArgs)
Response.Write("Page_Load執行中 <br/>")
End Sub
Protected Sub Page_Unload(sender As Object, e As System.EventArgs)
'Response.Write("<br/>") '在此程序中不能使用Response.Write
End Sub
Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
Response.Write("Button1_Click執行中 <br/>")
Button1.Text = "已按下過"
End Sub
</script>
128
5.5.3
Response屬性
– 範例說明:
• (1)第7~9行:在Page_Load事件程序中使用Response.Write輸出
一個字串。
• (2)第15~18行:在Button1_Click中,使用Response.Write輸出一
個字串,並且更改按鈕文字,藉以區別是否為第二次讀取網頁。
• (3)第11~13行:在Page_Unload事件程序中不能使用
Response.Write,因為在此事件發生時,輸出的資料已經傳送給
瀏覽器,無法再送出資料。
• (4)在這個範例中,我們使用Response.Write傳送資料時,並未以
類別共用屬性(Page. Response)或物件屬性的方式取得
HttpResponse物件,而為了與傳統ASP相容,ASP.NET也允許我
們這樣做(事實上,我們只是省略了Me.而已)。
129
5.5.3
Response屬性
• (5)觀察執行結果,您可以發現,Response.Write輸出的資料將位於所有
控制項之上(也就是網頁開頭),若您在瀏覽器中執行【檢視原始檔】指
令,會發現使用Response.Write輸出的字串將位於最上方(比
<!DOCTYPE …>還要早出現)。因此,除非是為了說明範例,否則在正
式的ASP.NET網頁中,我們並不建議使用Response.Write輸出資料,以
免增加網頁元件配置的複雜化。
– Step3:執行程式。
130
5.5.3
Response屬性
• 【範例5-8】
– 使用Response. Redirect將網頁轉向到其他網頁。
• 範例5-8:
– 網站目錄 ASPNET\ch05\ch05_08\(檔案ch05_08.aspx)
– Step1:網頁介面設計【略,屬性請自行參閱檔案】:當中只包含兩
個Button按鈕控制項(使用預設名稱)。
– Step2:撰寫<script>內的兩個事件程序如下:
• 程式部分內容:
131
5
6
7
8
9
10
11
12
13
14
<script runat="server">
Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
Me.Response.Redirect("http://tw.yahoo.com/")
End Sub
Protected Sub Button2_Click(sender As Object, e As System.EventArgs)
Page.Response.Redirect("http://www.google.com.tw/")
End Sub
</script>
– 範例說明:
• (1)第8行:在Button1_Click程序使用Response.Redirect將網頁導向到
Yahoo網站。在此我們採用的是物件取屬性然後執行方法的方式。此處的
物件以Me來代表,也就是網頁物件本身。
• (2)第12行:在Button2_Click程序使用Response.Redirect將網頁導向到
Google網站。在此我們採用的是共用屬性然後執行方法的方式,雖然當
您查閱線上文件時,Response並非共用屬性,但由於Page物件只有一個,
因此ASP.NET也允許我們這樣做。
– Step3:執行程式。
132
5.5.3
Response屬性
133
5.5.3
Response屬性
134
5.5.4
Request屬性
• 在傳統ASP中,Response可用來寫入資料傳送給客戶端瀏覽
器,而Request則可以用來接收由客戶端瀏覽器傳送過來的資
料,這些資料除了基本的表頭之外,只能接收網頁表單
<form>內的資料。
• 在ASP.NET中,讀取Page.Request屬性時,將獲得一個
System.Web.HttpRequest類別的物件。
– 它的功能和傳統ASP相同,都是用來讀取客戶端傳送到伺服器端的資
料(例如表單form內的資料)。
– 而相關的資料也放置在System.Web.HttpRequest類別的某些屬性中,
整理如表5-7:
135
5.5.4
Request屬性
136
5.5.4
Request屬性
– 我們並不建議您使用Form或QueryString屬性查閱客戶端傳送過來的
表單資料,因為在ASP.NET的新模型下,應該以事件驅動方式來設計
程式。
– 以下我們僅提供一個簡單範例說明Page.Request屬性的使用方法。
• 【範例5-9】
– 使用Page.Request讀取表單資料、瀏覽器資訊,以及示範如何使用
NameValueCollection集合。
• 範例5-9:
– 網站目錄 ASPNET\ch05\ch05_09\(檔案ch05_09.aspx)
137
5.5.4
Request屬性
– Step1:網頁介面設計使用絕對方式配置控制項,當中包含兩個
TextBox文字方塊、一個Button按鈕及四個Label標籤(全部使用預設
名稱)。
– Step2:撰寫Button1_Click事件程序如下:
• 程式部分內容:
138
5.5.4
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Request屬性
Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
Dim MyCo1 As System.Collections.Specialized.NameValueCollection
Label1.Text = "" : Label2.Text = "" : Label3.Text = "" : Label4.Text = ""
MyCo1 = Me.Request.Form()
'讀取收到的表單資料並放入MyCo1中
Label1.Text = "TextBox1文字方塊內容為:" & MyCo1.Get("TextBox1")
For Each str As String In MyCo1 '使用迴圈取出集合內的所有成對元素
Label2.Text &= str & "<br />"
Label3.Text &= MyCo1.Get(str) & "<br />"
Next
Label4.Text = "客戶端瀏覽器為:" & Me.Request.Browser.Browser
End Sub
139
5.5.4
Request屬性
– 範例說明:
• (1)第12行:透過Form屬性取得表單資料,其回傳值是
NameValueCollection資料集合類別的物件,故我們在第8行宣告
MyCol物件變數。這個集合是成對集合,每個元素包含Name與
Value兩個欄位,其中Name具有key的性質。
• (2)第14行:NameValueCollection集合類別提供了Get方法,只要
指定其Name的值(即key值),就會把對應的Value值回傳。故我們
指定要讀取Name=“TextBox1”的元素之Vaule值。
• (3)第16~19行:由於集合可以看作是自動變動長度的陣列,因此
也可以使用For Each迴圈一一讀取元素值。而讀出的值為各元素
的Name欄位。因此,我們另外再使用Get方法取出對應的Value欄
位值。由執行結果可知,一共會讀到五個元素,故可以將MyCol集
合物件之內容繪製如下圖。
140
5.5.4
Request屬性
• (4)第21行:Request.Browser會回
傳一個HttpBrowserCapabilities類別
的物件,而該類別又提供了一個
Browser屬性,該屬性代表客戶端瀏
覽器的種類。
• (MyCol集合中包含五個元素,其中
TextBox1,TextBox2,Button1都是控
制項,在HTML的表單中,會以下
列三個input標籤表示(請於第一次
讀取網頁後在瀏覽器中檢視原始
碼),齊中name屬性值會被放入
Name欄位。而文字方塊的值會被放
入Value欄位,至於submit按鈕,則
是將其value屬性值放入Value欄位。
141
圖5-6 成對元素之集合示意圖
5.5.4
Request屬性
<form name="form1" method="post" action="ch05_09.aspx" id="form1">
<input name="TextBox1" type="text" id="TextBox1" style="………" />
<input name="TextBox2" type="text" id="TextBox2" style="………" />
<input type="submit" name="Button1" value="傳送" id="Button1" style="………" />
</form>
• (MyCol集合中另外兩個元素,__VIEWSTATE及
__EVENTVALIDATION,則會以<input type="hidden"………>標
籤來表示,故在網頁中看不到顯示效果。事實上,這兩個欄位在
ASP.NET的設計中非常重要,我們會於後面章節解釋。在執行本
範例時,請您多按幾下【傳送】鈕,就會發現__VIEWSTATE的值
除了第一次與第二次不同之外,第二次之後不論您按幾下【傳送】
鈕都不會改變(後面章節中會解釋原因)。
142
5.5.4
Request屬性
– Step3:執行程式。
143
144
5.6 共用事件程序
• 到目前為止,我們撰寫的事件程序都有兩個參數sender 與e,而這兩個參
數的意義與用途如下:
– sender參數:
• 代表產生事件的物件,也就是事件來源者。例如在Button1_Click事件程序
中,通常是Button1引發了Click事件,故sender代表的就是Button1物件。
而sender的型別雖然被宣告為Object,但由於任何類別都是Object的子孫
類別,故可以傳入任何類別型別的物件作為sender。
– e參數:
• 這是一個事件物件,可以透過此物件取得更多有關於該事件的資訊。
– 通常e參數很少被使用作為程式設計的一般用途(除資料控制項以外),這是
因為不同事件傳入的物件並不相同。
• 例如大多數控制項的預設事件程序之e參數為System.EventArgs類別型別,
但ImageButton控制項的預設事件程序之e參數則為
System.Web.UI.ImageClickEventArgs類別型別,而它是
System.EventArgs類別的衍生類別。
145
5.6 共用事件程序
– 比較有用的是sender參數,因為它可以代表觸發此事件的物件。當然
在一般狀況下,只會有一個物件會觸發該事件,但若我們使用共用事
件程序的技巧時,這個參數就派得上用場了。
• 舉例來說,若我們有兩個按鈕,名稱為Button1與Button2,則可以
讓兩個按鈕在按下時,都執行Button1_Click()事件程序。
• 要達到此功能,只要先建立Button1_Click()事件程序,然後在屬性
窗格中,設定Button2物件的Click事件處理程序為Button1_Click即
可(設定時,必須切換到事件頁籤),過程如下圖:
146
147
5.6 共用事件程序
• 【範例5-10】
– 改寫範例5-8,使兩個按鈕共用事件處理程序,並藉由sender參數判別
使用者按下了哪一個按鈕,然後導向至正確的網頁。
• 範例5-10:
– 網站目錄 ASPNET\ch05\ch05_10\(檔案ch05_10.aspx)
– Step1:網頁介面設計【同範例5-8】:當中包含兩個Button按鈕控制
項。
– Step2:如上圖設定Button2物件的Click事件處理程序為Button1_Click。
(請利用屬性窗格設定,不要直接修改標籤內容)
– Step3:撰寫Button1_Click程序碼如下:
• 程式部分內容:
148
5.6 共用事件程序
7
8
9
10
11
12
13
Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
If sender.ID = "Button1" Then
Me.Response.Redirect("http://tw.yahoo.com/")
ElseIf sender.ID = "Button2" Then
Page.Response.Redirect("http://www.google.com.tw/")
End If
End Sub
– 範例說明:
• 第8~12行:使用sender.ID判斷是哪一個物件觸發了事件,亦即是
哪一個物件是事件來源者。ID屬性是每一個伺服器控制項都有的
屬性,用以識別各控制項。
– Step4:執行程式。程式執行結果同範例5-8。
149
5.7 本章回顧
•
在本章中,我們介紹了VB關於物件導向的相關術語(除了例外處理),
包含下列項目:
–
–
–
–
–
–
–
•
1. 類別、結構、封裝、繼承、多型(覆寫與介面)
2.繼承與實作、ASP.NET的網頁繼承(Page類別的繼承)
3.欄位(Field) 和屬性(Property)
4.建構函式(Constructor)、方法(Method)、多載(Overloading)
5.共用方法(Shared Method) 和共用欄位(Shared Filed)
6.事件驅動與事件處理程序(event-handling method)
7.字串類別與字串型別的關係
在本章中,我們也介紹了.NET Framework的命名空間與常用類別,包含
下列項目:
–
–
1..NET Framework使用命名空間管理類別。
2.開發ASP.NET時自動引入的命名空間。
150
5.7 本章回顧
–
–
–
–
–
–
–
–
–
–
3. Microsoft.VisualBasic命名空間提供傳統VB的內建函式與新的類別。
4.在ASP.NET中,引入命名空間的方式。
5.類別名稱衝突時採用類別全名(命名空間+類別)解決。
6. Microsoft.VisualBasic.Information類別的方法可用來進行型別判斷或資料判
斷。
7.System.Object類別:所有類別的祖先類別。
8.System.String類別:VB的字串資料型別會在編譯時,對應到此類別,故可
以當作物件執行相關方法。而String字串是不可變更內容的字串。
9.System.Math類別:提供數學運算功能。
10.System.Math類別:提供數學運算功能。
11.System.Random類別:可產生亂數。
12. System.Array類別:所有的陣列都衍生自Array類別,其中有些方法可以
對陣列元素進行搜尋與排序。
151
5.7 本章回顧
• 在本章的最後則介紹了ASP.NET的生命週期以及代表網頁的Page類別,
包含下列項目:
– 1. ASP.NET生命週期分為ASP.NET應用程式生命週期與ASP.NET網頁生命週
期。並且ASP.NET網頁生命週期包含在ASP.NET應用程式生命週期之內。
– 2.ASP.NET網頁生命週期會經歷的階段,以及各階段的主要工作。
– 3.Page類別代表網頁程式碼。Page物件則代表網頁執行時的實體。
– 4.Page物件的存滅同樣代表了ASP.NET網頁生命週期。在此過程中,會觸發
許多事件。在Page_Unload ()事件處理程序中,已經無法對客戶端的顯示造
成改變。
– 5. Page.Response屬性可用來輸出資料或進行網頁導向。
– 6.Page.Request屬性可用來讀取客戶端瀏覽器的資訊以及傳送過來的表單資
料。
– 7.集合(Collection) 可想像為會自動變動長度的陣列,並且可以使用For Each
迴圈取出其中的元素。
152
5.7 本章回顧
– 8. NameValueCollection類別是一種MapCollection集合,它的元素具有兩個
欄位,一個是用來作為key(鍵值)的Name欄位,另一個則是對應的Value欄
位。
– 9.ASP.NET表單資料中,包含兩個隱藏欄位__VIEWSTATE及
__EVENTVALIDATION。
– 10. 在事件程序中,sender參數是事件來源者。
• 由於本章內容較為深入,若某部分不是很了解,可能是因為您對於VB的
語法不熟悉的緣故。不過對於後續章節的影響並不大。但了解本章內容將
有助於您熟悉ASP.NET的編譯與執行,以及查閱線上說明時減少困惑。
153
本章習題
154