如何遍历DataTable并添加可回传数据的服务器端TextBox/TextArea
解决ASP.NET动态生成能回传数据的TextBox/TextArea问题
为啥之前的方法拿不到值
你直接拼接HTML生成的<textarea>是纯客户端控件,没有加runat="server"属性,ASP.NET不会将其纳入服务器控件生命周期管理,回传时自然无法获取到输入值。
方案一:动态添加服务器端控件(最靠谱)
别再靠拼接HTML字符串生成控件,直接在后台创建ASP.NET服务器控件实例,添加到页面的容器控件中,这样控件会被ASP.NET完整管理,回传时能稳定获取输入值。
步骤:
- 在ascx页面添加一个
PlaceHolder作为动态控件的容器(必须是服务器控件):
<asp:PlaceHolder ID="phControls" runat="server"></asp:PlaceHolder>
- 后台代码遍历DataTable,创建控件并添加到容器:
protected void Page_Load(object sender, EventArgs e) { Guid itemGUID = new Guid("你的目标ID"); // 无论是否回传,都要重新创建控件,否则ASP.NET无法识别原有控件 LoadDynamicControls(itemGUID); } private void LoadDynamicControls(Guid ItemGUID) { DataTable dt = new DataTable(); // 这里写你的数据获取逻辑,从数据库填充DataTable foreach (DataRow dr in dt.Rows) { // 创建包裹标题和输入框的div HtmlGenericControl div = new HtmlGenericControl("div"); // 添加标题元素 HtmlGenericControl h3 = new HtmlGenericControl("h3"); h3.InnerText = dr["Name"].ToString(); div.Controls.Add(h3); // 创建服务器端TextArea(用TextBox控件,设置TextMode为MultiLine) TextBox txtArea = new TextBox(); txtArea.ID = "txt_" + dr["ItemGUID"].ToString(); // 设置唯一ID关联数据行 txtArea.TextMode = TextBoxMode.MultiLine; txtArea.MaxLength = 1000; txtArea.Style["width"] = "90%"; txtArea.Style["height"] = "150px"; // 如有默认值,直接从DataRow中赋值 txtArea.Text = dr["DefaultContent"]?.ToString() ?? ""; div.Controls.Add(new LiteralControl("<br />")); div.Controls.Add(txtArea); div.Controls.Add(new LiteralControl("<br />")); // 将组装好的div添加到PlaceHolder phControls.Controls.Add(div); } }
- 回传时获取输入值:
// 示例:提交按钮点击事件中获取所有输入值 protected void btnSubmit_Click(object sender, EventArgs e) { foreach (Control ctrl in phControls.Controls) { if (ctrl is HtmlGenericControl div && div.HasControls()) { foreach (Control childCtrl in div.Controls) { if (childCtrl is TextBox txt && txt.ID.StartsWith("txt_")) { string inputValue = txt.Text; string itemGUID = txt.ID.Replace("txt_", ""); // 这里处理获取到的值,比如存入数据库 } } } } }
划重点:动态创建的服务器控件必须在每次页面加载(包括回传)时重新创建,且ID要和第一次创建时完全一致,否则ASP.NET无法恢复控件状态和输入值。
方案二:临时快速解决方法
如果不想大幅修改现有代码,可以尝试以下两种方式,但稳定性和可维护性不如方案一。
方式1:给HTML控件加runat="server"
拼接HTML时给textarea加上runat="server",同时确保div_contents本身是服务器控件(带runat="server"属性):
content += "<br /><textarea runat=\"server\" ID=\"txt_" + dr["ItemGUID"].ToString() + "\" MaxLength=\"1000\" style=\"width:90%; height:150px\"></textarea><br />";
后端通过FindControl获取控件值:
TextBox txt = div_contents.FindControl("txt_xxxx") as TextBox; if (txt != null) { string value = txt.Text; }
缺点:回传时可能因控件树重建问题导致无法获取值,稳定性差。
方式2:通过Request.Form直接获取值
不给控件加runat="server",但添加name属性,回传时通过表单提交的键值对直接获取:
content += "<br /><textarea name=\"txt_" + dr["ItemGUID"].ToString() + "\" MaxLength=\"1000\" style=\"width:90%; height:150px\"></textarea><br />";
后端取值:
string value = Request.Form["txt_xxxx"];
优点:实现简单,无需依赖服务器控件生命周期;缺点:无法利用ASP.NET的控件状态管理,默认值回显等逻辑需自行处理。
总结
优先选择方案一,虽然需要调整现有代码结构,但最稳定可靠,符合ASP.NET的开发规范。方案二适合临时快速解决小需求,但长期维护容易出现问题。
内容的提问来源于stack exchange,提问作者dwewers
相关产品推荐
相关产品推荐

