--- 视图状态实战篇
前言:本篇讲解与视图ViewState相关的知识,包括IStateManager,自定义转换器TypeConvert,以及和视图功能相同的控件状态。可以说本篇是对保存状态有关知识的总结,代码也详细的给出。。。。。。。。
自从上次写了有关视图的文章后,收到了很多朋友的邮件,很感谢大家的支持:)很多朋友都说要求说说实践性更强的东西,所以本篇就进一步的来谈谈视图(不仅仅只是视图,而且在ASP.NET中的状态保存的话题)。首先希望大家对自定义控件有一定的了解。大家可以去参看我的控件开发系列。
首先我看从一个简单的控件开发来谈起,我们在ASP.NET有Login的登录控件,我们现在就来自己来实现一个类似的控件,因为本篇主要讲述与视图有关的话题,所以关于事件冒泡等我们不提及,主要是为了使得代码简洁,易懂,集中讲述一个问题。
实现自定义Login控件有很多的方式,我这里会带着大家一步步的做,首先我们继承WebControl来实现一个控件,然后我们再改进例子,我们来看看从WebControl继承的Login控件:
class="cnblogs_code_copy">
 

 using System;
using System; using System.Data;
using System.Data; using System.Configuration;
using System.Configuration; using System.Linq;
using System.Linq; using System.Web;
using System.Web; using System.Web.Security;
using System.Web.Security; using System.Web.UI;
using System.Web.UI; using System.Web.UI.HtmlControls;
using System.Web.UI.HtmlControls; using System.Web.UI.WebControls;
using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls.WebParts; using System.Xml.Linq;
using System.Xml.Linq;
 namespace CustomComponents
namespace CustomComponents {
{ /// <summary>
        /// <summary> ///MyLogin 的摘要说明
        ///MyLogin 的摘要说明 /// </summary>
        /// </summary> public class MyLogin:WebControl
        public class MyLogin:WebControl  {
        { #region  属性
                #region  属性 public string UserName
                public string UserName {
                { get
                        get {
                        { return ViewState["UserName"] != null ? (string)ViewState["UserName"] : "UserName";
                                return ViewState["UserName"] != null ? (string)ViewState["UserName"] : "UserName";
 }
                        } set
                        set {
                        { ViewState["UserName"] = value;
                                ViewState["UserName"] = value; }
                        } 
                 }
                } public string UserPassword
                public string UserPassword {
                { get
                        get {
                        { return ViewState["UserPassword"] != null ? (string)ViewState["UserPassword"] : "UserPassword";
                                return ViewState["UserPassword"] != null ? (string)ViewState["UserPassword"] : "UserPassword";
 }
                        } set
                        set {
                        { ViewState["UserPassword"] = value;
                                ViewState["UserPassword"] = value; }
                        }
 }
                } #endregion
                #endregion
 protected override HtmlTextWriterTag TagKey
                protected override HtmlTextWriterTag TagKey {
                { get
                        get {
                        { return HtmlTextWriterTag.Table;
                                return HtmlTextWriterTag.Table; }
                        } }
                }
 protected override void RenderContents(HtmlTextWriter writer)
                protected override void RenderContents(HtmlTextWriter writer) {
                { //显示用户名
                        //显示用户名 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                        writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.Write(UserName);
                        writer.Write(UserName); writer.RenderEndTag();
                        writer.RenderEndTag();
 
                        writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtUserName");
                        writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtUserName"); writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
                        writer.AddAttribute(HtmlTextWriterAttribute.Type, "text"); writer.RenderBeginTag(HtmlTextWriterTag.Input);
                        writer.RenderBeginTag(HtmlTextWriterTag.Input); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag();
 //显示用户密码
                        //显示用户密码 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                        writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.Write(UserPassword);
                        writer.Write(UserPassword); writer.RenderEndTag();
                        writer.RenderEndTag();

 writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtPassword");
                        writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtPassword"); writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
                        writer.AddAttribute(HtmlTextWriterAttribute.Type, "text"); writer.RenderBeginTag(HtmlTextWriterTag.Input);
                        writer.RenderBeginTag(HtmlTextWriterTag.Input); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag();
 //显示登录按钮
                        //显示登录按钮 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                        writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
                        writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2"); writer.AddAttribute(HtmlTextWriterAttribute.Align, "center");
                        writer.AddAttribute(HtmlTextWriterAttribute.Align, "center"); writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.AddAttribute(HtmlTextWriterAttribute.Id, "btnSubmit");
                        writer.AddAttribute(HtmlTextWriterAttribute.Id, "btnSubmit"); writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
                        writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit"); writer.AddAttribute(HtmlTextWriterAttribute.Value, "Login");
                        writer.AddAttribute(HtmlTextWriterAttribute.Value, "Login"); writer.RenderBeginTag(HtmlTextWriterTag.Input);
                        writer.RenderBeginTag(HtmlTextWriterTag.Input); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag();


 }
                }
 
             
 }
        } }
}
 
了解自定义控件开发的朋友应该对上面的代码不陌生。控件最后呈现的效果基本和ASP.NET中的标准的控件外观差不多的。上面的控件缺少事件等。但是我们这里不关注这些。我们关注视图。
大家可以看过我们实际上是再用ViewState来把保存控件的UserName,Password的信息,就是说如果我们仅仅只是用下面的代码来保存,如下:
 

 
我们控件的状态就会在回传的过程中丢失。
我们现在就来具体的讲述视图在上面的控件是如何起作用的。
假设我们开发的控件用在了一个已经部署好了的IIS中的网站的页面上了。当我们第一次请求这个页面,如:http://localhost/Test/Default.aspx。页面就开始被ASP.NET运行时开始解析编译,最后把结果发送给我们,如下:(假设页面中就只有一个控件)
 
起始ASP.NET运行时在解析页面的时候,就把Login控件的一些状态,如UserName属性等其他的设置信息序列化为一个字符串保存名为_VIEWSTATE的隐藏控件中,,然后把这些个序列化是通过一个转换器来进行的,如UserName属性的值类型是String,所以就用StringConvert来转换。其实在ASP.NET中有很多的内置的转换器,派生自TypeConvert,,如StringConvert,BoolenConvert。也就是说,如果我们在上面的控件中有sring,int,bool等的属性(如UserName就是string),ASP.NET自动将他们用对应的转换器转换;所以如果我们开发了自定义的一个类,如Person类,而且这个类还是上面Login控件的一个属性, 那么我们就必须开发自定的转换器来转换Person,我们自定义的转化器一定要继承自TypeConvert。 然后就把转换后的结果发送客户端的浏览器中,当我们在浏览器中填写了用户名等信息后,我们点击按钮,整个页面就回传给了服务器,然后服务器就解析数据,同时也解析之前保存在_VIEWSTATE中的信息,而且用相应的转换器,来还原之前的属性,然后把这些属性赋值给在服务器端新生成的类的实例。 用转换器是一种方法,但是还有另外的一种方法就是使得我们自定义的类,如之前提及的person类实现IStateManager接口,接口定义了一个属性,三个方法,其实实现起来也很简单,比实现自定义的转换器更加简单。而且实现起来格式也很固定的。我们就开改进之前的例子:
 

 public class Person:IStateManager
  public class Person:IStateManager  {
        {
 public string AddressInfo
                public string AddressInfo {
                { get
                        get {
                        { return ViewState["AddressInfo"] != null ? (string)ViewState["AddressInfo"] : "AddressInfo";
                                return ViewState["AddressInfo"] != null ? (string)ViewState["AddressInfo"] : "AddressInfo";
 }
                        } set
                        set {
                        { ViewState["AddressInfo"] = value;
                                ViewState["AddressInfo"] = value; }
                        }
 }
                } 
              #region IStateManager 成员
                #region IStateManager 成员
 private bool _isTrackViewState;
                private bool _isTrackViewState; private StateBag _viewState;
                private StateBag _viewState; 
               public StateBag ViewState
                public StateBag ViewState {
                { get
                    get {
                    { if (_viewState == null)
                        if (_viewState == null) {
                        { _viewState = new StateBag(false);
                            _viewState = new StateBag(false); if (_isTrackViewState)
                            if (_isTrackViewState) {
                            { ((IStateManager)_viewState).TrackViewState();
                                ((IStateManager)_viewState).TrackViewState(); }
                            } }
                        } return _viewState;
                        return _viewState; }
                    } }
                }
 
                public bool IsTrackingViewState
                public bool IsTrackingViewState {
                { get
                    get  {
                    { return _isTrackViewState;
                        return _isTrackViewState; }
                    } }
                }
 public void LoadViewState(object state)
                public void LoadViewState(object state) {
                { if (state != null)
                    if (state != null) {
                    { ((IStateManager)ViewState).LoadViewState(state);
                        ((IStateManager)ViewState).LoadViewState(state); }
                    } }
                }
 public object SaveViewState()
                public object SaveViewState() {
                { if (this._viewState != null)
                    if (this._viewState != null) {
                    { return ((IStateManager)_viewState).SaveViewState();
                        return ((IStateManager)_viewState).SaveViewState(); }
                    } return null;
                    return null; }
                }
 public void TrackViewState()
                public void TrackViewState() {
                { this._isTrackViewState = true;
                    this._isTrackViewState = true; if (_viewState != null)
                    if (_viewState != null) {
                    { ((IStateManager)_viewState).TrackViewState();
                        ((IStateManager)_viewState).TrackViewState(); }
                    } }
                }
 #endregion
                #endregion
 
              
 }
        }
 然后,我们来看看之前的Login控件,下面是完整的代码,不同的地方我用注释格开了:大家先扫过,代码我们下面会讲解的。
 
     然后,我们来看看之前的Login控件,下面是完整的代码,不同的地方我用注释格开了:大家先扫过,代码我们下面会讲解的。
     
 

 public class MyLogin : WebControl
 public class MyLogin : WebControl {
        { //---------------------------------------------------
                //--------------------------------------------------- public Person personInfo;
                public Person personInfo; public Person PersonInfo
                public Person PersonInfo {
                { get
                        get {
                        { if (personInfo == null)
                                if (personInfo == null) personInfo = new Person();
                                        personInfo = new Person(); ((IStateManager)personInfo).TrackViewState();
                                ((IStateManager)personInfo).TrackViewState(); }
                        } set
                        set {
                        { personInfo = value;
                                personInfo = value; }
                        } }
                } //--------------------------------------------
                //-------------------------------------------- 
              protected override object SaveViewState()
                protected override object SaveViewState() {
                { object[] states = new object[2];
                        object[] states = new object[2]; states[0] = base.SaveViewState();
                        states[0] = base.SaveViewState(); states[1] = ((IStateManager)PersonInfo).SaveViewState();
                        states[1] = ((IStateManager)PersonInfo).SaveViewState(); }
                }  
 protected override void LoadViewState(object savedState)
                protected override void LoadViewState(object savedState) {
                { object[] states = (object[])savedState;
                        object[] states = (object[])savedState; base.LoadViewState(states[0]);
                        base.LoadViewState(states[0]); ((IStateManager)PersonInfo).SaveViewState(states[1]);
                        ((IStateManager)PersonInfo).SaveViewState(states[1]);
 }
                }
 protected override void TrackViewState()
                protected override void TrackViewState() {
                { base.TrackViewState();
                        base.TrackViewState(); ((IStateManager)PersonInfo).TrackViewState();
                        ((IStateManager)PersonInfo).TrackViewState(); }
                } 
               #region 和之前的相同的部分
                #region 和之前的相同的部分
 属性
                属性 protected override HtmlTextWriterTag TagKey
                protected override HtmlTextWriterTag TagKey {
                { get
                        get {
                        { return HtmlTextWriterTag.Table;
                                return HtmlTextWriterTag.Table; }
                        } }
                }
 protected override void RenderContents(HtmlTextWriter writer)
                protected override void RenderContents(HtmlTextWriter writer) {
                { //显示用户名
                        //显示用户名 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                        writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.Write(UserName);
                        writer.Write(UserName); writer.RenderEndTag();
                        writer.RenderEndTag();

 writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtUserName");
                        writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtUserName"); writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
                        writer.AddAttribute(HtmlTextWriterAttribute.Type, "text"); writer.RenderBeginTag(HtmlTextWriterTag.Input);
                        writer.RenderBeginTag(HtmlTextWriterTag.Input); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag();
 //显示用户密码
                        //显示用户密码 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                        writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.Write(UserPassword);
                        writer.Write(UserPassword); writer.RenderEndTag();
                        writer.RenderEndTag();

 writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtPassword");
                        writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtPassword"); writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
                        writer.AddAttribute(HtmlTextWriterAttribute.Type, "text"); writer.RenderBeginTag(HtmlTextWriterTag.Input);
                        writer.RenderBeginTag(HtmlTextWriterTag.Input); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag();
 //显示登录按钮
                        //显示登录按钮 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                        writer.RenderBeginTag(HtmlTextWriterTag.Tr); writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
                        writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2"); writer.AddAttribute(HtmlTextWriterAttribute.Align, "center");
                        writer.AddAttribute(HtmlTextWriterAttribute.Align, "center"); writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.RenderBeginTag(HtmlTextWriterTag.Td); writer.AddAttribute(HtmlTextWriterAttribute.Id, "btnSubmit");
                        writer.AddAttribute(HtmlTextWriterAttribute.Id, "btnSubmit"); writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
                        writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit"); writer.AddAttribute(HtmlTextWriterAttribute.Value, "Login");
                        writer.AddAttribute(HtmlTextWriterAttribute.Value, "Login"); writer.RenderBeginTag(HtmlTextWriterTag.Input);
                        writer.RenderBeginTag(HtmlTextWriterTag.Input); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag(); writer.RenderEndTag();
                        writer.RenderEndTag();


 }
                } #endregion
                #endregion


 }
        }
 上面的代码首先就是多了一个Person类型的属性PersonInfo,然后就是重写了三个方法。其实重写的这个三个方法是很好理解的,而且代码也不是很难,首先我们看看
     
     上面的代码首先就是多了一个Person类型的属性PersonInfo,然后就是重写了三个方法。其实重写的这个三个方法是很好理解的,而且代码也不是很难,首先我们看看
     
 

 protected override object SaveViewState()
     protected override object SaveViewState() {
                { object[] states = new object[2];
                        object[] states = new object[2]; states[0] = base.SaveViewState();
                        states[0] = base.SaveViewState(); states[1] = ((IStateManager)PersonInfo).SaveViewState();
                        states[1] = ((IStateManager)PersonInfo).SaveViewState(); }
                }  
 
上面的代码就是保存视图状态,首先base.SaveViewState();返回的就是控件中其他的一些状态,如UserName等的状态,我们这里实际上就是把我们的属性PersonInfo的状态和控件的其他状态值加载在一起。如果还有其他的类型,如Employee类型的属性,我们就要在这个方法中写上:
 

 protected override object SaveViewState()
 protected override object SaveViewState() {
                { object[] states = new object[3];
                        object[] states = new object[3]; states[0] = base.SaveViewState();
                        states[0] = base.SaveViewState(); states[1] = ((IStateManager)PersonInfo).SaveViewState();
                        states[1] = ((IStateManager)PersonInfo).SaveViewState(); states[2] = ((IStateManager)Employee).SaveViewState();
                        states[2] = ((IStateManager)Employee).SaveViewState(); }
                }   
 
其他的两个方法大家已经就可以看懂了。