ASP.NETdynamic创build控件和回发
我知道这个问题已经被问了几千次了,之前我一直在努力,但由于某种原因,我不能完成我想要完成的任务…我有一个dynamic添加的LinkButton,点击后会dynamic添加一个控件(在这个例子中是一个文本框)到同一个面板。 意图是不断添加尽可能多的控件,作为LinkButton被点击的时间(即我点击一次,一个框,然后再点击将给我2盒,另一次点击增加了第三)。 在下面的代码中,我使用序列化的当前date和时间为每个文本框控件创build一个唯一的ID。
当我执行代码时,单击“添加filter”将会生成一个新的文本框,但是一旦再次单击将创build一个新的文本框,并在其之前进行处理。 相反,我想坚持以前的文本框以及其中提交的任何数据。
你的帮助表示赞赏。
在aspx:
<asp:Panel ID="pnlFilter" runat="server"> </asp:Panel>
在aspx.cs中:
protected void Page_Init(object sender, EventArgs e) { LinkButton lb = new LinkButton(); lb.ID = "lbAddFilter"; pnlFilter.Controls.Add(lb); lb.Text = "Add Filter"; lb.Click += new EventHandler(lbAddFilter_Click); } void lbAddFilter_Click(object sender, EventArgs e) { TextBox tb = new TextBox(); tb.ID = "tb" + DateTime.Now.ToBinary().ToString(); pnlFilter.Controls.Add(tb); }
对于其他人试图做这样的事情:不要。 相反,想一想信息的stream动,并明白有一个更好的方法来做到这一点。 input控件不需要dynamic创build。 它们可以是静态的,在填写和提交时,信息必须到达某处(例如数据库,caching,会话)。 一旦它在那里,回发,循环通过您的存储select的所有项目,并为他们创build一个显示。
这就是我所做的,使生活变得更容易。 希望它可以帮助别人。
void lbAddFilter_Click(object sender, EventArgs e) { TextBox tb = new TextBox(); tb.ID = "tb" + DateTime.Now.ToBinary().ToString(); pnlFilter.Controls.Add(tb); }
这是行不通的 – 这是您在问题中推断的生命周期问题。 有很多方法可以解决这个问题,但瓦格纳的build议是最灵活的。
这里发生的事情是,你在事件处理程序中调用Controls.Add,并将控件添加到控件列表,并在下一个请求(是部分回发,完整回发或新的页面命中),该控件已经走了,因为你没有坚持到任何地方。
以下是您的页面事件生命周期中正在发生的事情:
- 页面调用OnInit并添加您的LinkButton
- 用户点击LinkButton
- 页面调用OnInit来开始回发请求。 LinkButton被重新创build
- 事件处理程序被调用,它dynamic创build您的TextBox并将其添加到控件集合
- 用户再次单击LinkButton
- 页面调用OnInit再次添加LinkButton。 pnlFilter.Controls集合在这一点上是空的,除了你在标记中静态声明的任何元素。
- 事件处理程序被调用,一个新的TextBox被添加到控制列表中。
我不确定这是否是最佳做法,但是我已经成功使用了与此相似的模型(请注意,我没有testing过这个代码 – 可能需要调整):
protected override void OnInit(EventArgs e) { base.OnInit(e); LinkButton lb = new LinkButton(); lb.ID = "lbAddFilter"; pnlFilter.Controls.Add(lb); lb.Text = "Add Filter"; lb.Click += new EventHandler(lbAddFilter_Click); // regenerate dynamically created controls foreach ( var control in PersistedControls ) { pnlFilter.Controls.Add(GenerateControl(control)); } } private IList<Control> _persistedControls; private const string PersistedControlsSessionKey = "thispage_persistedcontrols"; private IList<Control> PersistedControls { if (_persistedControls == null) { if (Session[PersistedControlsSessionKey] == null) Session[PersistedControlsSessionKey] = new List<Control>(); _persistedControls = Session[PersistedControlsSessionKey] as IList<Control>; } return _persistedControls; } void lbAddFilter_Click(object sender, EventArgs e) { TextBox tb = new TextBox(); tb.ID = "tb" + DateTime.Now.ToBinary().ToString(); PersistedControls.Add(tb); pnlFilter.Controls.Add(tb); }
请注意,我不确定是否将实际的控件对象添加到会话存储 – 我相信有问题的控件ID将导致错误回发(也许控制不可序列化?)。 在我开发的解决scheme中,我生成了一个新的TextBox / Label / ComboBox /等同于GenerateControl方法,并在PersistedControls集合中存储了一个自定义容器类,该集合包含需要生成的UI控件的各种属性它在每个页面Init。
我相信你需要在每一个回传中重新创build每个控件。
我知道Repeater控件在数据绑定时存储了有关其子项的足够信息以重新创build它们…您可能可以使用它来节省一些工作。
尝试添加,
if(!Page.IsPostback) --- your code that adds different controls.