主题,控件的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.必须以添加它们的相同顺序检索
四 控件状态的细节远不只是这些,有不妥当的地方,还望同仁指出...(后续)