WebForm —— 页面状态自动加载和保存(中)
2011-04-08 09:18
429 查看
上篇我将页面状态的自动加载和保存原理讲了一下,并作了一个简单的例子。在这里我会把上篇的例子整理一下,并提供一个基类(这里我将其定义为BasePage类,从Page类继承)处理这些事情,使得程序员从赋值、取值的繁琐操作中解脱出来。
首先定义一个特性(Attribute)。我会将这个特性放到需要自动加载和保存的属性上,以便将这些需要处理的属性从所有的页面属性中筛选出来,做进一步处理。这个特性的定义如下:
[code]///自动保存属性.能够实现字段或属性值的自动保存和加载.该属性只在非静态字段或属性上才能生效.
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
然后就是重写页面生命周期的某些事件,加入我们的处理代码。处理的过程为:㈠检索当前页面类型并将其需要处理的属性筛选出来(初始化过程);㈡将筛选出来的属性做保存或赋值操作(关键点)。
㈠筛选需要处理的属性,将其缓存到一个静态字典中,在需要的时候再取出来。这个初始化的代码如下:
[code]///用户控件类型及自动保存属性成员缓冲字典
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
可以看到,在调用调用初始化函数InitCacheDic时,系统会做两件事:缓存当前页面类型、筛选需要处理的属性。筛选属性反射操作,执行一次后不再重复。
㈡在赋值取值时,根据CurrType找到需要处理的属性,反射调用即可。这里我将属性的赋值操作放在了OnInit方法中,具体的代码如下:
[code]///引发<seecref="E:System.Web.UI.Control.Init"/>事件以对页进行初始化。
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
其中GetCacheData方法是获得该页缓存的数据。这些缓存的数据你可以放在Session、Database、ViewState、分布式或者其它你能想到的地方。这涉及到了下篇中的内容,这里先卖个关子,相信难不倒聪明的你!
㈢在赋值操作时,根据CurrType找到需要处理的属性,反射赋值即可。这里我将属性的保存操作放在了SaveViewState方法中。具体的代码如下:
[code]///在这里实现属性的自动保存。
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
其中SaveCacheData方法是保存该页缓存的数据,和GetCacheData方法的作用是相反。这里你可以尽情发挥你的想象,比如保存到Session中?
这样吧,为了满足某些人的懒惰心理,我先贴上演示用的数据保存和提取方法。代码如下:
[code]{
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
好了,你的程序应该可以运行起来了。至于取值、赋值的操作使用反射,是因为需要处理的属性个数少,不密集调用时使用Emit或者其它技术起不到多少加速的作用。你在乎1微妙的加速吗?网页的网络传输才是问题吧……
首先定义一个特性(Attribute)。我会将这个特性放到需要自动加载和保存的属性上,以便将这些需要处理的属性从所有的页面属性中筛选出来,做进一步处理。这个特性的定义如下:
///<summary>
[code]///自动保存属性.能够实现字段或属性值的自动保存和加载.该属性只在非静态字段或属性上才能生效.
///</summary>
///<remarks>
///自动保存属性.在页面类的属性上面加上该属性.可以使得该字段或属性能够自动保存和自动加载.
///但是该属性必须是可序列化的.否则抛出异常.该属性只在非公有字段或属性上才能生效.
///</remarks>
[AttributeUsage(AttributeTargets.Property|AttributeTargets.Field,AllowMultiple=false,Inherited=false)]
publicclassAutoSaveAttribute:Attribute
{
///<summary>
///初始化创建一个<seecref="AutoSaveAttribute"/>类的实例.使得具有该属性的类的属性具有自动保存的特性.
///</summary>
publicAutoSaveAttribute(){}
}
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
然后就是重写页面生命周期的某些事件,加入我们的处理代码。处理的过程为:㈠检索当前页面类型并将其需要处理的属性筛选出来(初始化过程);㈡将筛选出来的属性做保存或赋值操作(关键点)。
㈠筛选需要处理的属性,将其缓存到一个静态字典中,在需要的时候再取出来。这个初始化的代码如下:
///<summary>
[code]///用户控件类型及自动保存属性成员缓冲字典
///</summary>
protectedstaticDictionary<Type,MemberInfo[]>CacheDic=null;
///<summary>
///获得成员列表的绑定标识.
///</summary>
protectedstaticBindingFlagsFlag;
///<summary>
///初始化<seecref="BasePage"/>类.
///</summary>
staticBasePage()
{
CacheDic=newDictionary<Type,MemberInfo[]>();
Flag=BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.GetField|BindingFlags.GetProperty|BindingFlags.FlattenHierarchy;
}
///<summary>
///当前页面的类型
///</summary>
protectedTypeCurrType=null;
///<summary>
///初始化当前页面的缓冲字典
///</summary>
protectedvoidInitCacheDic()
{
//获得当前实例类型
CurrType=Page.GetType();
MemberInfo[]mems=null;
if(!CacheDic.TryGetValue(CurrType,outmems))
{
//自动保存属性处理
varlist=CurrType.GetMembers(Flag)
.Where(p=>Attribute.IsDefined(p,typeof(AutoSave),false))
.ToArray();
CacheDic[CurrType]=list;
}
}
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
可以看到,在调用调用初始化函数InitCacheDic时,系统会做两件事:缓存当前页面类型、筛选需要处理的属性。筛选属性反射操作,执行一次后不再重复。
㈡在赋值取值时,根据CurrType找到需要处理的属性,反射调用即可。这里我将属性的赋值操作放在了OnInit方法中,具体的代码如下:
///<summary>
[code]///引发<seecref="E:System.Web.UI.Control.Init"/>事件以对页进行初始化。
///</summary>
///<paramname="e">包含事件数据的<seecref="T:System.EventArgs"/>。</param>
protectedoverridevoidOnInit(EventArgse)
{
if(Page.IsPostBack)
{
//初始化当前用户控件的缓冲字典
InitCacheDic();
//获得缓冲数据列表
varlist=GetCacheData();
//自动加载AutoSave属性保存的值
intindex=0;
foreach(MemberInfoinfoinCacheDic[CurrType])
{
if(info.MemberType==MemberTypes.Property)
{
PropertyInfopi=infoasPropertyInfo;
objectvalue=list[index];
if(value!=null)
pi.SetValue(this,value,null);
}
elseif(info.MemberType==MemberTypes.Field)
{
FieldInfofi=infoasFieldInfo;
objectvalue=list[index];
fi.SetValue(this,value);
}
index++;
}
}
}
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
其中GetCacheData方法是获得该页缓存的数据。这些缓存的数据你可以放在Session、Database、ViewState、分布式或者其它你能想到的地方。这涉及到了下篇中的内容,这里先卖个关子,相信难不倒聪明的你!
㈢在赋值操作时,根据CurrType找到需要处理的属性,反射赋值即可。这里我将属性的保存操作放在了SaveViewState方法中。具体的代码如下:
///<summary>
[code]///在这里实现属性的自动保存。
///</summary>
protectedoverrideobjectSaveViewState()
{
//初始化当前用户控件的缓冲字典
InitCacheDic();
//初始化要保存的属性值列表
ArrayListlist=newArrayList();
intindex=0;
foreach(MemberInfoinfoinCacheDic[CurrType])
{
if(info.MemberType==MemberTypes.Property)
{
PropertyInfopi=infoasPropertyInfo;
list[index]=pi.GetValue(this,null);
}
elseif(info.MemberType==MemberTypes.Field)
{
FieldInfofi=infoasFieldInfo;
list[index]=fi.GetValue(this);
}
}
//保存更改
SaveCacheData(list);
returnbase.SaveViewState();
}
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
其中SaveCacheData方法是保存该页缓存的数据,和GetCacheData方法的作用是相反。这里你可以尽情发挥你的想象,比如保存到Session中?
这样吧,为了满足某些人的懒惰心理,我先贴上演示用的数据保存和提取方法。代码如下:
privateArrayListGetCacheData()
[code]{
return(ArrayList)Session[CurrType];
}
privatevoidSaveCacheData(ArrayListdata)
{
Session[CurrType]=data;
}
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
好了,你的程序应该可以运行起来了。至于取值、赋值的操作使用反射,是因为需要处理的属性个数少,不密集调用时使用Emit或者其它技术起不到多少加速的作用。你在乎1微妙的加速吗?网页的网络传输才是问题吧……
相关文章推荐
- WebForm —— 页面状态自动加载和保存(下)
- WebForm —— 页面状态自动加载和保存(上)
- ALSA配置状态保存,恢复和自动加载
- android快速开发框架--快速实现 页面 加载中 加载失败 无数据等状态以及下拉刷新和自动加载
- 博科B300 BROCADE 300 WEB页面访问访问不能自动加载JAVA
- 未能加载视图状态。正在向其中加载视图状态的控件树必须与前一请求期间用于保存视图状态的控件树相匹配。
- 基于AngularJS实现页面滚动到底自动加载数据的功能
- C#:用WebBrowser获取JS动态加载以后的页面代码并保存图片
- 页面加载完成后自动执行一个方法函数的JQ和JS方法
- 自定义SwpieRefreshLayout(进入页面自动刷新,下拉刷新,点击加载更多)
- 页面底端自动加载无需翻页功能 类似 新浪微博和Pinterest
- location.hash保存页面状态的技巧
- javaScript 页面自动加载事件详解
- Flask: Ajax 设置Access-Control-Allow-Origin实现跨域访问;Ajax页面底部自动加载
- js/jquery控制页面动态加载数据 滑动滚动条自动加载事件的方法
- 自动判断页面上的图片是否加载成功,不成功替换为默认图片
- silverlight实现页面跳转,保存上次的页面访问的状态,像手机应用一样
- 关于Asp.net 页面动态加载用户控件,出现“未能加载视图状态”的原因
- 点击添加按钮,关闭对话框,回到主住页面自动加载新添内容
- seajs+backbone实现单页面应用模块自动加载