如何获取动态填充控件的值

时间:2015-06-16 14:51:57

标签: c# asp.net

我在aspx页面中有一个div Conatining a Panel

<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)
        {

        }
    }

但我无法获得代码隐藏中的值。

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

上面的代码无法找到控件并且它总是给出null 。我做错了什么。我在页面加载中重新创建了控件,因为回发是无状态但仍然没有成功。< / p>

先谢谢

11 个答案:

答案 0 :(得分:7)

您需要在PreInit中创建不在OnLoad中的动态控件。请参阅此处的文档:https://msdn.microsoft.com/en-us/library/ms178472.aspx

重新/在页面加载时创建控件将导致ViewState不被绑定到控件,因为在OnLoad之前发生了viewstate绑定。

答案 1 :(得分:6)

正如其他人所说。要创建动态控件,您需要为每个回发和正确的时间执行此操作。要呈现动态控件,请使用 Preinit事件。我建议您查看https://msdn.microsoft.com/en-us/library/ms178472(v=vs.80).aspx以了解详情。

  

MSDN - PreInit:   将此事件用于以下事项:   检查IsPostBack属性以确定这是否是第一次处理页面。   创建或重新创建动态控件。   动态设置母版页。   动态设置Theme属性。   读取或设置配置文件属性值。   注意注意如果请求是回发,则控件的值尚未从视图状态恢复。如果在此阶段设置控件属性,则可能会在下一个事件中覆盖其值。

下一个有趣的事件是预加载,表明:

  

MSDN - PreLoad   如果需要在Load事件之前对页面或控件执行处理,请使用此事件。   在Page引发此事件后,它会为自身和所有控件加载视图状态,然后处理Request实例中包含的所有回发数据。

意味着在下一个事件中加载(Page_Load)应该加载视图状态,所以在这里你应该能够有效地检查你的值。

您还需要确保启用了视图状态,并且最简单的可能是在页面级指令中:

<%@Page EnableViewState="True" %>

查看文章https://msdn.microsoft.com/en-us/library/ms972976.aspx 2,这篇文章更深入了解所有这些

注意

如果你的问题是你需要在点击按钮上动态创建控件,并且会创建很多控件,你应该转向jQuery ajax并在公共函数上使用属性[WebMethod]在你的代码背后。创建动态控件和维护 ViewState 是非常昂贵的,所以我真的推荐这个,以获得更好的用户体验。

答案 2 :(得分:5)

如果您使用像asp:GridView这样的DataPresentation控件,则会更容易。

标记

<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>

代码隐藏

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

答案 3 :(得分:4)

我认为你正确地这样做了。在asp.net webforms中,很多时候您会遇到正在发生的奇怪事情。特别是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, 
    }
}

答案 4 :(得分:3)

需要在每个回发后重新创建动态控件。在代码中实现这一目标的最简单方法是缓存控制结构并重新填充它。这是怎么做到的:

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)
    {

    }
}

希望这有帮助。

答案 5 :(得分:1)

当页面回发时,动态创建的控件将消失,本文here解释了为什么会发生这种情况。

因此,为了使动态控件能够被asp.net页面识别,你需要在preinit事件处理程序中重新创建它,但我认为这很难,因为你的情况下这个动态控件依赖于其他一些web表单元素,如此阶段还没有下拉列表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事件处理程序中重新创建表。 / p>

希望它有所帮助。

答案 6 :(得分:1)

将您的btnSubmitCountParticipant_Click方法数据放入具有您选择名称的其他函数中。在方法btnSubmitCountParticipant_Click和方法CreateControls()中调用该函数。另外在btnSubmitCountParticipant_Click方法

中剪切粘贴下面的代码
  

int numberofparticipants =   Convert.ToInt32(drpNoofparticipants.SelectedValue);               ViewState [&#34; numberofparticipants&#34;] = numberofparticipants;

。这在我的机器上工作。希望这有帮助

答案 7 :(得分:1)

是的,动态控件在回发中丢失了,所以我们需要在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);
        }

参考Link,MSDN Link,希望它有所帮助。

答案 8 :(得分:1)

创建文本框时,请确保设置ClientIDMode 我最近做过类似的事情。我在GridView行中动态创建了复选框,它对我有用。

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

答案 9 :(得分:1)

  

必须在回发时再次创建动态添加的控件,否则动态添加的控件的状态将丢失(如果控件丢失,则如何保留其旧状态)。现在的问题。何时加载了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按钮的click事件中,我使用以下代码创建控件

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)
        {


        }
    }

如上所述,为了维持控制状态,我包括在页面Load事件中重新创建控件,基于 viewstate [&#34; numberofparticipants&#34;]

 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)
        {

        }

希望这有帮助

答案 10 :(得分:-1)

我不确定是否需要这样,但是你要在面板中添加多个表,但我认为你只需要/需要一个表。所以这一行应该在外部for循环之外,如下所示:

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 Is there a better way to find controls that are within other controls?