您的位置:首页 > 其它

WebForm —— 页面状态自动加载和保存(中)

2011-04-08 09:18 429 查看
上篇我将页面状态的自动加载和保存原理讲了一下,并作了一个简单的例子。在这里我会把上篇的例子整理一下,并提供一个基类(这里我将其定义为BasePage类,从Page类继承)处理这些事情,使得程序员从赋值、取值的繁琐操作中解脱出来。

首先定义一个特性(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微妙的加速吗?网页的网络传输才是问题吧……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐