Добавление элементов управления динамически в UpdatePanel в ASP.NET AJAX

У меня есть следующий действительно простой код

<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
    <asp:PlaceHolder ID="PlaceHolder1" runat="server">
    </asp:PlaceHolder>
    <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
</ContentTemplate>
</asp:UpdatePanel>

И codebehind

protected void Button1_Click(object sender, EventArgs e)
{
    Literal literal = new Literal();
    literal.Text = DateTime.Now.ToString();
    literal.ID = DateTime.Now.Ticks.ToString();

    // These both work fine the first time the button is clicked
    // but the second time nothing is added.
    UpdatePanel1.ContentTemplateContainer.Controls.Add(literal);
    PlaceHolder1.Controls.Add(literal);
}

Моя проблема заключается в том, что элемент управления Literal добавляется только один раз. Я просмотрел сайты Google и блога (плюс книги), но без везения. Что мне не хватает?

Ответы

Ответ 1

В asp.net элементы управления в файле ASPX автоматически генерируются при каждой обратной передаче. Элементы управления, которые вы создали, не входят в код ASPX, поэтому структура не создает их для вас. При первом запуске метода Button1_Click вы добавляете один дополнительный элемент управления на страницу. Во второй раз, когда вы запускаете метод Button1_Click, вы находитесь в другом сообщении, и эта первая дополнительная кнопка была забыта. Таким образом, результат этой обратной передачи - вы снова получите одну дополнительную кнопку.

Это будет создавать один дополнительный элемент управления каждый раз, когда вы нажимаете кнопку (хотя временные метки будут обновляться каждый раз, когда вы нажимаете кнопку, потому что элементы управления заново создаются)

protected void Button1_Click(object sender, EventArgs e)
{
    int count = 0;

    if (ViewState["ButtonCount"] != null)
    {
        count = (int)ViewState["ButtonCount"];
    }

    count++;
    ViewState["ButtonCount"] = count;

    for (int i = 0; i < count; i++)
    {
        Literal literal = new Literal();
        literal.Text = DateTime.Now.ToString();
        literal.ID = DateTime.Now.Ticks.ToString();

        UpdatePanel1.ContentTemplateContainer.Controls.Add(literal);
        PlaceHolder1.Controls.Add(literal);
    }            
}

Ответ 2

Я согласен с приведенным выше ответом. Однако этот подход не сохранит состояние динамических элементов управления (или, если быть точным, он сохранит состояние, но не загрузит их обратно). Состояние представления нагрузки вызывается в разделе "Событие нагрузки" жизненного цикла страницы, где он присваивает обратно управляющие значения, сохраненные в состоянии просмотра. Однако, если элементы управления не создаются к этому времени, они не могут быть загружены с предыдущими данными, поэтому для состояния, которое необходимо сохранить, новые элементы управления должны быть воссозданы или перед событием загрузки.

protected void Page_Load(object sender, EventArgs e)
{
    //PS: Below approach saves state as id is constant, it simply generates a new control with same id hence viewstate loads the value
    if (IsPostBack)
    {
        int count = 0;

        if (ViewState["ButtonCount"] != null)
        {
            count = (int)ViewState["ButtonCount"];
        }

        count++;
        ViewState["ButtonCount"] = count;

        for (int i = 0; i < count; i++)
        {
            TextBox literal = new TextBox();
            //literal.Text = DateTime.Now.ToString();
            literal.ID = "Textbox" + i.ToString();

            //UpdatePanel1.ContentTemplateContainer.Controls.Add(literal);
            PlaceHolder1.Controls.Add(literal);

        }
    }
}

Динамическое добавление элементов управления Просмотр состояния и обратной передачи