专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »Web开发 » 什么是web控件:Web基础控件开发之视图状态 »正文

什么是web控件:Web基础控件开发之视图状态

来源: 发布时间:星期一, 2008年6月2日 浏览:552次 评论:0
来源:王孟军 NULL - 博客园

主题

控件自定义属性类型之状态维护

引子

上一章节讲到了自定义属性类型的类型转换,看似完美了,其实不然,我们还得解决BS结构中,最为头疼,最为重要,最为古老的话题-视图状态。

  为什么说,视图状态是最为古老,最为重要呢?那是因为,服务器控件一出世,我们这些做“父母的”,就得在“她”postBack的时候,在网页中“偷偷的”放上几段Hidden乱码,为“她”还原或者更新状态。

为什么说最为头疼呢?在Ajax未普及之前,我们不得不PostBack,忍受那几毫秒的”空白“,自定义属性的类型,自定义样式等,哪样不需要我们这些“程序设计员”,(我不太喜欢叫程序员,我们难道没有设计?没有自己的思想?所以,我建议,从圆子里开始,给”程序员“加上设计二字)手动的去实现视图状态接口呢?而Ajax目前正处于“青黄不接”的时节。

发现问题

1.当我们未给People的简单属性维护状态的时候,当我们改变简单属性的值的时候,我们发现更改无效,这也理所当然,因为我们没给简单属性维护状态。

设置People的简单属性值

this.People1.Name = "郭孟军";
this.People1.Age = 22;
this.People1.Family = "呵呵";
this.People1.CustomMetier = CustomPeople.Metier.程序设计员;

先看设置前的状态



设置事件发生后的状态



此时,People的简单熟悉确实变化了

我们来点击POSTBACK,看看会有什么变化(注意,POSTBACK按钮不做任何动作)



呵呵,People的几个简单属性的值又变成了第一次加载时候的值,即默认值。

刚刚也说了,出现这种情况的原因,是因为我们没有维护People简单属性的状态,下面我们来给“她”的简单属性,加上状态


public String Name
{
get { return ViewState["Name"] != null ? (string)ViewState["Name"] : string.Empty; }
set { ViewState["Name"] = value; }
}

这里只列举Name属性,其他的都一样,稍后可以去下载Demo

我们点击POSTBACK按纽,发现这次简单属性的值改变了,呵呵

2.到此,简单属性的状态维护得到了维护

大家先停一下,People不是还有CustomAddress这个”连字符“复杂属性吗?(忘记了朋友,请回头看看属性的第一章),是不是也象维护简单属性状态那样简单呢?当然不是,MSDN上有明确定义,视图不能保存自定义的类型。

其实,动手写之前,我犹郁了很久,一是因为写方面的东西比较多,怕”重复发明车轮“,二是,虽然写视图状态的“文字”比较多,但是正在写得透彻,写得丝丝入扣的却少,Google了一大把描写视图状态的文章,一一细看,怎感觉不得要领,怎感觉我的”降龙十八掌“还差那么一点火候,我这人有个坏毛病,什么东西都喜欢自己动手做一遍,看到效果,才放心(我爸妈结婚的时候,爷爷送了一块老式上海手表,我硬是把她拆了,结果却多出几个齿轮^-^)

好了,题外话就不多说,视图状态的文章,我Google了一篇,自认为还可以的文章,大家先看看 http://9host.cn/asp.net/2007102520818.html

相信还有朋友对自定义类型为什么不能保存在视图状态中还有点迷惑,为什么People的Name,Age等可以,那是因为People继承了Control类,而Control又显示实现了IStateManager接口。

请大家再次Stop,Control并没有”显示实现“IStateManager接口,故意误导大家一下,给大家留个印象。很多书是这样说的”委托给ViewState属性管理“,但我一直很纳闷,有朋友知道的,麻烦指点指点。

3.解决自定义属性类型的状态问题,分两步走

3.1第一步,维护自定义类型的状态,(注意,这里我们叫她自定义类型)至于MSDN上面讲到的要实现IStateManager接口的一个属性和三个方法,我在这里,就不多说

Code

using System;
using System.ComponentModel;
using System.Globalization;
using System.Web.UI;

namespace CustomPeople
{
[TypeConverter(typeof(AddressConverter))]
public class Address : IStateManager
{
private String street = null;
private String city = null;
private String state = null;
private String zip = null;

public Address()
:
this(String.Empty, String.Empty,
String.Empty, String.Empty)
{ }

public Address(string street, string city,
string state, string zip)
{
this.street = street;
this.city = city;
this.state = state;
this.zip = zip;
}

[NotifyParentProperty(true)]
public String Street
{
get { return ViewState["Street"] != null ? (string)ViewState["Street"] : String.Empty; }
set { ViewState["Street"] = value; }
}

[
Category("Behavior"),
DefaultValue(""),
Description("城市"),
NotifyParentProperty(true),
]
public String City
{
get { return ViewState["City"] != null ? (string)ViewState["City"] : String.Empty; }
set { ViewState["City"] = value; }
}

[
Category("Behavior"),
DefaultValue(""),
Description("国籍"),
NotifyParentProperty(true),
]

public String State
{
get { return ViewState["State"] != null ? (string)ViewState["State"] : String.Empty; }
set { ViewState["State"] = value; }
}

[
Category("Behavior"),
DefaultValue(""),
Description("邮编"),
NotifyParentProperty(true)
]
public String Zip
{
get { return ViewState["Zip"] != null ? (string)ViewState["Zip"] : String.Empty; }
set { ViewState["Zip"] = value; }
}


方法#region 方法

public override string ToString()
{
return ToString(CultureInfo.CurrentCulture);
}

public virtual string ToString(CultureInfo culture)
{
return TypeDescriptor.GetConverter(typeof(Address)).ConvertToString(null, culture, this);
}

#endregion

自定义状态管理#region 自定义状态管理

private bool _isTrackingViewState;
private StateBag _viewState;

protected StateBag ViewState
{
get
{
if (_viewState == null)
{
_viewState = new StateBag(false);
if (_isTrackingViewState) ((IStateManager)_viewState).TrackViewState();
}
return _viewState;
}
}

bool IStateManager.IsTrackingViewState
{
get
{
return _isTrackingViewState;
}
}

void IStateManager.LoadViewState(object savedState)
{
if (savedState != null)
{
((IStateManager)ViewState).LoadViewState(savedState);
}
}

object IStateManager.SaveViewState()
{
object savedState = null;
if (_viewState != null)
{
savedState =
((IStateManager)_viewState).SaveViewState();
}
return savedState;
}

void IStateManager.TrackViewState()
{
_isTrackingViewState = true;

if (_viewState != null)
{
((IStateManager)_viewState).TrackViewState();
}
}

internal void SetDirty()
{
_viewState.SetDirty(true);
}

#endregion
}
}

本来不想解释什么,怕大家嫌我罗嗦,但是要记得ViewState的为StateBag类型

3.2第二步,维护自定义属性的状态,(请注意,此时的CustomAddress就是People的一个属性,所以我们就叫自定义属性的状态维护)
Code
自定义视图状态#region 自定义视图状态

[Description("地址集合")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[PersistenceMode(PersistenceMode.InnerProperty)]
public Address CustomAddress
{
get
{
if (address == null)
{
address = new Address();
if (IsTrackingViewState)
{
((IStateManager)address).TrackViewState();
}
}
return address;
}
}

protected override void LoadViewState(object savedState)
{
Pair p = savedState as Pair;
if (p != null)
{
base.LoadViewState(p.First);
((IStateManager)CustomAddress).LoadViewState(p.Second);
return;
}
base.LoadViewState(savedState);

}

protected override object SaveViewState()
{
object baseState = base.SaveViewState();
object thisState = null;

if (address != null)
{
thisState = ((IStateManager)address).SaveViewState();
}

if (thisState != null)
{
return new Pair(baseState, thisState);
}
else
{
return baseState;
}

}

protected override void TrackViewState()
{
if (address != null)
{
((IStateManager)address).TrackViewState();
}
base.TrackViewState();
}

#endregion有几个地方,要请大家注意

一点,视图状态的操作包括基类base的操作,还需要调用相应的自定义属性的类型的状态维护方法。
二点,Load和Save是一个完全相反的操作过程。
三点,Load和Save保持数据的Pair,可以用数组Array代替,如果是两个自定义属性,怎么办呢?当然是Priple,如果是三个呢?怎么办?请大家自己想。
四点,要理解视图状态,先理解她的生命周期,免得有时候,竹篮打水,一场空。
五点,CustomAddress属性为只读, ^-^
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: