Подтвердить что ты не робот

Как получить значение динамически заполненных элементов управления

У меня есть div Conatining a Panel на странице aspx

<div id="divNameofParticipants" runat="server">
    <asp:Panel ID="panelNameofParticipants" runat="server">
    </asp:Panel>
</div>

Я динамически заполняю панель с кода следующим кодом:

void btnSubmitCountParticipant_Click(object sender, EventArgs e)
    {
        StringBuilder sbparticipantName=new StringBuilder();

        try
        {
            int numberofparticipants = Convert.ToInt32(drpNoofparticipants.SelectedValue);
            ViewState["numberofparticipants"] = numberofparticipants;
            Table tableparticipantName = new Table();
            int rowcount = 1;
            int columnCount = numberofparticipants;
            for (int i = 0; i < rowcount; i++)
            {
                TableRow row = new TableRow();
                for (int j = 0; j < columnCount; j++)
                {
                    TableCell cell = new TableCell();
                    TextBox txtNameofParticipant = new TextBox();
                    txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
                    cell.ID = "cell" + Convert.ToString(i);
                    cell.Controls.Add(txtNameofParticipant);
                    row.Cells.Add(cell);


                }
                tableparticipantName.Rows.Add(row);
                panelNameofParticipants.Controls.Add(tableparticipantName);

            }

        }
        catch(Exception ex)
        {


        }
    }

Теперь я хочу получить доступ к значению этого динамически сгенерированного текстового поля в codebehind.for, где мой код выглядит следующим образом:

public void CreateControls()
    {

        try
        {
            //String test1 = test.Value;
            List<string> listParticipantName = new List<string>();
            if (ViewState["numberofparticipants"] != null)
            {
                int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
                for (int i = 0; i < numberofparticipants; i++)
                {
                    string findcontrol = "txtNameofParticipant" + i;
                    TextBox txtParticipantName = (TextBox)panelNameofParticipants.FindControl(findcontrol);
                    listParticipantName.Add(txtParticipantName.Text);

                }
            }
        }
        catch (Exception ex)
        {

        }
    }

но я не могу получить значения в codebehind.

 TextBox txtParticipantName = (TextBox)panelNameofParticipants.FindControl(findcontrol);

приведенный выше код не может найти элемент управления и всегда дает null. Что я делаю неправильно. Я воссоздал элементы управления при загрузке страницы, так как postback является апатридом, но все равно не имеет успеха.

Спасибо в Advance

4b9b3361

Ответ 1

Вам необходимо создать динамические элементы управления в PreInit, а не в OnLoad. Смотрите документацию здесь: https://msdn.microsoft.com/en-us/library/ms178472.aspx

Re/Создание элементов управления при загрузке страницы приведет к тому, что ViewState не будет привязан к элементам управления, потому что привязка к представлению будет происходить до OnLoad.

Ответ 2

Как упоминалось другими людьми. Чтобы создать динамические элементы управления, вам нужно сделать это для каждой обратной передачи и в нужное время. Для рендеринга динамических элементов управления используйте событие Preinit. Я предлагаю вам ознакомиться с https://msdn.microsoft.com/en-us/library/ms178472(v=vs.80).aspx, чтобы узнать больше об этом.

MSDN - PreInit:Используйте это событие для следующего: Проверьте свойство IsPostBack, чтобы определить, будет ли это первый раз, когда страница обрабатывается. Создать или воссоздать динамические элементы управления.Задайте основную страницу динамически. Задайте свойство Theme динамически. Прочитайте или задайте значения свойств профиля. NoteNote Если запрос является обратной передачей, значения элементов управления еще не восстановлены из состояния просмотра. Если вы установите свойство управления на этом этапе, его значение может быть перезаписано в следующем событии.

Следующее интересное событие: Preload, которое гласит:

MSDN - PreLoadИспользуйте это событие, если вам нужно выполнить обработку на своей странице или управлять до события загрузки. После того, как страница вызывает это событие, оно загружает состояние представления для себя и всех элементов управления, а затем обрабатывает любые данные обратной передачи, включенные в экземпляр запроса.

Значение в следующем событии Загрузить (Page_Load) должно быть загружено в viewstate, поэтому здесь вы должны эффективно проверить свои значения.

Вам также необходимо убедиться, что состояние просмотра включено, а самый простой - это, вероятно, в директиве уровня страницы:

<%@Page EnableViewState="True" %>

Взгляните на статью https://msdn.microsoft.com/en-us/library/ms972976.aspx 2, которая больше глубина всего этого

Примечание

Если ваша проблема заключается в том, что вам нужно динамически создавать элементы управления при нажатии кнопки, и будет создано множество элементов управления, вероятно, вы должны перейти на jQuery ajax и использовать атрибут [WebMethod] для публичной функции в вашем коде. Создание динамических элементов управления и поддержка ViewState довольно дорогостоящее, поэтому я рекомендую это для лучшего удобства пользователей.

Ответ 3

Если вы используете элемент управления DataPresentation, например asp:GridView, это будет намного проще.

Разметка

<asp:GridView ID="ParticipantsGrid" runat="server" AutoGenerateColumns="false">   
    <Columns>
        <asp:TemplateField HeaderText="Participants">
            <ItemTemplate>
                <asp:TextBox ID="txtNameofParticipant" runat="server" 
                    Text='<%# Container.DataItem %>'>
                </asp:TextBox>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

Code-за

protected void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
    try
    {
        var selectedParticipantCount = Convert.ToInt32(drpNoofparticipants.SelectedValue);
        var items = Enumerable.Repeat(string.Empty, selectedParticipantCount).ToList();
        ParticipantsGrid.DataSource = items;
        ParticipantsGrid.DataBind();
    }
    catch (Exception ex)
    { }
}
public void CreateControls()
{

    try
    {
        var participants = ParticipantsGrid.Rows
            .Cast<GridViewRow>()
            .Select(row => ((TextBox)row.FindControl("txtNameofParticipant")).Text)
            .ToList();
    }
    catch (Exception ex)
    { }
}

Ответ 4

Я думаю, что вы делаете это правильно. В веб-формах asp.net существует много раз, когда вы будете испытывать странные вещи, которые происходят. Особенно при наличии ViewState. Сначала нам необходимо устранить наш код и попробовать различные тесты и подходы. Это будет моим советом для вас, просьба использовать этот код и отлаживать, если что действительно происходит:

    void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
    StringBuilder sbparticipantName=new StringBuilder();

    try
    {
        int numberofparticipants = Convert.ToInt32(drpNoofparticipants.SelectedValue);
        ViewState["numberofparticipants"] = numberofparticipants;
        Table tableparticipantName = new Table();
        int rowcount = 1;
        int columnCount = numberofparticipants;

        TableRow row = new TableRow();
        TableCell cell = new TableCell();
        TextBox txtNameofParticipant = new TextBox();
        txtNameofParticipant.ID = "NameTest";
        txtNameofParticipant.Text = "This is a textbox";
        cell.ID = "cellTest";
        cell.Controls.Add(txtNameofParticipant);
        row.Cells.Add(cell);

        tableparticipantName.Rows.Add(row);
        panelNameofParticipants.Controls.Add(tableparticipantName);

    }
    catch(Exception ex)
    { // please put a breakpoint here, so that we'll know if something occurs, 
    }
}


public void CreateControls()
{
    try
    {
        //String test1 = test.Value;
        List<string> listParticipantName = new List<string>();
        //if (ViewState["numberofparticipants"] != null)
        //{
        string findcontrol = "NameTest";
        TextBox txtParticipantName = (TextBox)panelNameofParticipants.Controls["NameText"];
        //check if get what we want. 
        listParticipantName.Add(txtParticipantName.Text);
        //}
    }
    catch (Exception ex)
    {// please put a breakpoint here, so that we'll know if something occurs, 
    }
}

Ответ 5

Динамические элементы управления необходимо воссоздавать на каждой обратной стороне. Самый простой способ добиться этого в вашем коде будет заключаться в кэшировании структуры управления и ее повторной засекречивания. Это можно сделать:

void btnSubmitCountParticipant_Click(object sender, EventArgs e)
{
    StringBuilder sbparticipantName=new StringBuilder();
    Panel p1 = new Panel();

    try
    {
        int numberofparticipants = Convert.ToInt32(drpNoofparticipants.SelectedValue);
        ViewState["numberofparticipants"] = numberofparticipants;
        Table tableparticipantName = new Table();
        int rowcount = 1;
        int columnCount = numberofparticipants;
        for (int i = 0; i < rowcount; i++)
        {
            TableRow row = new TableRow();
            for (int j = 0; j < columnCount; j++)
            {
                TableCell cell = new TableCell();
                TextBox txtNameofParticipant = new TextBox();
                txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
                cell.ID = "cell" + Convert.ToString(i);
                cell.Controls.Add(txtNameofParticipant);
                row.Cells.Add(cell);


            }
            tableparticipantName.Rows.Add(row);
            p1.Controls.Add(tableparticipantName);
        }
        Cache["TempPanel"] = p1;
        panelNameofParticipants.Controls.Add(p1);

    }
    catch(Exception ex)
    {


    }
}

Посмотрите на панель p1 в приведенном выше коде, чтобы увидеть изменения. Теперь код для функции CreateControls необходимо изменить следующим образом:

public void CreateControls()
{

    try
    {

        Panel p1= (Panel)Cache["TempPanel"];
        panelNameofParticipants.Controls.Add(p1);

        //String test1 = test.Value;
        List<string> listParticipantName = new List<string>();
        if (ViewState["numberofparticipants"] != null)
        {
            int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
            for (int i = 0; i < numberofparticipants; i++)
            {
                string findcontrol = "txtNameofParticipant" + i;
                TextBox txtParticipantName = (TextBox)panelNameofParticipants.FindControl(findcontrol);
                listParticipantName.Add(txtParticipantName.Text);

            }
        }
    }
    catch (Exception ex)
    {

    }
}

Надеюсь, что это поможет.

Ответ 6

Динамически созданные элементы управления будут исчезать при возврате страницы назад. Эта статья здесь объясняет, почему это происходит.

Итак, чтобы распознавать динамические элементы управления на странице asp.net, вам нужно воссоздать его в обработчике событий preinit, но я думаю, что это сложно, так как этот динамический элемент управления в вашем случае полагается на какой-либо другой элемент веб-формы, такой как выпадающий список drpNoofparticipants, а также ViewState на данном этапе недоступен.

Мое предложение состоит в том, что мы делаем это по-другому, каждый пост назад на самом деле является сообщением формы, поэтому вместо того, чтобы находить динамическое текстовое поле, вы можете напрямую получить значение через коллекцию Request.Form. Вот фрагмент кода:

        var list = Request.Form.AllKeys.Where(x => x.Contains("txtNameofParticipant"));
        foreach (var item in list)
        {
            var value = Request.Form[item];
        }

Таким образом, вы можете получить значение, и, поскольку вам не нужно полагаться на механизм ASP.NET для получения значения из динамически созданного элемента управления, вы можете отложить повторное создание таблицы в обработчике событий page_load.

Надеюсь, что это поможет.

Ответ 7

Поместите данные метода btnSubmitCountParticipant_Click в другую функцию с именем по вашему выбору. Вызвать эту функцию в методе btnSubmitCountParticipant_Click и в методе CreateControls(). Также вырежьте пасту ниже кода в методе btnSubmitCountParticipant_Click

int numberof участников = Convert.ToInt32 (drpNoofparticipants.SelectedValue);             ViewState [ "numberofчастников" ] = число участников,

. Это работает на моей машине. Надеюсь, что это поможет

Ответ 8

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

//Create Button Dynamic Control
             protected void btnDyCreateControl_Click(object sender, EventArgs e)
                    {

                        try
                        {
                            int numberofparticipants = 5;
                            ViewState["numberofparticipants"] = numberofparticipants;
                            int test = (int)ViewState["numberofparticipants"];
                            int rowcount = 1;
                            int columnCount = numberofparticipants;
                            CreateDynamicTable(rowcount, columnCount);


                        }
                        catch (Exception ex)
                        {


                        }
                    }
                 //submit values
            protected void btnSave_Click(object sender, EventArgs e)
                {
                   try
                {

                    List<string> listParticipantName = new List<string>();
                    if (ViewState["numberofparticipants"] != null)
                    {
                        int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);

                            foreach (Control c in panelNameofParticipants.Controls)
                            {   
                               if (c is Table)
                                {
                                    foreach (TableRow row in c.Controls)
                                    {
                                        int i = 0;
                                        foreach (TableCell cell in row.Controls)
                                        {

                                            if (cell.Controls[0] is TextBox)
                                            {
                                                string findcontrol = "txtNameofParticipant" + i;
                                                TextBox txtParticipantName = (TextBox)cell.Controls[0].FindControl(findcontrol);
                                                listParticipantName.Add(txtParticipantName.Text);

                                            }
                                            i++;

                                        }


                                    }
                                }
                            }

                    }
                }
                catch (Exception ex)
                {

                }
                }

              //Save ViewState
        protected override object SaveViewState()
                {
                    object[] newViewState = new object[3];

                    List<string> txtValues = new List<string>();
                    foreach (Control c in panelNameofParticipants.Controls)
                    {
                        if (c is Table)
                        {
                            foreach (TableRow row in c.Controls)
                            {
                                foreach (TableCell cell in row.Controls)
                                {
                                    if (cell.Controls[0] is TextBox)
                                    {
                                        txtValues.Add(((TextBox)cell.Controls[0]).Text);
                                    }
                                }
                            }
                        }
                    }

                    newViewState[0] = txtValues.ToArray();
                    newViewState[1] = base.SaveViewState();
                    if (ViewState["numberofparticipants"] != null)
                        newViewState[2] = (int)ViewState["numberofparticipants"];
                    else
                        newViewState[2] = 0;
                    return newViewState;
                }
    //Load ViewState

    protected override void LoadViewState(object savedState)
            {
                //if we can identify the custom view state as defined in the override for SaveViewState
                if (savedState is object[] && ((object[])savedState).Length == 3 && ((object[])savedState)[0] is string[])
                {
                    object[] newViewState = (object[])savedState;
                    string[] txtValues = (string[])(newViewState[0]);
                    if (txtValues.Length > 0)
                    {
                        //re-load tables
                        CreateDynamicTable(1, Convert.ToInt32(newViewState[2]));
                        int i = 0;
                        foreach (Control c in panelNameofParticipants.Controls)
                        {
                            if (c is Table)
                            {
                                foreach (TableRow row in c.Controls)
                                {
                                    foreach (TableCell cell in row.Controls)
                                    {
                                        if (cell.Controls[0] is TextBox && i < txtValues.Length)
                                        {
                                            ((TextBox)cell.Controls[0]).Text = txtValues[i++].ToString();

                                        }
                                    }
                                }
                            }
                    }
                    }
                    //load the ViewState normally
                    base.LoadViewState(newViewState[1]);
                }
                else
                {
                    base.LoadViewState(savedState);

                }
            }
//Create Dynamic Control

public void CreateDynamicTable(int rowcount, int columnCount)
        {
            Table tableparticipantName = new Table();

             for (int i = 0; i < rowcount; i++)
                {
                    TableRow row = new TableRow();
                    for (int j = 0; j < columnCount; j++)
                    {
                        TableCell cell = new TableCell();

                        TextBox txtNameofParticipant = new TextBox();
                        txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(j);
                        cell.ID = "cell" + Convert.ToString(j);
                        cell.Controls.Add(txtNameofParticipant);
                        row.Cells.Add(cell);
                    }
                    tableparticipantName.Rows.Add(row);
                    tableparticipantName.EnableViewState = true;
                    ViewState["tableparticipantName"] = true;
        }
             panelNameofParticipants.Controls.Add(tableparticipantName);
        }

Ссылка Ссылка, MSDN Ссылка, Надеюсь, что это поможет.

Ответ 9

При создании текстовых полей убедитесь, что вы установили ClientIDMode Недавно я работал над чем-то похожим. Я динамически создал флажки в строках GridView, и это сработало для меня.

TextBox txtNameofParticipant = new TextBox();
txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
txtNameOfParticipant.ClientIDMode = System.Web.UI.ClientIDMode.Static;

Ответ 10

Динамически добавленные элементы управления должны быть созданы снова при обратной передаче, в противном случае состояние динамически добавленных элементов управления будет потеряно (если элементы управления потеряны, как можно сохранить их старое состояние). Теперь вопрос. Когда загружается viewstated? Он загружается между двумя событиями Page_Init и Load.

Следующие примеры кода представляют собой небольшую модификацию вашего кода для вашего понимания.

Разметка aspx такая же, как ваша, но с некоторыми дополнительными элементами управления

<form id="form1" runat="server">
    <asp:DropDownList ID="drpNoofparticipants" runat="server"  >
        <asp:ListItem>1</asp:ListItem>
        <asp:ListItem>2</asp:ListItem>
        <asp:ListItem>3</asp:ListItem>
        <asp:ListItem>4</asp:ListItem>
        <asp:ListItem>5</asp:ListItem>
        <asp:ListItem>6</asp:ListItem>
        <asp:ListItem>7</asp:ListItem>
        <asp:ListItem>8</asp:ListItem>
        <asp:ListItem>9</asp:ListItem>
        <asp:ListItem>10</asp:ListItem>
    </asp:DropDownList>
    <br /><asp:Button ID="btnCreateTextBoxes" runat="server" OnClick="btnSubmitCountParticipant_Click" Text="Create TextBoxes" />
    <div id="divNameofParticipants" runat="server">
        <asp:Panel ID="panelNameofParticipants" runat="server">
        </asp:Panel>
    </div>
    <div>
        <asp:Button ID="btnSubmitParticipants" runat="server" Text="Submit the Participants" OnClick="BtnSubmitParticipantsClicked" />
    </div>
</form>

В событии клика кнопки btnCreateTextBoxes я создаю элементы управления, используя следующий код

private void CreateTheControlsAgain(int numberofparticipants)
    {


        try
        {
            ViewState["numberofparticipants"] = Convert.ToString(numberofparticipants);
                Table tableparticipantName = new Table();
                int rowcount = 1;
                int columnCount = numberofparticipants;
                for (int i = 0; i < rowcount; i++)
                {

                    for (int j = 0; j < columnCount; j++)
                    {
                        TableRow row = new TableRow();
                        TableCell cell = new TableCell();
                        TextBox txtNameofParticipant = new TextBox();
                        txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(j);
                        cell.ID = "cell" + Convert.ToString(j);
                        cell.Controls.Add(txtNameofParticipant);
                        row.Cells.Add(cell);
                        tableparticipantName.Rows.Add(row);

                    }



                }
                panelNameofParticipants.Controls.Add(tableparticipantName);
            }



        catch (Exception ex)
        {


        }
    }

Как упоминалось выше для поддержания состояния управления, я включил повторное создание элементов управления в событии "Загрузка страницы" на основе viewstate [ "numberofчастников" ]

 protected void Page_Load(object sender, EventArgs e)
    {
        if (ViewState["numberofparticipants"] != null)
        {
            CreateTheControlsAgain(Convert.ToInt32(ViewState["numberofparticipants"]));
            CreateControls();

        }

    }

В момент нажатия кнопки btnSubmitParticipants я написал следующее событие и записал имена участников на консоль

try
        {
            //String test1 = test.Value;
            List<string> listParticipantName = new List<string>();
            if (ViewState["numberofparticipants"] != null)
            {
                int numberofparticipants = Convert.ToInt32(ViewState["numberofparticipants"]);
                for (int i = 0; i < numberofparticipants; i++)
                {
                    string findcontrol = "txtNameofParticipant" + i;
                    var txtParticipantName = panelNameofParticipants.FindControl(string.Format("txtNameofParticipant{0}", i)) as TextBox;
                    listParticipantName.Add(txtParticipantName.Text);

                }
            }
            foreach (var item in listParticipantName)
            {
                Response.Write(string.Format("{0}<br/>", item));
            }
        }
        catch (Exception ex)
        {

        }

Надеюсь, что это поможет

Ответ 11

Я не уверен, что это желательно, но вы добавляете несколько таблиц на свою панель, но я думаю, что вам нужна только одна таблица. Так что эта строка должна быть вне внешнего для цикла так:

for (int i = 0; i < rowcount; i++)
{
     TableRow row = new TableRow();
     for (int j = 0; j < columnCount; j++)
     {
          TableCell cell = new TableCell();
          TextBox txtNameofParticipant = new TextBox();
          txtNameofParticipant.ID = "txtNameofParticipant" + Convert.ToString(i);
          cell.ID = "cell" + Convert.ToString(i);
          cell.Controls.Add(txtNameofParticipant);
          row.Cells.Add(cell);
     }
     tableparticipantName.Rows.Add(row);
}

panelNameofParticipants.Controls.Add(tableparticipantName);

Кроме того, FindControl будет искать только прямые дочерние элементы контейнера, в этом случае он может найти только таблицу, иначе он вернет null. поэтому вам нужно найти дочерние элементы панели, чтобы найти элемент управления, например. ваша таблица:

foreach (TableRow row in tableparticipantName.Rows)
{
    TextBox txtParticipantName = (TextBox)row.FindControl(findcontrol);
    listParticipantName.Add(txtParticipantName.Text);
}

Если это не сработает, то выполнение этого рекурсивно может работать лучше: ASP.NET Есть ли лучший способ найти элементы управления, которые находятся внутри других элементов управления?