ASP.NET ViewState 初探
與剛接觸ASP.NET頁麵的開發人員交談時,他們通常向我提出的第一個問題就是:“那個ViewState到底是什麼?”他們的語氣中流露出的那種感覺,就象我來到一家異國情調的餐館,侍者端上一道我從未見過的菜肴時的那種感覺-既疑惑不解,又充滿好奇。但肯定有人認為它不錯,否則就不會提供了。所以,我會先嚐一嚐,或許會喜歡上它,盡管它看上去的確很古怪!
對於ViewState也是如此,但是如果適應了它的風格,您會發現在許多情況下,您將樂於在自己的ASP.NET應用程序中使用ViewState,因為它可以幫助您使用更少的代碼完成更多的工作。但是,有時也會對ViewState完全棄之不用。下麵我們就這兩種情況分別進行闡述,不過,讓我們先回答什麼是ViewState這個問題。
答案:ViewState用於維護頁麵的UI狀態
Web是沒有狀態的,ASP.NET頁麵也沒有狀態,它們在到服務器的每個往返過程中被實例化、執行、呈現和處理。作為Web開發人員,您可以使用眾所周知的技術(如以會話狀態將狀態存儲在服務器上,或將頁麵回傳到自身)來添加狀態。下麵我們以圖1中的注冊窗體為例進行論述。
從上圖中可以看出,我為便餐選擇了一個無效的值。此窗體與Web上的多數窗體一樣友好,它在出現錯誤的字段旁邊顯示一條有用的錯誤消息和一個星號。而且,窗體中還顯示了我在其他文本框和下拉列表中輸入的所有有效值。這在某種程度上是可能的,因為HTML窗體元素會在HTTP標頭中將其當前值從瀏覽器發送到服務器。您可以使用ASP.NET跟蹤來查看回傳的窗體值,如圖2所示。
在ASP.NET之前,通過多次回傳將值恢複到窗體字段中完全是頁麵開發人員的責任,他們將不得不從HTTP窗體中逐個拾取回傳值,然後再將其推回字段中。幸運的是,現在ASP.NET可以自動完成這項任務,從而為開發人員免除了一項令人厭煩的工作,同時也無需再為窗體編寫大量的代碼。但這並不是ViewState。
ViewState(英文)是一種機製,ASP.NET使用這種機製來跟蹤服務器控件狀態值,否則這些值將不作為HTTP窗體的一部分而回傳。例如,由Label控件顯示的文本默認情況下就保存在ViewState中。作為開發人員,您可以綁定數據,或在首次加載該頁麵時僅對Label編程設置一次,在後續的回傳中,該標簽文本將自動從ViewState中重新填充。因此,除了可以減少繁瑣的工作和代碼外,ViewState通常還可以減少數據庫的往返次數。
ViewState的工作原理
ViewState確實沒有什麼神秘之處,它是由ASP.NET頁麵框架管理的一個隱藏的窗體字段。當ASP.NET執行某個頁麵時,該頁麵上的ViewState值和所有控件將被收集並格式化成一個編碼字符串,然後被分配給隱藏窗體字段的值屬性(即<inputtype=hidden>)。由於隱藏窗體字段是發送到客戶端的頁麵的一部分,所以ViewState值被臨時存儲在客戶端的瀏覽器中。如果客戶端選擇將該頁麵回傳給服務器,則ViewState字符串也將被回傳。在上麵的圖2中可以看到ViewState窗體字段及其回傳的值。
回傳後,ASP.NET頁麵框架將解析ViewState字符串,並為該頁麵和各個控件填充ViewState屬性。然後,控件再使用ViewState數據將自己重新恢複為以前的狀態。
關於ViewState還有三個值得注意的小問題。
如果要使用ViewState,則在ASPX頁麵中必須有一個服務器端窗體標記(<formrunat=server>)。窗體字段是必需的,這樣包含ViewState信息的隱藏字段才能回傳給服務器。而且,該窗體還必須是服務器端的窗體,這樣在服務器上執行該頁麵時,ASP.NET頁麵框架才能添加隱藏的字段。
頁麵本身將20字節左右的信息保存在ViewState中,用於在回傳時將PostBack數據和ViewState值分發給正確的控件。因此,即使該頁麵或應用程序禁用了ViewState,仍可以在ViewState中看到少量的剩餘字節。
在頁麵不回傳的情況下,可以通過省略服務器端的<form>標記來去除頁麵中的ViewState。
充分利用ViewState
ViewState為跨回傳跟蹤控件的狀態提供了一條神奇的途徑,因為它不使用服務器資源、不會超時,並且適用於任何瀏覽器。如果您要編寫控件,那麼肯定需要了解如何在控件中維護狀態(英文)。
開發人員在編寫頁麵時同樣可以按照幾乎相同的方式來利用ViewState,隻是有時頁麵會包含不由控件存儲的UI狀態值。您可以跟蹤ViewState中的值,使用的編程語法與會話和高速緩存的語法類似:
[VisualBasic]
'保存在ViewState中 ViewState("SortOrder")="DESC" '從ViewState中讀取 DimSortOrderAsString=CStr(ViewState("SortOrder")) |
[C#]
//保存在ViewState中 ViewState["SortOrder"]="DESC"; //從ViewState中讀取 stringsortOrder=(string)ViewState["SortOrder"]; |
請看下麵的示例:要在Web頁上顯示一個項目列表,而每個用戶需要不同的列表排序。項目列表是靜態的,因此可以將這些頁麵綁定到相同的緩存數據集,而排序順序隻是用戶特定的UI狀態的一小部分。ViewState非常適合於存儲這種類型的值。代碼如下:
[VisualBasic]
<%@ImportNamespace="System.Data"%> <HTML> <HEAD> <title>用於頁麵UI狀態值的ViewState/title> </HEAD> <body> <formrunat="server"> <H3> 在ViewState中存儲非控件狀態 </H3> <P> 此示例將一列靜態數據的當前排序順序存儲在ViewState中。<br> 單擊列標題中的鏈接,可按該字段排序數據。<br> 再次單擊該鏈接,將按相反順序排序。 <br><br><br> <asp:datagridrunat="server" OnSortCommand="SortGrid"BorderStyle="None"BorderWidth="1px" BorderColor="#CCCCCC"BackColor="White"CellPadding="5"AllowSorting="True"> <HeaderStyleFont-Bold="True"ForeColor="White" BackColor="#006699"> </HeaderStyle> </asp:datagrid> </P> </form> </body> </HTML> <scriptrunat="server"> '在ViewState中跟蹤SortField屬性 Get Set(ValueAsString) EndProperty '在ViewState中跟蹤SortAscending屬性 Get Set(ValueAsBoolean) EndProperty PrivateSubPage_Load(senderAsObject,eAsEventArgs)HandlesMyBase.Load IfNotPage.IsPostBackThen EndSub SubBindGrid() '獲取數據 DimdvAsNewDataView(ds.Tables(0)) '應用排序過濾器和方向 '綁定網格 EndSub PrivateSubSortGrid(senderAsObject,eAsDataGridSortCommandEventArgs) </script> |
[C#]
<%@PageLanguage="C#"%> <%@ImportNamespace="System.Data"%> <HTML> <HEAD> <title>用於頁麵UI狀態值的ViewState</title> </HEAD> <body> <formrunat="server"> <H3> 在ViewState中存儲非控件狀態 </H3> <P> 此示例將一列靜態數據的當前排序順序存儲在ViewState中。<br> 單擊列標題中的鏈接,可按該字段排序數據。<br> 再次單擊該鏈接,將按相反順序排序。 <br><br><br> <asp:datagridrunat="server"OnSortCommand="SortGrid" BorderStyle="None"BorderWidth="1px"BorderColor="#CCCCCC" BackColor="White"CellPadding="5"AllowSorting="True"> <HeaderStyleFont-Bold="True"ForeColor="White"BackColor="#006699"> </HeaderStyle> </asp:datagrid> </P> </form> </body> </HTML> <scriptrunat="server"> //在ViewState中跟蹤SortField屬性 get{ set{ //在ViewState中跟蹤SortAscending屬性 get{ set{ voidPage_Load(objectsender,EventArgse){ if(!Page.IsPostBack){ voidBindGrid(){ //獲取數據 DataViewdv=newDataView(ds.Tables[0]); //應用排序過濾器和方向 //綁定網格 voidSortGrid(objectsender,DataGridSortCommandEventArgse){ DataGrid1.CurrentPageIndex=0; </script> |
下麵是上述兩個代碼段中引用的testdata.xml的代碼:
<?xmlversion="1.0"standalone="yes"?> |
最後更新:2017-04-02 00:06:33