.Net 2.0 中的动态控件解决方案
最常用的解决办法就是把动态控件放在OnInit事件中创建,并且放在IsPostback之外,可是这样一来就非常得不方便了,如果一定要在按钮的Click事件
中处理怎么办呢?下面说说我的解决办法,也许很菜,请不要见笑。
这要从Postback机制说起,当页面正常载入以后,页面会递归的执行控件的TrackViewState方法,也就是跟踪控件的ViewState状态是否更改,等页面完后生成以后,
页面又会递归的调用控件的SaveViewState方法以保存控件的ViewState状态,然后当页面PostBack时,页面又会递归地执行控件的LoadViewState方法以还原控件的
ViewState状态,所以,要保存动态控件的ViewState状态也必须分三步。
完整的代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Reflection;
namespace Sxw888.Base
{
public class DynamicControlPage : System.Web.UI.Page
{
private List<DynamicControlItem> dynamicControlItems = new List<DynamicControlItem>();
protected void TrackControlViewState(System.Web.UI.Control control)
{
Type type = typeof(System.Web.UI.Control);
type.InvokeMember("TrackViewState", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, control, null);
}
protected void AddDynamicControlPageToTree(System.Web.UI.Control control)
{
if (!this.EnableViewState)
{
throw new System.Exception("当Page的EnableViewState为false时不能添加动态控件!");
}
if (control.Parent == null) throw new System.Exception("请将该控件添加入控件树!");
this.AddDynamicControlPageToTreePrivate(control);
}
private void AddDynamicControlPageToTreePrivate(System.Web.UI.Control control)
{
if (!control.EnableViewState) return;
if (!String.IsNullOrEmpty(control.ID))
{
if (this.FindDynamicControl(control.ID) != null) return;
}
if (String.IsNullOrEmpty(control.ID)) control.ID = control.UniqueID;//new Guid().ToString();
DynamicControlItem item = new DynamicControlItem();
item.Control = control;
item.Parameter = new DynamicControlParameter();
item.Parameter.Id = control.ID;
item.Parameter.ParentId = control.Parent.ID;
item.Parameter.TypeName = control.GetType().AssemblyQualifiedName;
item.Parameter.ViewState = null;
this.dynamicControlItems.Add(item);
if (control.HasControls())
{
foreach (System.Web.UI.Control c in control.Controls)
{
this.AddDynamicControlPageToTreePrivate(c);
}
}
}
public System.Web.UI.Control FindDynamicControl(string Id)
{
foreach (DynamicControlItem item in this.dynamicControlItems)
{
if (item.Control.ID == Id) return item.Control;
}
return null;
}
protected virtual override void LoadViewState(object savedState)
{
Pair p = (Pair)savedState;
DynamicControlParameter[] DynamicControlParameters = (DynamicControlParameter[])p.Second;
foreach (DynamicControlParameter Paremeter in DynamicControlParameters)
{
Type type = Type.GetType(Paremeter.TypeName);
ConstructorInfo construct = type.GetConstructor(new Type[] { });
System.Web.UI.Control c = (System.Web.UI.Control)construct.Invoke(new object[] { });
type.InvokeMember("LoadViewState", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, c, new object[] { Paremeter.ViewState });
c.ID = Paremeter.Id;
if (this.FindControl(c.ID) != null) continue;
System.Web.UI.Control parent = this.FindControl(Paremeter.ParentId);
if (parent == null) parent = this.FindDynamicControl(Paremeter.ParentId);
parent.Controls.Add(c);
DynamicControlItem item = new DynamicControlItem();
item.Parameter = Paremeter;
item.Control = c;
this.dynamicControlItems.Add(item);
}
base.LoadViewState(p.First);
}
protected virtual override object SaveViewState()
{
Pair p = new Pair();
p.First = base.SaveViewState();
List<DynamicControlParameter> objects = new List<DynamicControlParameter>();
foreach (DynamicControlItem item in this.dynamicControlItems)
{
Type t = typeof(System.Web.UI.Control);
object o = t.InvokeMember("SaveViewState", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, item.Control, null);
item.Parameter.ViewState = o;
objects.Add(item.Parameter);
}
p.Second = objects.ToArray();
return p;
}
}
[Serializable]
internal class DynamicControlParameter
{
private string _TypeName;
private string _Id;
private string _ParentId;
private object _ViewState;
public string TypeName
{
get { return this._TypeName; }
set { this._TypeName = value; }
}
public string Id
{
get { return this._Id; }
set { this._Id = value; }
}
public string ParentId
{
get { return this._ParentId; }
set { this._ParentId = value; }
}
public object ViewState
{
get { return this._ViewState; }
set { this._ViewState = value; }
}
}
internal class DynamicControlItem
{
private System.Web.UI.Control _Control;
private DynamicControlParameter _Paremeter;
public System.Web.UI.Control Control
{
get { return this._Control; }
set { this._Control = value; }
}
public DynamicControlParameter Parameter
{
get { return this._Paremeter; }
set { this._Paremeter = value; }
}
}
}
上述代码的用法如下:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Xml.Serialization;
public partial class test : Sxw888.Base.DynamicControlPage
{
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
TextBox tb = new TextBox();
this.TrackControlViewState(tb);
tb.Text = "测试";
this.Panel1.Controls.Add(tb) //假设页面中有一Panel控件,并且ID为Panel1
this.AddDynamicControlPageToTree(tb);
}
}
好,现在可以去测试一下,你会发现PostBack一下之后,动态生成的控件仍然还在,对了,如果还需要激活动态控件的事件的话,只需要重载一下LoadViewState方法即可,这里不作说明。
匆匆忙忙写一点,希望大家批评指正。
posted on 2008-07-08 12:58 一切随缘(183031322) 阅读(2400) 评论(10) 编辑 收藏 举报
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步