主题,控件的viewstate状态
一“七七八八”
有次,朋友开玩笑说,不知道什么时候,微软会取消viewstate,不再使用隐藏字段在服务器与客户端保存状态!虽然,可以使用客户端技术减少一些回传,但是,一些必要的服务器状态还是要保存的,现在网络带宽已经不是问题,所以在网络上适当的传递一些状态数据,还是可以容忍的!当然,如果终端是mobile,可以考虑把viewstate保存到服务器上!
二“误解viewstate”
园子里,有不少描写viewstate的文字,也看了不少,知道Viewstate实现了IStateManager接口的一个属性和三个方法!刚接触“她”的时候,一直以为control对象直接实现了IStateManager接口,模糊的记得好象有几个LoadViewstate和SaveViewstate方法,也没有在意方法有没有override修饰!后来发现不是这样的,control并没有直接实现IStateManager接口,而是通过定义一个StateBar类型的Viewstate属性,委托Viewstate属性去管理状态,也就是让StateBar类型去真正实现状态的管理,这种方式可以使控件本身和viewState的实现完全分离!也许,这些经验,对高手谈不上是“经验”,希望刚入门的同仁能少走点弯路!
三“结合Style样式,浅谈Viewstate”
Viewstate属性能装载的数据类型比较有限,但是有些不能加载的类型怎么办呢?当然是重写
IStateManager了,然后WebControl委托给ControlStyle属性来管理状态,有点象WebControl
定义ViewState属性
还是从简单的入手吧,直接使用Style类型的状态管理
目标,定义一个文本框和一个按钮的复合控件
要点,分别给文本框和按钮各自定义样式,并提升她们为顶级样式属性
图一

图二 (文本框和按钮的样式)

图四 Demo

Code
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.ComponentModel.Design;

namespace WebControlLibrary


{
[
DefaultEvent("Button"),
DefaultProperty("Text"),
//Designer(typeof(WebControlLibrary.Design.CustomerControlDesigner))
]
public class WebCustomControl1 : CompositeControl

{
//声明变量
private Button _button;
private TextBox _textBox;
private static readonly object EventButtonClick = new object();
private Style _buttonStyle;
private Style _textBoxStyle;

//定义属性Text,用于指定按钮上的文字
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("获取或设置显示显示在按钮上的文字")
]
public string Text

{
get

{
EnsureChildControls();
return _button.Text;
}

set

{
EnsureChildControls();
_button.Text = value;
}
}

//定义ButtonStyle属性
[
Category("Style"),
Description("设置Button的样式属性"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.InnerProperty),
]
public virtual Style ButtonStyle

{
get

{
if (_buttonStyle == null)

{
_buttonStyle = new Style();
if (IsTrackingViewState)

{
((IStateManager)_buttonStyle).TrackViewState();
}
}
return _buttonStyle;
}
}

//定义TextStyle属性
[
Category("Style"),
Description("设置TextBox的样式属性"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.InnerProperty),
]
public virtual Style TextBoxStyle

{
get

{
if (_textBoxStyle == null)

{
_textBoxStyle = new Style();
if (IsTrackingViewState)

{
((IStateManager)_textBoxStyle).TrackViewState();
}
}
return _textBoxStyle;
}
}

//重写Controls属性
public override ControlCollection Controls

{
get

{
EnsureChildControls();
return base.Controls;
}
}

//重写CreateChildControls方法,将子控件添加到复合控件中
protected override void CreateChildControls()

{
Controls.Clear();
_button = new Button();
_textBox = new TextBox();
_button.ID = "btn";
_button.CommandName = "ButtonClick";
this.Controls.Add(_button);
this.Controls.Add(_textBox);
}

//重写Render方法,呈现控件中其他的HTML代码
protected override void Render(HtmlTextWriter output)

{
//AddAttributesToRender(output);
if (_textBoxStyle != null)

{
_textBox.ApplyStyle(TextBoxStyle);
}
if (_buttonStyle != null)

{
_button.ApplyStyle(ButtonStyle);
}
output.AddAttribute(HtmlTextWriterAttribute.Border, "0px");
output.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "5px");
output.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0px");
output.RenderBeginTag(HtmlTextWriterTag.Table);
output.RenderBeginTag(HtmlTextWriterTag.Tr);
output.RenderBeginTag(HtmlTextWriterTag.Td);
_textBox.RenderControl(output);
output.RenderEndTag();
output.RenderBeginTag(HtmlTextWriterTag.Td);
_button.RenderControl(output);
output.RenderEndTag();
output.RenderEndTag();
output.RenderEndTag();
}

//事件处理
public event EventHandler ButtonClick

{
add

{
Events.AddHandler(EventButtonClick, value);
}
remove

{
Events.RemoveHandler(EventButtonClick, value);
}
}

protected virtual void OnButtonClick(EventArgs e)

{
EventHandler buttonClickHandler = (EventHandler)Events[EventButtonClick];
if (buttonClickHandler != null)

{
buttonClickHandler(this, e);
}
}

protected override bool OnBubbleEvent(object sender, EventArgs e)

{
bool handled = false;
if (e is CommandEventArgs)

{
CommandEventArgs ce = (CommandEventArgs)e;
if (ce.CommandName == "ButtonClick")

{
OnButtonClick(EventArgs.Empty);
handled = true;
}
}
return handled;
}

//样式状态管理,重写3个相关方法
protected override void LoadViewState(object savedState)

{
if (savedState == null)

{
base.LoadViewState(null);
return;
}
if (savedState != null)

{
object[] myState = (object[])savedState;
if (myState.Length != 3)

{
throw new ArgumentException("无效的ViewState");
}
base.LoadViewState(myState[0]);
if (myState[1] != null)

{
((IStateManager)TextBoxStyle).LoadViewState(myState[1]);
}
if (myState[2] != null)

{
((IStateManager)ButtonStyle).LoadViewState(myState[2]);
}
}
}

protected override object SaveViewState()

{
object[] myState = new object[3];
myState[0] = base.SaveViewState();
myState[1] = (_textBoxStyle != null) ? ((IStateManager)_textBoxStyle).SaveViewState() : null;
myState[2] = (_buttonStyle != null) ? ((IStateManager)_buttonStyle).SaveViewState() : null;

for (int i = 0; i < 3; i++)

{
if (myState[i] != null)

{
return myState;
}
}
return null;
}

protected override void TrackViewState()

{
base.TrackViewState();

if (_buttonStyle != null)

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

{
((IStateManager)_textBoxStyle).TrackViewState();
}
}
}
}

Demo比较简单,在类顶部定义了两个Style类型的属性,然后重写维护状态的三个方法一个属性
注意
1.这里并不是直接重写IStateManager接口
2.重写 SaveViewState 方法以将附加样式属性保存到 ViewState
3.重写 LoadViewState 方法以自定义从 ViewState 的附加样式属性的还原
4.必须以添加它们的相同顺序检索
四 控件状态的细节远不只是这些,有不妥当的地方,还望同仁指出...(后续)