首先,屬性是各種.net語言的基本語法。而我們常說的控件屬性是指控件類中用public修飾的屬性。
見Lable的Text屬性:
[Bindable(true), DefaultValue(""), Localizable(true), PersistenceMode(PersistenceMode.InnerDefaultPRoperty), WebCategory("Appearance"), WebSysDescrpublic virtual string Text
{ get
{ object obj = this.ViewState["Text"];
if (obj != null)
{ return (string)obj;
}
return string.Empty;
}
set
{ if (this.HasControls())
{ this.Controls.Clear();
}
this.ViewState["Text"] = value;
}
}
二、屬性的持久化
Lable的Text屬性都干了些什么呢?為什么不直接封裝一個string字段呢?
在回答這些問題前,我們先看看這樣一個實驗。
話說:Lable有一個兒子,他是這樣的:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
namespace CustomServerControl
{ public class MemorylessLable : Label
{ public override string Text
{ get;
set;
}
}
}
有一天Lable和兒子排好隊,站出相同的姿勢:
<div>
<csc:MemorylessLable ID="MemorylessLable1" Text="MemorylessLable" runat="server">
</csc:MemorylessLable>
<br />
<asp:Button ID="btnMemorylessLable" runat="server" Text="MemorylessLableAdd(?)" OnClick="btnMemorylessLable_Click" />
</div>
<div>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<br />
<asp:Button ID="btnLabel" runat="server" Text="LabelAdd(?)" OnClick="btnLabel_Click" />
</div>
他們做著同樣的事情:
protected void btnMemorylessLable_Click(object sender, EventArgs e)
{ MemorylessLable1.Text += "?";
}
protected void btnLabel_Click(object sender, EventArgs e)
{ Label1.Text += "?";
}
但是......但是,是你看到的結果。但是,這又是為什么呢?我們回顧一下HTTP協議的工作模式:HTTP是一種無狀態的斷開式連接模式,也就是說,客戶端向服務端發送請求,服務端做出響應后就不再維持此次請求客戶端的信息。在默認情況下,多次請求來自同一個客戶端還是多個不同的客戶端,對于服務端來說處理方式沒有什么不同。
1、視圖狀態
現在,我們已經弄清了MemorylessLable 中Text屬性沒有記憶的原因。回到問題的開始,Lable的Text屬性又干了些什么呢?是什么讓他看上去有了記憶?
我們看生成的HTML中有一個name為“__VIEWSTATE”的隱藏表單域:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKLTEzNjg4MTc2OQ9kFgICAw9kFgICBQ8PFgIeBFRleHQFCkxhYmVsPz8/Pz9kZGTR/AR1D6vaE/KV3PxzwkBnTnXssA==" />

為了解決保存控件狀態的問題,asp.net引入了一種叫視圖狀態(ViewState)的特性。需要在頁面回傳過程中保存值的控件屬性,可以把值保存在視圖狀態中,ASP.NET框架會在呈現頁面前把視圖信息序列化成一個字符串,并保存到頁面中的一個叫_VIEWSTATE”的隱藏表單域(<input type='hidden'/>)中。這樣,控件的狀態就保存到了客戶端,隱藏表單域中的值在下次頁面回傳時,由表單(Form)提交回服務器,服務器再對提交回的_VIEWSTATE隱藏域的值進行反序列化,還原各個控件的狀態。
但,有時用戶是要禁用視圖狀態的。對,視圖狀態可以禁用。禁用方法是在頁面前臺文件頂部的<%@Page%>指令中添加EnableViewState="false"。什么時候禁用呢?試想一下,比如,一個頁面中有一個產生數KB大小視圖狀態的GridView(GridView會產生大量的視圖狀態內容),而且N多次表單的提交。那么這數KB的視圖狀態就要在在客戶端和服務端見往返的傳遞,它會拖慢網頁的響應速度。好,我們把EnableViewState="false"添加到我們的Demo中,看一看。
![clipboard[6] clipboard[6]](http://s1.VeVb.com/20150728/p0jenoyyh31.png)
2、控件狀態
但,有些信息對于控件的正確運行是至關重要的。比如,我們剛才所說的那個GridView中的PageIndex屬性。如果該屬性序列化到視圖狀態中,在頁面禁用視圖狀態時,GridView的分頁功能將徹底崩潰。但實際卻不是如此,GirdView是怎么做到的呢?如,標題:控件狀態(ControlState)。
ASP.NET2.0后為控件開發人員提供了一種比視圖狀態更安全的保存控件狀態值的機制。控件狀態類似于視圖狀態,但它在用戶設置EnableViewState="false"時任然有效。
Lable的孫子:
using System;
using System.Collections.Generic;
using System.Text;
namespace CustomServerControl
{ public class SuperMemoryLable:MemorylessLable
{ protected override void OnInit(EventArgs e)
{ //通知控件運行時所在頁面,將該控件注冊為具有持久性控件狀態的控件
Page.RegisterRequiresControlState(this);
base.OnInit(e);
}
//返回要保存到控件狀態中的值
protected override object SaveControlState()
{ return this.Text;
}
//將從控件狀態中反序列化出來的對象解析成控件的各個狀態值
protected override void LoadControlState(object savedState)
{ this.Text = savedState as string;
}
}
}
Lable和孫子玩起了他和兒子當年的游戲:
<div>
<csc:SuperMemoryLable ID="SuperMemoryLable1" runat="server" Text="SuperMemoryLable">
</csc:SuperMemoryLable>
<br />
<asp:Button ID="btnSuperMemoryLable" runat="server" Text="SuperMemoryLableAdd(?)"
OnClick="btnSuperMemoryLable_Click" />
</div>
<div>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<br />
<asp:Button ID="btnLabel" runat="server" Text="LabelAdd(?)" OnClick="btnLabel_Click" />
</div>
![clipboard[8] clipboard[8]](http://s1.VeVb.com/20150728/duz5nxwx5st.png)
游戲升級:添加EnableViewState="false"后的一瞥。
![clipboard[10] clipboard[10]](http://s1.VeVb.com/20150728/ie0gewwjnxe.png)
三、總結
1.控件屬性是指控件類中用public修飾的屬性。
2.實現屬性持久化的方式有兩種:
①將控件屬性序列化到視圖狀態;
②將控件屬性序列化到控件狀態。
頁面開發時,可以通過EnableViewState="false"禁用視圖狀態。
3.應用控件狀態的三個步驟:
①重寫OnInit()方法,在調用base.OnInit()前,調用Page.RegisterRequiresControlState()方法通知控件運行時所在的頁面,需要為它提供控件狀態功能;
②重寫SaveControlState()方法,提供需要保存到控件狀態中的值;
③重寫LoadControlState()方法,將從控件狀態中反序列化出來的對象解析成控件的各個狀態值。
附:GridView通過控件狀態持久化PageIndex屬性:
步驟一:
protected internal override void OnInit(EventArgs e)
{ base.OnInit(e);
if (this.Page != null)
{ if (this.DataKeyNames.Length > 0 && !this.AutoGenerateColumns)
{ this.Page.RegisterRequiresViewStateEncryption();
}
//通知控件運行時所在的頁面,需要為它提供控件狀態功能
this.Page.RegisterRequiresControlState(this);
}
}
步驟二:
protected internal override object SaveControlState()
{ object obj = base.SaveControlState();
if (obj != null || this._pageIndex != 0 || this._editIndex != -1 || this._selectedIndex != -1 ||
(this._sortExpression != null && this._sortExpression.Length != 0) || (this._sortDirection != SortDirection.Ascending ||
(this._dataKeyNames != null && this._dataKeyNames.Length != 0)) ||
(this._dataKeysArrayList != null && this._dataKeysArrayList.Count > 0) || this._pageCount != -1)
{ return new object[]
{ obj,
(this._editIndex == -1) ? null : this._editIndex,
新聞熱點
疑難解答