Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1143190
  • 博文数量: 141
  • 博客积分: 3161
  • 博客等级: 中校
  • 技术积分: 3011
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-27 14:53
文章存档

2012年(28)

2011年(113)

分类: 嵌入式

2011-12-28 20:37:33

     前言:本篇讲解与视图ViewState相关的知识,包括IStateManager,自定义转换器TypeConvert,以及和视图功能相同的控件状态。可以说本篇是对保存状态有关知识的总结,代码也详细的给出。。。。。。。。

 

    自从上次写了有关视图的文章后,收到了很多朋友的邮件,很感谢大家的支持:)很多朋友都说要求说说实践性更强的东西,所以本篇就进一步的来谈谈视图(不仅仅只是视图,而且在ASP.NET中的状态保存的话题)。首先希望大家对自定义控件有一定的了解。大家可以去参看我的控件开发系列。

 

    首先我看从一个简单的控件开发来谈起,我们在ASP.NET有Login的登录控件,我们现在就来自己来实现一个类似的控件,因为本篇主要讲述与视图有关的话题,所以关于事件冒泡等我们不提及,主要是为了使得代码简洁,易懂,集中讲述一个问题。

     

    实现自定义Login控件有很多的方式,我这里会带着大家一步步的做,首先我们继承WebControl来实现一个控件,然后我们再改进例子,我们来看看从WebControl继承的Login控件:

 

  1. using System;
  2. using System.Data;
  3. using System.Configuration;
  4. using System.Linq;
  5. using System.Web;
  6. using System.Web.Security;
  7. using System.Web.UI;
  8. using System.Web.UI.HtmlControls;
  9. using System.Web.UI.WebControls;
  10. using System.Web.UI.WebControls.WebParts;
  11. using System.Xml.Linq;

  12. namespace CustomComponents
  13. {
  14.         /**////

  15.         ///MyLogin 的摘要说明

  16.         ///

  17.         public class MyLogin:WebControl
  18.         {
  19.                 属性#region 属性
  20.                 public string UserName
  21.                 {
  22.                         get
  23.                         {
  24.                                 return ViewState["UserName"] != null ? (string)ViewState["UserName"] : "UserName";

  25.                         }
  26.                         set
  27.                         {
  28.                                 ViewState["UserName"] = value;
  29.                         }
  30.                 
  31.                 }
  32.                 public string UserPassword
  33.                 {
  34.                         get
  35.                         {
  36.                                 return ViewState["UserPassword"] != null ? (string)ViewState["UserPassword"] : "UserPassword";

  37.                         }
  38.                         set
  39.                         {
  40.                                 ViewState["UserPassword"] = value;
  41.                         }

  42.                 }
  43.                 #endregion

  44.                 protected override HtmlTextWriterTag TagKey
  45.                 {
  46.                         get
  47.                         {
  48.                                 return HtmlTextWriterTag.Table;
  49.                         }
  50.                 }

  51.                 protected override void RenderContents(HtmlTextWriter writer)
  52.                 {
  53.                         //显示用户名

  54.                         writer.RenderBeginTag(HtmlTextWriterTag.Tr);
  55.                         writer.RenderBeginTag(HtmlTextWriterTag.Td);
  56.                         writer.Write(UserName);
  57.                         writer.RenderEndTag();

  58.                        
  59.                         writer.RenderBeginTag(HtmlTextWriterTag.Td);
  60.                         writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtUserName");
  61.                         writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
  62.                         writer.RenderBeginTag(HtmlTextWriterTag.Input);
  63.                         writer.RenderEndTag();
  64.                         writer.RenderEndTag();
  65.                         writer.RenderEndTag();

  66.                         //显示用户密码

  67.                         writer.RenderBeginTag(HtmlTextWriterTag.Tr);
  68.                         writer.RenderBeginTag(HtmlTextWriterTag.Td);
  69.                         writer.Write(UserPassword);
  70.                         writer.RenderEndTag();


  71.                         writer.RenderBeginTag(HtmlTextWriterTag.Td);
  72.                         writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtPassword");
  73.                         writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
  74.                         writer.RenderBeginTag(HtmlTextWriterTag.Input);
  75.                         writer.RenderEndTag();
  76.                         writer.RenderEndTag();
  77.                         writer.RenderEndTag();

  78.                         //显示登录按钮

  79.                         writer.RenderBeginTag(HtmlTextWriterTag.Tr);
  80.                         writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
  81.                         writer.AddAttribute(HtmlTextWriterAttribute.Align, "center");
  82.                         writer.RenderBeginTag(HtmlTextWriterTag.Td);
  83.                         writer.AddAttribute(HtmlTextWriterAttribute.Id, "btnSubmit");
  84.                         writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
  85.                         writer.AddAttribute(HtmlTextWriterAttribute.Value, "Login");
  86.                         writer.RenderBeginTag(HtmlTextWriterTag.Input);
  87.                         writer.RenderEndTag();
  88.                         writer.RenderEndTag();
  89.                         writer.RenderEndTag();



  90.                 }

  91.              

  92.         }
  93. }

 

    了解自定义控件开发的朋友应该对上面的代码不陌生。控件最后呈现的效果基本和ASP.NET中的标准的控件外观差不多的。上面的控件缺少事件等。但是我们这里不关注这些。我们关注视图。

    

    大家可以看过我们实际上是再用ViewState来把保存控件的UserName,Password的信息,就是说如果我们仅仅只是用下面的代码来保存,如下:

 

  1. private string userName;
  2.                 public string UserName
  3.                 {
  4.                         get { return userName; }
  5.                         set{userName =value ;}
  6.                 }

 

    我们控件的状态就会在回传的过程中丢失。

    我们现在就来具体的讲述视图在上面的控件是如何起作用的。

    假设我们开发的控件用在了一个已经部署好了的IIS中的网站的页面上了。当我们第一次请求这个页面,如:。页面就开始被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接口,接口定义了一个属性,三个方法,其实实现起来也很简单,比实现自定义的转换器更加简单。而且实现起来格式也很固定的。我们就开改进之前的例子:
  1. public class Person:IStateManager
  2.         {

  3.                 public string AddressInfo
  4.                 {
  5.                         get
  6.                         {
  7.                                 return ViewState["AddressInfo"] != null ? (string)ViewState["AddressInfo"] : "AddressInfo";

  8.                         }
  9.                         set
  10.                         {
  11.                                 ViewState["AddressInfo"] = value;
  12.                         }

  13.                 }
  14.              
  15.                 IStateManager 成员#region IStateManager 成员

  16.                 private bool _isTrackViewState;
  17.                 private StateBag _viewState;
  18.               
  19.                 public StateBag ViewState
  20.                 {
  21.                     get
  22.                     {
  23.                         if (_viewState == null)
  24.                         {
  25.                             _viewState = new StateBag(false);
  26.                             if (_isTrackViewState)
  27.                             {
  28.                                 ((IStateManager)_viewState).TrackViewState();
  29.                             }
  30.                         }
  31.                         return _viewState;
  32.                     }
  33.                 }

  34.                
  35.                 public bool IsTrackingViewState
  36.                 {
  37.                     get
  38.                     {
  39.                         return _isTrackViewState;
  40.                     }
  41.                 }

  42.                 public void LoadViewState(object state)
  43.                 {
  44.                     if (state != null)
  45.                     {
  46.                         ((IStateManager)ViewState).LoadViewState(state);
  47.                     }
  48.                 }

  49.                 public object SaveViewState()
  50.                 {
  51.                     if (this._viewState != null)
  52.                     {
  53.                         return ((IStateManager)_viewState).SaveViewState();
  54.                     }
  55.                     return null;
  56.                 }

  57.                 public void TrackViewState()
  58.                 {
  59.                     this._isTrackViewState = true;
  60.                     if (_viewState != null)
  61.                     {
  62.                         ((IStateManager)_viewState).TrackViewState();
  63.                     }
  64.                 }

  65.                 #endregion

  66.               

  67.         }

 

    然后,我们来看看之前的Login控件,下面是完整的代码,不同的地方我用注释格开了:大家先扫过,代码我们下面会讲解的。

 

  1. public class MyLogin : WebControl
  2.         {
  3.                 //---------------------------------------------------

  4.                 public Person personInfo;
  5.                 public Person PersonInfo
  6.                 {
  7.                         get
  8.                         {
  9.                                 if (personInfo == null)
  10.                                         personInfo = new Person();
  11.                                 ((IStateManager)personInfo).TrackViewState();
  12.                         }
  13.                         set
  14.                         {
  15.                                 personInfo = value;
  16.                         }
  17.                 }
  18.                 //--------------------------------------------

  19.              
  20.                 protected override object SaveViewState()
  21.                 {
  22.                         object[] states = new object[2];
  23.                         states[0] = base.SaveViewState();
  24.                         states[1] = ((IStateManager)PersonInfo).SaveViewState();
  25.                 }

  26.                 protected override void LoadViewState(object savedState)
  27.                 {
  28.                         object[] states = (object[])savedState;
  29.                         base.LoadViewState(states[0]);
  30.                         ((IStateManager)PersonInfo).SaveViewState(states[1]);

  31.                 }

  32.                 protected override void TrackViewState()
  33.                 {
  34.                         base.TrackViewState();
  35.                         ((IStateManager)PersonInfo).TrackViewState();
  36.                 }
  37.               
  38.                 和之前的相同的部分#region 和之前的相同的部分

  39.                 属性#region 属性
  40.                 public string UserName
  41.                 {
  42.                         get
  43.                         {
  44.                                 return ViewState["UserName"] != null ? (string)ViewState["UserName"] : "UserName";

  45.                         }
  46.                         set
  47.                         {
  48.                                 ViewState["UserName"] = value;
  49.                         }

  50.                 }
  51.                 public string UserPassword
  52.                 {
  53.                         get
  54.                         {
  55.                                 return ViewState["UserPassword"] != null ? (string)ViewState["UserPassword"] : "UserPassword";

  56.                         }
  57.                         set
  58.                         {
  59.                                 ViewState["UserPassword"] = value;
  60.                         }

  61.                 }


  62.                 #endregion
  63.                 protected override HtmlTextWriterTag TagKey
  64.                 {
  65.                         get
  66.                         {
  67.                                 return HtmlTextWriterTag.Table;
  68.                         }
  69.                 }

  70.                 protected override void RenderContents(HtmlTextWriter writer)
  71.                 {
  72.                         //显示用户名

  73.                         writer.RenderBeginTag(HtmlTextWriterTag.Tr);
  74.                         writer.RenderBeginTag(HtmlTextWriterTag.Td);
  75.                         writer.Write(UserName);
  76.                         writer.RenderEndTag();


  77.                         writer.RenderBeginTag(HtmlTextWriterTag.Td);
  78.                         writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtUserName");
  79.                         writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
  80.                         writer.RenderBeginTag(HtmlTextWriterTag.Input);
  81.                         writer.RenderEndTag();
  82.                         writer.RenderEndTag();
  83.                         writer.RenderEndTag();

  84.                         //显示用户密码

  85.                         writer.RenderBeginTag(HtmlTextWriterTag.Tr);
  86.                         writer.RenderBeginTag(HtmlTextWriterTag.Td);
  87.                         writer.Write(UserPassword);
  88.                         writer.RenderEndTag();


  89.                         writer.RenderBeginTag(HtmlTextWriterTag.Td);
  90.                         writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtPassword");
  91.                         writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
  92.                         writer.RenderBeginTag(HtmlTextWriterTag.Input);
  93.                         writer.RenderEndTag();
  94.                         writer.RenderEndTag();
  95.                         writer.RenderEndTag();

  96.                         //显示登录按钮

  97.                         writer.RenderBeginTag(HtmlTextWriterTag.Tr);
  98.                         writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
  99.                         writer.AddAttribute(HtmlTextWriterAttribute.Align, "center");
  100.                         writer.RenderBeginTag(HtmlTextWriterTag.Td);
  101.                         writer.AddAttribute(HtmlTextWriterAttribute.Id, "btnSubmit");
  102.                         writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
  103.                         writer.AddAttribute(HtmlTextWriterAttribute.Value, "Login");
  104.                         writer.RenderBeginTag(HtmlTextWriterTag.Input);
  105.                         writer.RenderEndTag();
  106.                         writer.RenderEndTag();
  107.                         writer.RenderEndTag();



  108.                 }
  109.                 #endregion



  110.         }

 

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

 

  1. protected override object SaveViewState()
  2.                 {
  3.                         object[] states = new object[2];
  4.                         states[0] = base.SaveViewState();
  5.                         states[1] = ((IStateManager)PersonInfo).SaveViewState();
  6.                 }

 

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

 

  1. protected override object SaveViewState()
  2.                 {
  3.                         object[] states = new object[3];
  4.                         states[0] = base.SaveViewState();
  5.                         states[1] = ((IStateManager)PersonInfo).SaveViewState();
  6.                         states[2] = ((IStateManager)Employee).SaveViewState();
  7.                 }

     其他的两个方法大家已经就可以看懂了。

     今天我们就说到这里,下篇我们谈谈转换器的问题。

阅读(1289) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~