Web窗体动态添加UserControl时二次点击出现索引越界问题求助
问题分析与解决
错误原因
- 页面级变量状态丢失:你使用的
nQuestions和nCurrentQuestion是页面级全局变量,ASP.NET每次回发都会重建页面实例,这些变量会被重置为初始值,导致计数逻辑混乱。 - 动态控件未回发重建:ASP.NET不会自动保存动态添加的控件,第二次回发时
phQuestion.Controls集合里没有之前添加的控件,你的索引计算和实际集合数量不匹配,触发越界错误。 - 索引查找不必要:添加控件后直接用创建的
pnl对象访问子控件即可,没必要通过Controls索引查找,增加出错风险。
修复代码
1. 改用ViewState保存计数
把页面级变量替换为ViewState存储,确保回发时状态保留:
Private Property nQuestions As Integer Get If ViewState("nQuestions") Is Nothing Then Return 0 Else Return CInt(ViewState("nQuestions")) End If End Get Set(value As Integer) ViewState("nQuestions") = value End Set End Property Private Property nCurrentQuestion As Integer Get If ViewState("nCurrentQuestion") Is Nothing Then Return 0 Else Return CInt(ViewState("nCurrentQuestion")) End If End Get Set(value As Integer) ViewState("nCurrentQuestion") = value End Set End Property
2. 回发时重建动态控件
在Page_Init事件中重新创建所有已添加的UserControl,确保控件树结构正确:
Protected Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init ' 重建所有动态添加的QControl For i As Integer = 0 To nQuestions - 1 Dim pnl As QControl = LoadControl("~\userControls\QControl.ascx") pnl.ID = "p" & i.ToString phQuestion.Controls.Add(pnl) Next End Sub
3. 修改AddQuestion方法
直接使用创建的控件对象访问子控件,避免索引查找:
Private Sub AddQuestion() nQuestions += 1 nCurrentQuestion = nQuestions Dim ndex As Integer = nCurrentQuestion - 1 Dim pnl As QControl = LoadControl("~\userControls\QControl.ascx") pnl.ID = "p" & ndex.ToString phQuestion.Controls.Add(pnl) ' 直接用pnl访问子控件,无需通过Controls索引 Dim txtQuestion As TextBox = DirectCast(pnl.FindControl("txtQuestion"), TextBox) txtQuestion?.Focus() End Sub
关键说明
- ViewState是ASP.NET中保存页面状态的标准方式,适合存储这类页面级的计数信息。
- 动态控件必须在
Page_Init或Page_Load早期重建,否则会丢失视图状态和事件绑定。 - 直接使用创建的控件对象访问子控件,比通过Controls集合索引更可靠,避免因控件集合变化导致的索引错误。
内容的提问来源于stack exchange,提问作者JNEW
相关产品推荐
相关产品推荐

