深入講解控制項的屬性持久化(一)
系列文章連結:
ASP.NET自訂控制項組件開發 第一章 待續
ASP.NET自訂控制項組件開發 第一章 第二篇 接著待續
ASP.NET自訂控制項組件開發 第一章 第三篇
ASP.NET自訂控制項組件開發 第二章 繼承WebControl的自訂控制項
ASP.NET自訂控制項組件開發 第三章 為控制項添加事件 前篇
ASP.NET自訂控制項組件開發 第三章 為控制項添加事件 後篇
ASP.NET自訂控制項組件開發 第四章 群組控制項開發CompositeControl
ASP.NET自訂控制項組件開發 第四章 群組控制項開發CompositeControl 後篇 --事件冒泡
ASP.NET自訂控制項組件開發 第五章 模板控制項開發
ASP.NET2.0自訂控制項組件開發 第六章 深入講解控制項的屬性
ASP.NET2.0組件控制項開發視頻 初體驗
自從寫了控制項開發的文章後,收到了不少朋友的來信,提出了不少的問題,感謝大家的關注。今天就把大家說的一些問
題來講解下。
雖然我這個系列是控制項開發,但是我的目的還是希望大家通過開發控制項更加快速的對ASP.NET有更加深入的瞭解,所以
我們也很有必要把一些基礎性的東西將清楚。
為了達到深入講解屬性的目的,我首先來講講頁面周期和頁面解析的一些問題:
1。頁面的解析:
大家可能聽說,頁面在提交給伺服器的時候,都是被解析成為了一個個的繼承與Page的類,最直接的證明就是:
Code
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
大家看看,就是那個程式碼後置
Code
CodeFile="Default.aspx.cs" Inherits="_Default"
大家也許覺得疑惑:一個aspx的頁面都是一些標記語言啊,如下面:(注意:是將下面的文本解析為一個類)
Code
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>無標題頁</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="提交" OnClick="Button1_Click" /></div>
<asp:LinkButton ID="LinkButton1" runat="server">LinkButton</asp:LinkButton>
</form>
</body>
</html>
大家也許看見了,上面的源是一個類似與XML的文檔。
當這個頁面發送到伺服器後,伺服器就開發用正則表達模式來解析這個文檔,比如,看見"<head>"就把他解析為一個
LiteralControl,如:LiteralControl head = new LiteralControl("<head>");,看見了<form>就解析為HtmlForm
類,就這樣,一個類似與XML的文檔就解析為了一個繼承於Page的cs類。如下:(偽碼,只是示範而已,真正的不是這樣的):
Code
public class Default_aspx :Page
{
//.,
HtmlForm form = new HtmlForm();
Button button1 = new Button();
buton1.Text="提交";
button1.Click+= Button1_Click(object sender, EventArgs e);
//.
//.
}
大家注意:頁面解析的時候,把我們為控制項設定的值,如Text=“ 提交”都初始化給了控制項。
然後,將解析完的類產生一個類的執行個體,之後就開始頁面的生命週期。
2.HTTP工作模式
HTTP是一種無狀態的串連模式,也就是說,用戶端像伺服器發送請求職後,伺服器響應後就不再維持用戶端的資訊。
3.綜合1,2講解屬性持久化
現在假設,在Button中沒有屬性持久化這個特點。我們看看下面的流程:
3.1:再頁面中放入一個Button按鈕,並且設定Text 屬性為“提交”,然後再Button的點擊Click事件中寫下如下
代碼:
Code
protected void Button1_Click(object sender, EventArgs e)
{
if (this.Button1.Text == "提交")
this.Button1.Text = "清空";
else
this.Button1.Text = "提交";
}
3.2:將頁面提交給伺服器,此時,就開始了頁面的解析工作,並且在解析的時候,使得Button的Text屬性設定為了
“提交”,然後就開始了頁面的生命週期。最後頁面就呈現在我們面前。
3.3:我們在瀏覽器的頁面中點擊Button按鈕,頁面就再次提交伺服器,頁面開始解析,然後開始生命週期,在周期的
某一個階段(以後講解),就會引發按鈕的Click事件,將按鈕的文本設定為”清空“,最後頁面呈現在我們面前。
3.4;當我們再次點擊按鈕,我們本來是想使得按鈕顯示”提交“,但是不管我們點擊多少次,按鈕總是顯示”清空“。
為什嗎?
因為每次把頁面提交的時候,頁面解析的結果都是將Button的Text屬性設定為”提交“,第二次點擊按鈕時,按鈕的
Text屬性顯示的是”清空“,但是一旦頁面提交後,頁面還時按照第一次那樣解析,並且初始化。按鈕的Click事件還是發現Button的Text為”提交“。因為上次提交後,按鈕的Text 屬性-”清空“,沒有儲存(基於Http協議)。
所以為了使得我們可以像 WinForm那樣開發,為了使得達到我們想要的效果。ASP.NET中就採用了”儲存狀態“技術.
4.儲存狀態技術
其實也很簡單,只是每次在頁面回傳的過程中,把上次的頁面的所有設定的狀態儲存在一個表單字串"_VIEWSTATE",中,具體是這樣的,當頁面回到用戶端的時候,伺服器就把頁面中的控制項的狀態序列化為一個字串,
一同發給用戶端,當用戶端提交頁面後,伺服器就對提交的_VIEWSTATE解析,進行還原序列化,然後根據還原序列化的結
果,恢複各個控制項的狀態,這樣就得到到上次頁面的狀態。
然後在頁面的生命週期中,如果在控制項的事件中有修改控制項狀態的代碼,就在合適的時候引發,然後,再次更新_VIEWSTATE 的值。
這樣控制項屬性的持久化就完成了。
所以我們在開發自訂控制項的時候,常常要顯示的生命控制項屬性的持久化。就是用ViewState.