如何用VB在asp.net 3.5中引用动态创建的控件

时间:2011-03-20 14:14:07

标签: asp.net vb.net dynamic-controls

我正在编写一个程序,可以动态地将控件插入到webform中。根据变量,我添加一个文本框,一组单选按钮或一组复选框。之后,在用户单击提交按钮后,我需要使用控件来确定用户是否正在提交正确的答案,但是当我尝试引用控件的id时,我得到“txtAnser未声明。它可能无法访问由于它的保护水平。

这是.aspx页面(它是母版页的标准内容页面):

<%@ Page Title="" Language="VB" MasterPageFile="~/top.master" AutoEventWireup="false" 
CodeFile="test_page.aspx.vb" Inherits="Default2" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="PageContent" Runat="Server">
    <asp:SqlDataSource ID="sdsQuestionPuller" runat="server" 
    ConnectionString="<%$ ConnectionStrings:SchoolhouseConnectionString6 %>" 
    SelectCommand="SELECT QuestionText, AnswerType, PossibleAnswers,    CorrectAnswers        
    FROM Questions WHERE (SubjectID = @SubjectID) AND (QuestionOrder = @QuestionOrder)">
    <SelectParameters>
        <asp:SessionParameter Name="SubjectID" SessionField="SubjectID" />
        <asp:SessionParameter Name="QuestionOrder" SessionField="PageNumber" />
    </SelectParameters>
</asp:SqlDataSource>
    <asp:SqlDataSource ID="sdsMaxQuestions" runat="server" 
        ConnectionString="<%$ ConnectionStrings:SchoolhouseConnectionString7 %>" 
        SelectCommand="SELECT MAX(QuestionOrder) AS LastQuestion FROM Questions GROUP     BY SubjectID HAVING (SubjectID = @SubjectID)">
        <SelectParameters>
            <asp:SessionParameter Name="SubjectID" SessionField="SubjectID" />
        </SelectParameters>
    </asp:SqlDataSource>
<div>
    <asp:Label ID="lblInstructionHolder" runat="server"></asp:Label>
</div>
<div>
    <asp:Label ID="lblQuestionHolder" runat="server"></asp:Label>
</div>
    <asp:PlaceHolder ID="plhQuestionHolder" runat="server"></asp:PlaceHolder>
<div>
    <asp:Button ID="btnSubmit" Text="Submit" runat="server" />
</div>
</asp:Content>

这是后面的代码,我在提交按钮单击事件中遇到问题,我尝试在select case语句中引用txtAnswer控件:

Imports System.Data

Partial Class Default2
    Inherits System.Web.UI.Page

    Dim intMaxPage As Integer
    'QuestionText, AnswerType, PossibleAnswers, CorrectAnswers
    Dim strQuestion As String
    Dim strQuestionType As String
    Dim astrPossibleAnswers() As String
    Dim intNumberOfPossAnswers As Integer
    Dim astrCorrectAnswers() As String
    Dim intNumberOfCorrectAnswers As Integer

    Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init

    End Sub

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Load up the variables(make sure data is retrieved, create a view from the source, retrieve the only row, assing the item(s) from the row to variables)
        sdsMaxQuestions.DataBind()
        Dim dtvLastPageView As DataView = CType(sdsMaxQuestions.Select(DataSourceSelectArguments.Empty), DataView)
        Dim dtrLastPageRow As DataRowView = dtvLastPageView.Item(0)
        intMaxPage = CInt(Trim(dtrLastPageRow.Item(0).ToString))

        Dim dtvQuestionsView As DataView = CType(sdsQuestionPuller.Select(DataSourceSelectArguments.Empty), DataView)
        Dim dtrQuestionsRow As DataRowView = dtvQuestionsView.Item(0)
        strQuestion = Trim(dtrQuestionsRow.Item(0).ToString)
        strQuestionType = Trim(dtrQuestionsRow.Item(1).ToString)
        astrPossibleAnswers = Split(Trim(dtrQuestionsRow.Item(2).ToString), ";")
        intNumberOfPossAnswers = astrPossibleAnswers.Count
        astrCorrectAnswers = Split(Trim(dtrQuestionsRow.Item(3).ToString), ";")
        intNumberOfCorrectAnswers = astrCorrectAnswers.Count

        'Finish loading controls
        lblQuestionHolder.Text = strQuestion
        Select Case strQuestionType
            Case "checkbox"
                lblInstructionHolder.Text = "Choose the correct answer(s)."
            Case "radio"
                lblInstructionHolder.Text = "Choose the best answer."
            Case "fillintheblank"
                lblInstructionHolder.Text = "Please fill in the blank, case doesn't count, spelling does."
            Case Else
                lblInstructionHolder.Text = "Somethings wrong, contact admin"
        End Select

        'Generate the controls for answers...
        GenerateControls()

    End Sub

    Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmit.Click
        'Declare the variables, get any existing values, then check to see if the answer is correct, display a message and go to the next page or store the score.
        Dim intNumberRight As Integer = 0
        Dim intNumberTotal As Integer = 0

        If Not (Session("NumberRight") = Nothing) Then
            intNumberRight = CInt(Session("NumberRight"))
        End If
        If Not (Session("NumberTotal") = Nothing) Then
            intNumberTotal = CInt(Session("NumberTotal"))
        End If

        Select Case strQuestionType
            Case "checkbox"

            Case "radio"

            Case "fillintheblank"
                'Here is where I am having issues
                If txtAnswer Is Not Nothing Then

                End If
                If txtAnswer.text.ToLower = astrCorrectAnswers(0).ToLower Then

                End If
            Case Else
                MsgBox("Somethings wrong, contact admin")
        End Select

        If intMaxPage = CType(Session("PageNumber"), Integer) Then
            Response.Redirect("user_landing.aspx")
        Else
            Session("PageNumber") = CType(Session("PageNumber"), Integer) + 1
            Response.Redirect("test_page.aspx")
        End If
    End Sub

    Private Sub GenerateControls()
        'Make the correct controls depending on the type
        Dim conDivHolder As HtmlGenericControl = New HtmlGenericControl("div")

        Select Case strQuestionType
            Case "checkbox"
                For i As Integer = 0 To intNumberOfPossAnswers - 1
                    Dim chkAnswer As CheckBox = New CheckBox
                    With chkAnswer
                        .ID = "chkAnswer" + i.ToString
                        .Text = astrPossibleAnswers(i)
                    End With
                    conDivHolder.Controls.Add(chkAnswer)
                Next

            Case "radio"
                For i As Integer = 0 To intNumberOfPossAnswers - 1
                    Dim rdoAnswer As RadioButton = New RadioButton
                    With rdoAnswer
                        .ID = "rdoAnswer" + i.ToString
                        .Text = astrPossibleAnswers(i)
                        .GroupName = "rdoGroup"
                    End With
                    conDivHolder.Controls.Add(rdoAnswer)
                Next

            Case "fillintheblank"
                Dim txtAnswer As TextBox = New TextBox
                txtAnswer.ID = "txtAnswer"
                conDivHolder.Controls.Add(txtAnswer)

            Case Else
                Dim lblOops As Label = New Label
                lblOops.Text = "Oops, contact admin"
                conDivHolder.Controls.Add(lblOops)
        End Select

        plhQuestionHolder.Controls.Add(conDivHolder)
    End Sub

End Class

如果有人能够指出我需要做什么,我将不胜感激。

谢谢, 西蒙

2 个答案:

答案 0 :(得分:1)

您将不得不在占位符上执行递归FindControl以获取对动态控件的引用。试试这个

Public Shared Function FindChildControl(start As Control, id As String) As Control
    If start IsNot Nothing Then
        Dim foundControl As Control
        foundControl = start.FindControl(id)

        If foundControl IsNot Nothing Then
            Return foundControl
        End If

        For Each c As Control In start.Controls
            foundControl = FindChildControl(c, id)
            If foundControl IsNot Nothing Then
                Return foundControl
            End If
        Next
    End If
    Return Nothing
End Function

并致电

txtAnswer = FindChildControl(plhQuestionHolder, "txtAnswer")
If txtAnswer Is Not Nothing Then

End If

答案 1 :(得分:1)

首先,你在Page_Load(PostBack与否)上生成你的控件,所以无论txtAnswer的状态是什么,在点击提交按钮之前,它已经消失 - txtAnswer已经以初始状态再次重新生成。仅当IsPostBack为false时,才应动态呈现控件。

其次,您可能应该在Is Not Nothing if语句块中访问txtAnswer的Text属性。否则,您可能会得到一个空引用异常。

第三,为了获得对TextBox控件的引用,你可以尝试在其占位符中通过ID找到控件,使用类似的东西(我在C#中这样做 - 你可以自己翻译成VB):< / p>

定义函数以递归方式查找控件:

protected Control FindControl(Control parent, string controlID)
{
  Control control = parent.FindControlByID("controlID");

  if (control != null) 
  {
    return control;
  }

  foreach(Control child in control.Controls)
  {
    Control childControl = FindControl(child , controlID);

    if (childControl != null) 
    {
      return childControl;
    }
  }

  return null;
}

调用递归查找函数:

Control ctrl = FindControl(plhQuestionHolder, "txtAnswer");

这些代码都没有经过实际测试,所以如果它不能正常工作,请不要对我大喊大叫。这只是一个指南。