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

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

我使用以下代码从代码隐藏动态填充面板:

 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 listParticipantName = new List(); 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 。我做错了。我在页面加载中重新创建了控件,因为回发是无状态但仍然没有成功。

提前致谢

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

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

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

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

下一个有趣的事件是Preload ,它指出:

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

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

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

 <%@Page EnableViewState="True" %> 

看看文章https://msdn.microsoft.com/en-us/library/ms972976.aspx 2 ,它更深入地介绍了这一切

注意

如果您的问题是需要在单击按钮时动态创建控件,并且将创建许多控件,您应该转向jQuery ajax并在代码后面的公共函数上使用属性[WebMethod] 。 创建动态控件和维护ViewState非常昂贵,所以我真的建议这样做,以获得更好的用户体验。

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

标记

           

代码隐藏

 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() .Select(row => ((TextBox)row.FindControl("txtNameofParticipant")).Text) .ToList(); } catch (Exception ex) { } } 

我认为你正确地做到了这一点。 在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 listParticipantName = new List(); //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, } } 

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

 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 listParticipantName = new List(); 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) { } } 

希望这可以帮助。

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

因此,为了使动态控件能够被asp.net页面识别,您需要在preinit事件处理程序中重新创建它,但我认为这很难,因为您的案例中的动态控件依赖于其他一些Web表单元素,例如下拉列表drpNoofparticipants此阶段还没有ViewState。

我的建议是我们以不同的方式进行,每个post实际上都是一个表单post,因此您可以通过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事件处理程序中重新创建表。

希望能帮助到你。

将您的btnSubmitCountParticipant_Click方法数据放入具有您选择名称的其他函数中。 在方法btnSubmitCountParticipant_Click和方法CreateControls()中调用该函数。 另外在btnSubmitCountParticipant_Click方法中剪切粘贴下面的代码

int numberofparticipants = Convert.ToInt32(drpNoofparticipants.SelectedValue); ViewState [“numberofparticipants”] =参与者数量;

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

是的,动态控件在回发中丢失,所以我们需要在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 listParticipantName = new List(); 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 txtValues = new List(); 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 链接 ,希望它有所帮助。

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

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

必须在回发时再次创建动态添加的控件,否则动态添加的控件的状态将丢失(如果控件丢失,则如何保留其旧状态)。 现在的问题。 何时加载了viewstated? 它加载在两个事件Page_Init和Load之间。

以下代码示例对您的代码进行了一些修改,以便您理解

aspx标记与您的相同,但有一些额外的控件

 
1 2 3 4 5 6 7 8 9 10

在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 [“numberofparticipants”]

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

在btnSubmitParticipants按钮的click事件中,我编写了以下事件并将参与者名称写入控制台

 try { //String test1 = test.Value; List listParticipantName = new List(); 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}
", item)); } } catch (Exception ex) { }

希望这可以帮助

我不确定是否需要这个,但是你要在面板中添加多个表,但我认为你只需要/需要一个表。 所以这一行应该在外部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是否有更好的方法来查找其他控件中的控件?