2011-03-20 5 views
2

동적으로 컨트롤을 웹 양식에 삽입하는 프로그램을 작성하고 있습니다. 변수에 따라 텍스트 상자, 라디오 단추 집합 또는 체크 상자 집합을 추가합니다. 나중에 사용자가 제출 단추를 클릭 한 후 컨트롤을 사용하여 사용자가 올바른 대답을 제출하는지 확인해야하지만 컨트롤의 ID를 참조하려고하면 "txtAnser가 선언되지 않습니다. 액세스 할 수 없습니다. 때문에 그것은 보호 수준의 여기 VB에서 asp.net 3.5에서 동적으로 생성 된 컨트롤을 참조하는 방법

가 .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 

누구든지 내가해야 할 일을 지적 할 수 있으면 감사하게 생각합니다.

덕분에, 사이먼

답변

1

당신은 동적 컨트롤에 대한 참조를 얻기 위해 자리에 재귀의 FindControl을해야 할 것입니다. 당신이를 Page_Load에 (다시 게시 또는되지 않음) 컨트롤을 생성하고,이

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 
+0

ㅎ ... 멋지다. :) – Kon

+0

감사합니다. 훌륭한 게시물이었고 도움이되었습니다. – Simon

1

먼저 전화를 시도, 너무 제출 버튼을 클릭하기 전에 txtAnswer의 어떤 상태가되었다, 이제 사라졌습니다. txtAnswer가 초기 상태로 다시 생성되었습니다. IsPostBack이 false 인 경우에만 컨트롤을 동적으로 렌더링해야합니다.

둘째, Is Not Nothing if 문 블록에서 txtAnswer의 Text 속성에 액세스해야합니다. 그렇지 않으면 null 참조 예외가 발생할 수 있습니다.

세 번째로 TextBox 컨트롤에 대한 참조를 얻으려면 다음과 같은 식으로 해당 자리 표시 자 내의 ID로 컨트롤을 찾으려고 할 수 있습니다 (C#에서이 작업을 수행하고 있습니다 - 사용자가 직접 VB로 번역 할 수 있음).

재귀 적으로 제어를 찾기 위해 함수를 정의 :

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"); 

없음 실제로 테스트되지

을, 그래서 그것이 작동하지 않으면 나에게 소리 지리지 마십시오. 이것은 단지 지침 일뿐입니다.

+0

감사합니다. 나는 꽤 새롭기 때문에 때로는 전체 페이지 수명주기를 엉망으로 만들고 나중에 수정해야합니다. – Simon

+0

모두 시작했습니다. 한 명은 전문가의 맘마미에서 튀어 나왔습니다. :) – Kon