iT邦幫忙

DAY 9
6

ASP.NET 由淺入深系列 第 9

91之ASP.NET由淺入深 不負責講座 Day9 - Page Life Cycle

一個ASP.NET Webform工程師,一定得知道的東西,就是頁面生命週期的順序,以及在每個事件該放什麼樣的code。這幾乎已經列在每一家開發Web系統公司面試題目必考題。
這邊簡單做個整理,如果您還不知道,就趁機把ASP.NET Webform頁面運作的機制瞭解一下。

沒有瞭解頁面的生命週期、事件的順序,就沒法把對應的code寫在最對的事件上,不瞭解頁面生命週期的工程師,寫出來的code,一樣會動,但是寫出來的code,不一定對。只要遇到需求變更,bug就會一一浮現出來。

這也是為什麼,這麼多面試ASP.NET工程師的場合,都會問這問題的原因。因為一次就可以篩選出,真正有用心去瞭解ASP.NET頁面運作原理的工程師。而不是講了一嘴自己寫了幾年ASP.NET程式,寫過幾個大系統,連這都不知道的工程師。
Page Life Cycle
Page與Control事件週期圖如下:
左邊是頁面生命週期的階段,中間是頁面生命週期的事件,右邊則是寫程式比較少用到,但設計時必須得知道發生時間點的事件。

參考資料
1.ASP.NET 網頁存留週期概觀:http://msdn.microsoft.com/zh-tw/library/ms178472.aspx
2.ASP.NET Web 伺服器控制項事件模型:[ http://msdn.microsoft.com/zh-tw/library/y3bwdsh3.aspx]( http://msdn.microsoft.com/zh-tw/library/y3bwdsh3.aspx)
3.http://blogs.msdn.com/aspnetue/archive/2010/01/14/asp-net-page-life-cycle-diagram.aspx

注意
1.有一些事件,其實是方便開發者在頁面與控制項交替進行事件時,安插在中間供彈性使用(通常就是拿來覆寫掉某些資訊)。
2.事件順序跟事件常用目的很重要
3.常用事件記憶方式:
(a)先記住Init, Load, PreRender,然後在前面加上Pre,在後面加上Complete。
額外需要注意的是,PreRender已經有Pre,而Render是另外一個特定字(是個方法),所以PreRender只要在後面加Complete。
(b)Control: Render,是一個特殊方法,而非事件。主要用來繪製最後要Render的HTML。
(c)特殊事件:
(1)Control: LoadVeiwState事件,介於InitComplete與PreLoad之間
(2)Control event,介於Load與LoadComplete之間
(3)Control: SaveViewState事件,介於PreRenderComplate與Render方法之間

事件
1.PreInit
注意:
(a)檢查 IsPostBack 屬性判斷是否是第一次處理網頁。
(b)建立或重新建立動態控制項。
(1)在這事件動態建立控制項,控制項的生命週期才會完整,尤其是有完整的ViewState相關處理。
(c)動態設定MasterPage。
(1)在這事件以後,因為頁面會自行呼叫套上主題與樣式的動作,之後的頁面事件都不允許再改變套用的MasterPage。
(d)動態設定 Theme 屬性。
(1)同MasterPage的觀念,Skin與Theme相關的屬性,只能在這個事件設定,之後就不允許改變。
(e)讀取或設定設定檔屬性值。
(f)如果這次Request是PostBack,控制項的值尚未從ViewState還原。如果在這個階段設定控制項屬性,則在下一個事件中可能會覆寫其值。

叮嚀:
(a)這個事件,因為尚未LoadViewState, 所以要讀取畫面上最新的值,只能使用Request, 因為Request的建立在頁面『開始』的階段就建立了。
(b)常見的使用情況,例如根據畫面上的下拉選單來決定套用不同的MasterPage或Theme, 此時如果用DroDownList.SelectedValue,則沒法子達到目的。 應該使用Request[DropDownList.UniqueID]。

2.Init
在初始化所有控制項並套用任何面板設定之後引發。這個事件可以用於讀取或初始化控制項屬性。

3.InitComplete
由 Page 物件引發。這個事件可以用於處理需要完成所有初始設定的工作。

4.PreLoad
(a)如果需要在 Load 事件之前先處理網頁或控制項,請使用這個物件。
(1)在 Page 引發這個事件之前,會先載入其本身和所有控制項的檢視狀態,再處理 Request 執行個體 (Instance) 所包含的任何回傳資料。
(b)叮嚀
(1)從這個事件開始,因為已經把ViewState載入, 所以大部分控制項屬性或資料如果使用ViewState當暫存機制, 這個事件之後就可以比較安心的使用控制項的屬性了。

5.Load
(a)Page 會先呼叫 Page 上的 OnLoad 事件方法,再遞迴地為每個子控制項執行相同動作,它會為其每個子控制項執行相同動作,直到載入完網頁和所有控制項為止。
(b)OnLoad 事件方法可以用於設定控制項中的屬性,以及建立資料庫連接。

叮嚀
這邊有個特性蠻特別的, 就是子控制項Init之後,才會引發Page_Init (容器的Init都會比子控制項Init晚), 但是Load的事件,卻是Page_Load(容器)之後,才會引發子控制項Load。 同樣的道理,也可以印證在UserControl裡,UserControl就是一個容器。 因為這些容器有實作INamingContainer,所以後面的ClientID都會套上container的ID當作prefix。 而MasterPage,是繼承UserControl,所以也具備UserControl的特性,故MasterPage也可以巢狀使用)。通常我會在這邊開始做控制項與資料的繫結。

6.Control events
(a)這些控制項事件可以用於處理特定控制項事件,例如 Button 控制項的 Click 事件,或 TextBox 控制項 TextChanged 事件。
(b)在回傳要求中,如果網頁包含驗證程式控制項,則在執行任何處理之前,請先檢查 Page 和個別驗證控制項的 IsValid 屬性。

叮嚀
通常對client端操作UI來說,這個Control的事件,就代表了User的操作, 而在操作之前,我們都應該檢查畫面上要使用或存入的資料,以避免存入garbage data。 這也是為什麼頁面的『驗證』階段,會擺在Control event的最前面。

通常我也會在Control Event對應的動作處理完後, 呼叫自己寫的重新binding資料的method。例如修改的存檔按鈕完,要重新整理GridView內容。

7.LoadComplete
(a)這個事件可以用於需要載入網頁上所有其他控制項的工作。

叮嚀
通常在Control Event之後,會在這根據新資料對畫面UI的顯示隱藏控制的method。 還有狀態定義改變的method(例如按了新增的按鈕後,新增成功,狀態要變成修改)

也就是根據Control的執行後,要重新整理頁面相關資料,我會寫在這邊。 (寫在Control Event的最後其實也可以,但是這樣就是耦合性變高, 因為是自己去定義動作的先後順序,而非遵循頁面生命週期的順序)

8.PreRender
在這個事件發生之前:
(a)Page 物件會呼叫每個控制項和網頁的 EnsureChildControls。
(b)每個已設定其 DataSourceID 屬性的資料繫結控制項會呼叫其 DataBind 方法。如需詳細資訊,請參閱本主題稍後的資料繫結控制項的資料繫結事件。

每個控制項的 PreRender 事件都會發生在網頁上。這個事件可以用於對網頁或其控制項的內容進行最終的變更。

叮嚀
簡單來說,這會是我拿來定義一般頁面程式撰寫,最後的一個event。 還有什麼樣式、要註冊的js、屬性,要在server端改的,這是最後一個事件了。

正因為定位在最後一個事件,所以很常拿來當作覆寫屬性的事件。 講明白點,就是『我不管前面怎麼寫,到這邊就是要這樣做』的情況,就寫在這個事件。針對的,仍然是頁面或控制項提供的東西。

9.SaveStateComplete
(a)網頁和所有控制項的 ViewState 在這個事件發生之前就已儲存了。在這之後對網頁或控制項所做的任何變更都將會被忽略。
(b)這個事件可以用於執行需要儲存檢視狀態但不對控制項做任何變更的工作。

叮嚀
MSDN上寫,『在這之後,對網頁或控制項所做的任何變更,都將會被忽略。』 所以,在PreRender的事件,才會被定義為一般使用的最後一個事件。

10.Render
(a)這不是一個事件;
(b)相反地,在這個處理階段,Page 物件會呼叫每個控制項上的這個方法。所有 ASP.NET Web 伺服器控制項都有 Render 方法,它可以寫出傳送至瀏覽器之控制項的標記。
(c)如果您建立自訂控制項,通常會覆寫這個方法,以便輸出控制項的標記。不過,如果自訂控制項只包含標準 ASP.NET Web 伺服器控制項且無任何自訂標記,就不需要覆寫 Render 方法。如需詳細資訊,請參閱 開發自訂的 ASP.NET 伺服器控制項。
http://msdn.microsoft.com/zh-tw/library/zt27tfhy.aspx
(d)使用者控制項 (.ascx 檔案) 自動會包含呈現,因此不需要在程式碼中明確呈現控制項。

叮嚀
這不是一個事件!多神奇的一句話,沒錯,他只是個固定會在呈現階段,被呼叫的一個方法。 目的就是拿來『繪製』頁面或控制項。

為什麼TextBox長的像TextBox,為什麼Button長的像Button, 為什麼GridView最後長出來是Table, 為什麼DropDownList吐出來的原始碼是Select, 都是在這邊進行繪製的動作,也就是把Server端的WebControl相關資訊,繪製成相關的HTML。

我之前有個需求,當DropDownList唯讀時,要轉成label,也是用類似的作法,覆寫成其他HTML元素來呈現

11.Unload
(a)這個事件會先發生在每個控制項上,然後才發生在網頁上。在控制項中,這個事件可以用於對特定控制項執行最終清除,例如關閉控制項特定的資料庫連接。
(b)對於網頁本身,這個事件可以用於執行最終清除工作,例如關閉開啟中的檔案或資料庫連接,或是結束登入或其他要求特定的工作。

最後,請想學習的客倌,看完這篇文章思考一下,下列的問題該如何回答:
1.頁面的事件週期,有哪一些常見的事件,按照順序排出來。
2.上述的事件通常會拿來做什麼事?
3.要調整Theme、MasterPage、SkinID得在哪一個事件?
4.那個事件之後才可以使用ViewState? 沒有ViewState時該如何讀取Form上面控制項的值?
5.Render是用來幹嘛的?
6.什麼事件之後,就不能使用ViewState了?


上一篇
91之ASP.NET由淺入深 不負責講座 Day8 - Server Controls Introduction(4)
下一篇
91之ASP.NET由淺入深 不負責講座 Day10 - 如何註冊執行一段JavaScript
系列文
ASP.NET 由淺入深30

尚未有邦友留言

立即登入留言