【问题标题】:Dynamically created TextBoxes in a Table lost Text value表格中动态创建的文本框丢失了文本值
【发布时间】:2017-01-29 14:58:25
【问题描述】:

我有一个动态生成的表格,在 2 列内有文本框。在回发期间,即使我填充它们,文本框也总是空的。 该表是这样构建的:

  protected void ddlScalaTaglie_SelectedIndexChanged(object sender, EventArgs e)
    {
        DataTable dtRighe = oTab.getScaleTaglieRighe(ddlScalaTaglie.SelectedValue);

        //dt is datatable object which holds DB results.
        Table tbl = new Table();
        tbl.CssClass = "table table-striped  table-bordered table-responsive";

        TableRow tr;
        TableCell tcEU, tcUS, tcUK, tcQty, tcEAN;
        Label lbEU, lbUS, lbUK, lbQty, lbEAN;
        TextBox tbEU, tbUS, tbUK, tbQty, tbEAN, tbToFocus = null;

        foreach (DataRow dr in dtRighe.Rows)
        {
            tr = new TableRow();

            //ean
            tcEAN = new TableCell();
            tbEAN = new TextBox();
            tbEAN.ID = "txtEAN" + dr[0].ToString();
            tbEAN.Width = new Unit(100, UnitType.Percentage);
            tbEAN.Columns = 15;
            tcEAN.Controls.Add(tbEAN); 
            tr.Controls.Add(tcEAN);

            //Qty
            tcQty = new TableCell();
            tbQty = new TextBox(); 
            tbQty.ID = "txtQty" + dr[0].ToString(); 
            tbQty.TextMode = TextBoxMode.Number; 
            tcQty.Controls.Add(tbQty);
            tr.Controls.Add(tcQty);            

            tbl.Controls.Add(tr);
        }

        Session["tbl"] = tbl;

        divTaglieRighe.Controls.Add(tbl);
    }

当我点击 SAVE 按钮时,我必须遍历我的表格并保存所有 TextBox.Text...

这是我写的:

 ArrayList arrScarpaFigli = new ArrayList();
 Table tbl = (Table)Session["tbl"];
 foreach (TableRow row in tbl.Rows)
 {
     foreach (TableCell cell in row.Cells)
     {
        foreach (Control ctrl in cell.Controls)
        {
           //CONTROL IS TEXBOXT: EXTRACT VALUES//
            if (ctrl is TextBox)
            {
                TextBox txt = (TextBox)ctrl;
                arrScarpaFigli.Add(txt.Text);
             }
         }
      }
  }

问题是,如果我填充文本框,在我的文本中总是有一个空字符串。 我填表的唯一时刻是在下拉菜单的 selectionChange 上。

我做错了什么? 提前致谢

【问题讨论】:

  • 也许this 的帖子可以解决你的问题。
  • 我动态设置ID
  • 您必须在 PostBack 上保留动态创建的控件的 ViewState。查看this article 了解更多信息。
  • @M.E.我看一下您发布的解决方案,但这不是我需要的方法。我有一个动态生成的表格,在 2 列内有文本框
  • @Martina 这里的问题是您在使用动态控件时没有使其工作所需的背景知识。就像许多其他人所写的那样,您必须在下一篇文章中重新创建控件才能使其正常工作。幸运的是,有现成的 Asp.Net 控件可供您使用:GridViewListViewRepeater 等。将它们与数据绑定一起使用,您不必使用动态创建的控件。

标签: c# asp.net textbox


【解决方案1】:

您必须在每次页面加载时重新创建动态控件,以确保在 PostBack 之后保留它们的值。所以你需要创建一个新的 Method 来处理每次页面加载时 Table 的创建。

protected void Page_Load(object sender, EventArgs e)
{
    //always create the controls on every page load if there is a value selected in ddlScalaTaglie
    if (!string.IsNullOrEmpty(ddlScalaTaglie.SelectedValue))
    {
        createTable(ddlScalaTaglie.SelectedValue);
    }
}

protected void Button1_Click(object sender, EventArgs e)
{
    //use findcontrol to find the Table inside the placeholder
    Table tbl = Page.FindControl("divTaglieRighe").FindControl("Table1") as Table;

    //loop all rows and cells in the Table
    foreach (TableRow row in tbl.Rows)
    {
        foreach (TableCell cell in row.Cells)
        {
            foreach (Control ctrl in cell.Controls)
            {
                //the control is a textbox
                if (ctrl is TextBox)
                {
                    //cast the control back to a textbox
                    TextBox tb = ctrl as TextBox;

                    //does the checkbox have a value, if so append the label
                    if (!string.IsNullOrEmpty(tb.Text))
                    {
                        Label1.Text += tb.Text + "<br>";
                    }
                }
            }
        }
    }

}

protected void ddlScalaTaglie_SelectedIndexChanged(object sender, EventArgs e)
{
    //no need to create the Table dynamically, that will be handled in Page_Load
    //this method is just a dummy to trigger a PostBack

    //you could remove this method and the OnSelectedIndexChanged from the DropDown
    //and just keep the AutoPostBack="true", that will also work
}

private void createTable(string value)
{
    DataTable dtRighe = Common.LoadFromDB();

    //create a new table WITH id, that is needed for findcontrol
    Table tbl = new Table();
    tbl.ID = "Table1";

    //loop all rows in the datatable
    foreach (DataRow dr in dtRighe.Rows)
    {
        TableRow tr = new TableRow();

        //ean
        TableCell tcEAN = new TableCell();
        TextBox tbEAN = new TextBox();
        tbEAN.ID = "txtEAN" + dr[0].ToString();
        tbEAN.Width = new Unit(100, UnitType.Percentage);
        tbEAN.Columns = 15;
        tcEAN.Controls.Add(tbEAN);
        tr.Controls.Add(tcEAN);

        //Qty
        TableCell tcQty = new TableCell();
        TextBox tbQty = new TextBox();
        tbQty.ID = "txtQty" + dr[0].ToString();
        tbQty.TextMode = TextBoxMode.Number;
        tcQty.Controls.Add(tbQty);
        tr.Controls.Add(tcQty);

        tbl.Controls.Add(tr);
    }

    //add the table to the placeholder
    divTaglieRighe.Controls.Add(tbl);
}

使示例完整的aspx

<asp:DropDownList ID="ddlScalaTaglie" runat="server" OnSelectedIndexChanged="ddlScalaTaglie_SelectedIndexChanged" AutoPostBack="true">
    <asp:ListItem Text="Select..." Value=""></asp:ListItem>
    <asp:ListItem Text="Option 1" Value="1"></asp:ListItem>
    <asp:ListItem Text="Option 2" Value="2"></asp:ListItem>
</asp:DropDownList>
<br />
<br />
<asp:PlaceHolder ID="divTaglieRighe" runat="server"></asp:PlaceHolder>
<br />
<br />
<asp:Button ID="Button1" runat="server" Text="Save" OnClick="Button1_Click" />
<br />
<br />
<asp:Label ID="Label1" runat="server" Text=""></asp:Label>

【讨论】:

  • 谢谢,今晚我会试试的,我会告诉你的!!
【解决方案2】:

Session 中存储Table 控件的实例是一个糟糕的想法,而且完全是错误的。控件属于它们的父页面 - 它们应该在创建后立即添加到其中,并且它们应该与它们的父页面一起消失。

在 ASP.NET 中动态创建控件的问题在于,您必须存储它们已创建事实的指示符(连同再次创建它们所需的相关信息)并在所有后续回发时重新创建它们 - 不迟于在Page_Load。只有这样,这些控件才有机会从Request 中获取它们的值,您才有机会从控件中获取这些值。

在您的代码中,存储在Session 中的Table 实例(连同它的所有行、单元格和文本框)永远不会反映任何客户端数据更改,也不属于Pages被创建来处理后续的回发请求。

更新

这里要理解的一个重要事实是,在处理了ddlScalaTaglie变化引起的回发并将hew html返回给客户端之后,页面实例就消失了。在下一次请求时,您的页面的一个新实例被创建 - 它不知道前一个实例已将表添加到其控制树中这一事实。是您在Page_Load 中的代码必须发现表单必须具有此表,并以与第一次创建时完全相同的方式创建表——行、单元格和文本框与IDs 完全相同。

然后,在您将这个新创建的表添加到 divTaglieRighe.Controls 后,文本框将能够从 Request.Form 集合中提取它们的客户端值。

【讨论】:

  • 但我无法在 Page_Load 上重新创建控件...我必须在下拉列表项更改后创建表,因为我从数据库中读取数据。如果在 Page_Load 我重新创建我的表,我会再次丢失用户输入,对吗?
  • 不,这里要理解的重要一点是,在处理了ddlScalaTaglie变化引起的回发并将hew html返回给客户端之后,页面实例就消失了。在下一次请求时,您的页面的一个新实例被创建 - 它不知道前一个实例添加了表这一事实。您在Page_Load 中的代码必须发现表单必须具有此表,并以与第一次创建时完全相同的方式创建表 - 行、单元格和文本框具有完全相同的IDs .
  • 然后,将这个新创建的表添加到divTaglieRighe.Controls 后,文本框将能够从Request.Form 集合中提取它们的客户端值。
【解决方案3】:

确保文本框有一个“名称”,以便发回控制器。 如果没有,它会为参数获取 null。

检查 Request.Form 以获取返回给控制器的数据。

【讨论】:

    【解决方案4】:

    您创建了一个名为tbl 的表格并添加了两个TextBox,然后您将表格控件存储在会话Session["tbl"] 中并添加到divTaglieRighe 控件中。最后,您尝试从会话 Session["tbl"] 表中获取 TextBox 数据,而不是在 divTaglieRighe 控件中添加的 ViewState 控件。您必须从 divTaglieRighe 控件中添加的 Table tbl 控件中获取数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-08
      • 1970-01-01
      • 1970-01-01
      • 2013-09-27
      • 1970-01-01
      相关资源
      最近更新 更多