我在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>
先谢谢
答案 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);
}
答案 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?