完整的代码如下:
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方法即可,这里不作说明。
匆匆忙忙写一点,希望大家批评指正。