自从上次写了有关视图的文章后,收到了很多朋友的邮件,很感谢大家的支持:)很多朋友都说要求说说实践性更强的东西,所以本篇就进一步的来谈谈视图(不仅仅只是视图,而且在ASP.NET中的状态保存的话题)。首先希望大家对自定义控件有一定的了解。大家可以去参看我的控件开发系列。
首先我看从一个简单的控件开发来谈起,我们在ASP.NET有Login的登录控件,我们现在就来自己来实现一个类似的控件,因为本篇主要讲述与视图有关的话题,所以关于事件冒泡等我们不提及,主要是为了使得代码简洁,易懂,集中讲述一个问题。
实现自定义Login控件有很多的方式,我这里会带着大家一步步的做,首先我们继承WebControl来实现一个控件,然后我们再改进例子,我们来看看从WebControl继承的Login控件:
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
namespace CustomComponents
{
/**//// <summary>
///MyLogin 的摘要说明
/// </summary>
public class MyLogin:WebControl
{
属性#region 属性
public string UserName
{
get
{
return ViewState["UserName"] != null ? (string)ViewState["UserName"] : "UserName";
}
set
{
ViewState["UserName"] = value;
}
}
public string UserPassword
{
get
{
return ViewState["UserPassword"] != null ? (string)ViewState["UserPassword"] : "UserPassword";
}
set
{
ViewState["UserPassword"] = value;
}
}
#endregion
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Table;
}
}
protected override void RenderContents(HtmlTextWriter writer)
{
//显示用户名
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write(UserName);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtUserName");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
//显示用户密码
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write(UserPassword);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtPassword");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
//显示登录按钮
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
writer.AddAttribute(HtmlTextWriterAttribute.Align, "center");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Id, "btnSubmit");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
writer.AddAttribute(HtmlTextWriterAttribute.Value, "Login");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
}
}
了解自定义控件开发的朋友应该对上面的代码不陌生。控件最后呈现的效果基本和ASP.NET中的标准的控件外观差不多的。上面的控件缺少事件等。但是我们这里不关注这些。我们关注视图。
大家可以看过我们实际上是再用ViewState来把保存控件的UserName,Password的信息,就是说如果我们仅仅只是用下面的代码来保存,如下:
private string userName;
public string UserName
{
get { return userName; }
set{userName =value ;}
}
我们控件的状态就会在回传的过程中丢失。
我们现在就来具体的讲述视图在上面的控件是如何起作用的。
假设我们开发的控件用在了一个已经部署好了的IIS中的网站的页面上了。当我们第一次请求这个页面,如:http://localhost/Test/Default.aspx。页面就开始被ASP.NET运行时开始解析编译,最后把结果发送给我们,如下:(假设页面中就只有一个控件)
public class Person:IStateManager
{
public string AddressInfo
{
get
{
return ViewState["AddressInfo"] != null ? (string)ViewState["AddressInfo"] : "AddressInfo";
}
set
{
ViewState["AddressInfo"] = value;
}
}
IStateManager 成员#region IStateManager 成员
private bool _isTrackViewState;
private StateBag _viewState;
public StateBag ViewState
{
get
{
if (_viewState == null)
{
_viewState = new StateBag(false);
if (_isTrackViewState)
{
((IStateManager)_viewState).TrackViewState();
}
}
return _viewState;
}
}
public bool IsTrackingViewState
{
get
{
return _isTrackViewState;
}
}
public void LoadViewState(object state)
{
if (state != null)
{
((IStateManager)ViewState).LoadViewState(state);
}
}
public object SaveViewState()
{
if (this._viewState != null)
{
return ((IStateManager)_viewState).SaveViewState();
}
return null;
}
public void TrackViewState()
{
this._isTrackViewState = true;
if (_viewState != null)
{
((IStateManager)_viewState).TrackViewState();
}
}
#endregion
}
public class MyLogin : WebControl
{
//---------------------------------------------------
public Person personInfo;
public Person PersonInfo
{
get
{
if (personInfo == null)
personInfo = new Person();
((IStateManager)personInfo).TrackViewState();
}
set
{
personInfo = value;
}
}
//--------------------------------------------
protected override object SaveViewState()
{
object[] states = new object[2];
states[0] = base.SaveViewState();
states[1] = ((IStateManager)PersonInfo).SaveViewState();
}
protected override void LoadViewState(object savedState)
{
object[] states = (object[])savedState;
base.LoadViewState(states[0]);
((IStateManager)PersonInfo).SaveViewState(states[1]);
}
protected override void TrackViewState()
{
base.TrackViewState();
((IStateManager)PersonInfo).TrackViewState();
}
和之前的相同的部分#region 和之前的相同的部分
属性#region 属性
public string UserName
{
get
{
return ViewState["UserName"] != null ? (string)ViewState["UserName"] : "UserName";
}
set
{
ViewState["UserName"] = value;
}
}
public string UserPassword
{
get
{
return ViewState["UserPassword"] != null ? (string)ViewState["UserPassword"] : "UserPassword";
}
set
{
ViewState["UserPassword"] = value;
}
}
#endregion
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Table;
}
}
protected override void RenderContents(HtmlTextWriter writer)
{
//显示用户名
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write(UserName);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtUserName");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
//显示用户密码
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write(UserPassword);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Id, "txtPassword");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
//显示登录按钮
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
writer.AddAttribute(HtmlTextWriterAttribute.Align, "center");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Id, "btnSubmit");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
writer.AddAttribute(HtmlTextWriterAttribute.Value, "Login");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
#endregion
}
protected override object SaveViewState()
{
object[] states = new object[2];
states[0] = base.SaveViewState();
states[1] = ((IStateManager)PersonInfo).SaveViewState();
}
上面的代码就是保存视图状态,首先base.SaveViewState();返回的就是控件中其他的一些状态,如UserName等的状态,我们这里实际上就是把我们的属性PersonInfo的状态和控件的其他状态值加载在一起。如果还有其他的类型,如Employee类型的属性,我们就要在这个方法中写上:
protected override object SaveViewState()
{
object[] states = new object[3];
states[0] = base.SaveViewState();
states[1] = ((IStateManager)PersonInfo).SaveViewState();
states[2] = ((IStateManager)Employee).SaveViewState();
}
其他的两个方法大家已经就可以看懂了。
今天我们就说到这里,下篇我们谈谈转换器的问题。