ASP.NET动态创建控件和回发

时间:2010-11-18 15:16:25

标签: asp.net postback dynamic-data

我知道这个问题已被问过几千次了,而且之前我一直在努力解决它,但由于某种原因,我无法完成我想要完成的任务......我有一个动态添加的LinkBut​​ton,当点击时将动态添加控件(在此示例中为文本框)到同一个面板。目的是在点击LinkBut​​ton的时候连续添加尽可能多的控件(即我单击一次,一个框,然后另一次单击将给我2个框,另一个单击添加第三个)。在下面的代码中,我使用序列化的当前日期和时间为每个文本框控件创建一个唯一的ID。

当我执行代码时,单击“添加过滤器”将生成一个新文本框,但是再次单击将创建一个新文本框,并在其之前处理该文本框。相反,我想要保留以前的文本框以及在其中提交的任何数据。

感谢您的帮助。

在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);
}

4 个答案:

答案 0 :(得分:16)

对于其他试图做这样事情的人:不要。相反,要考虑信息流,并了解有更好的方法。输入控件不需要动态创建。它们可以是静态的,在填写和提交时,该信息必须在某处(例如,数据库,缓存,会话)。一旦它在那里,在回发时,循环选择存储中的所有项目并为它们创建显示。

这就是我所做的,它让生活变得更轻松。希望它可以帮到某人。

答案 1 :(得分:11)

void lbAddFilter_Click(object sender, EventArgs e)
{
    TextBox tb = new TextBox();
    tb.ID = "tb" + DateTime.Now.ToBinary().ToString();
    pnlFilter.Controls.Add(tb);
}

这不会起作用 - 这是你在问题中推断的生命周期问题。有很多方法可以解决这个问题,但Honus Wagner的建议是最灵活的。

这里发生的是你在事件处理程序中调用Controls.Add并将控件添加到控件列表中,并在下一个请求中(无论是部分回发,完全回发还是新页面命中) ,这种控制已经消失,因为你没有把它坚持到任何地方。

以下是您的页面事件生命周期中正在发生的事情:

  1. 页面调用OnInit并添加您的LinkBut​​ton
  2. 用户点击LinkBut​​ton
  3. 页面调用OnInit开始回发请求。重新创建LinkBut​​ton
  4. 调用事件处理程序,它动态创建TextBox并将其添加到控件集合
  5. 用户再次点击LinkBut​​ton
  6. 页面调用OnInit再次添加LinkBut​​ton。此时pnlFilter.Controls集合为空,除了您在标记中静态声明的任何元素。
  7. 调用事件处理程序,并将新的TextBox添加到控件列表中。
  8. 我不确定这是最好的做法,但我已经成功使用了类似的模型(注意我没有测试过这段代码 - 可能需要调整):

    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);
    }
    

    请注意,我不确定是否将实际的Control对象添加到会话存储中 - 我相信控件ID存在问题会导致回发错误(可能是Control无法序列化?)。在我开发的解决方案中,我在GenerateControl方法中生成了一个新的TextBox / Label / ComboBox / etc,并在PersistedControls集合中存储了一个自定义容器类,其中包含我需要生成的UI控件的各种属性它在每个页面上。

答案 2 :(得分:1)

我相信你需要在每次回发时重新创建每个控件。

我知道Repeater控件存储有关其子节点的足够信息,以便在数据绑定时重新创建它们...您可以使用它来节省一些工作。

答案 3 :(得分:0)

尝试添加,

if(!Page.IsPostback)
  --- your code that adds different controls.