0

In a legacy ASP.NET Webforms app, I need to update a database table when the user clicks a button, depending on which checkboxes on the form are checked, using the value from a corresponding label to make the update.

It's not working; however, almost-identical code in a Winforms "test" app does work.

The FormLoad (Winforms) and Page_Load (Webforms) code works fine; there is no need to show all of that code; they both populate the form/page with pairs of label/checkbox controls.

To show how they differ one from the other, though: When the controls are dynamically created, they assign either a Tag value (Winforms) or ID (Webforms) string value (more on that below).

In the working (Winforms) code, it is done this way:

Dim lblCompanyName = New Label()
lblCompanyName.Tag = i.ToString()
lblCompanyName.Text = reader.Item(0).ToString()
Me.Controls.Add(lblCompanyName)

Dim ckbx = New CheckBox()
ckbx.Tag = i.ToString()
ckbx.Checked = True
Me.Controls.Add(ckbx)

In the nonworking (Webforms) code, it is done this way:

Dim coName = New Label()
' Must prepend with something, as controls cannot share the same ID
coName.ID = "lbl" + i.ToString()
coName.Text = categoryDT.Rows(i)(0).ToString()
formCustCatMaint.Controls.Add(coName)

Dim chk = New CheckBox()
chk.ID = "ckbx" + i.ToString()
chk.Checked = True
formCustCatMaint.Controls.Add(chk)

Besides the Form/Page load code, there are just three other blocks of code: a button click event handler, and two utility methods called by that handler.

The code in the Winforms app, which uses .NET Framework 4.5, works (updates the database table when the button is clicked); the code in the Webforms app, which uses .NET Framework 2, does not update the database table as it should - yet shows no err page, just sweetly grins and lazily rests on its laurels.

The only real difference I can see in the code between the two is that in one case (the Winforms app), the dynamically created controls' Tag property is assigned a value, whereas in the other (the Webforms site), the dynamically created controls' ID property is what is assigned. BTW, neither technology seem to have the other property available (Winforms can't seem to access an ID property for a control, and Webforms can't seem to access a Tag property for a control).

A related difference is that no two controls can have the same ID (Webforms); thus, I have to prepend "lbl" to the Label control IDs and "ckbx" to the Checkbox control IDs (each pair shares the same number, so that "lbl1" and "ckbx1" are a matched pair, "lbl42" and "ckbx42" are a matched pair, etc.).

Why does the almost-identical code in the Webforms app fail to update the database?

Here is the working (Winforms/.NET 4.5) code for those three code blocks:

Private Sub Button1_Click( sender As Object,  e As EventArgs) Handles Button1.Click
        Dim connStr As String = "SERVER=PLATYPUS42;DATABASE=duckbilldata;UID=schnozz;PWD=pondscum"
        Dim upd8DML As String = "UPDATE CustomerCategoryLog SET Category = 'Exploding' WHERE Unit = @Unit And MemberNo = @MemberNo AND Custno = @CustNo"

        Dim coName As String
        Dim argVals(2) As String
        Dim _Unit As String
        Dim _MemberNo As String
        Dim _CustNo As String
        Dim curTagVal As String

        For Each cntrl As Control In Me.Controls
                If TypeOf cntrl Is CheckBox Then
                    If DirectCast(cntrl, CheckBox).Checked = True Then
                        curTagVal = CStr(DirectCast(cntrl, CheckBox).Tag)
                        coName = GetLabelTextForTag(curTagVal)
                        argVals = GetArgValsForCompanyName(coName)
                        _Unit = argVals(0)
                        _MemberNo = argVals(1)
                        _CustNo = argVals(2)
                        Using conn As New SqlConnection(connStr), _
                            cmd As New SqlCommand(upd8DML, conn)
                            cmd.Parameters.Add("@Unit", SqlDbType.VarChar, 50).Value = _Unit
                            cmd.Parameters.Add("@MemberNo", SqlDbType.VarChar, 50).Value = _MemberNo
                            cmd.Parameters.Add("@CustNo", SqlDbType.VarChar, 50).Value = _CustNo
                            conn.Open
                            cmd.ExecuteScalar()
                        End Using
                    End If
                End If
            Next
End Sub

    Protected Function GetLabelTextForTag(tagVal As String) As String
        Dim CoName As String = ""

        For Each cntrl As Control In Me.Controls
            If TypeOf cntrl Is Label Then
                If DirectCast(cntrl, Label).Tag.ToString() = tagVal Then
                    CoName = DirectCast(cntrl, Label).Text
                    Exit For
                End If
            End If
        Next
        Return CoName
    End Function

    Protected Function GetArgValsForCompanyName(coName As String) As String()
        Dim args(2) As String

        Using con As New SqlConnection("SERVER=PLATYPUS42;DATABASE=duckbilldata;UID=schnozz;PWD=pondscum"),
              cmd As New SqlCommand("select Unit, MemberNo, CustNo from Customers WHERE CompanyName = @CoName", con)

            con.Open()

            cmd.CommandType = CommandType.Text
            cmd.Parameters.Add("@CoName", SqlDbType.VarChar, 50).Value = coName

            Using reader As SqlDataReader = cmd.ExecuteReader

                While reader.Read
                    args(0) = reader.Item(0).ToString()
                    args(1) = reader.Item(1).ToString()
                    args(2) = reader.Item(2).ToString()
                End While

            End Using

        End Using

        Return args
    End Function

...and here is the nonworking (Webforms/.NET 2.0) code for the corresponding code blocks there:

Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim connStr As String = "SERVER=PLATYPUS42;DATABASE=duckbilldata;UID=schnozz;PWD=pondscum"
    Dim upd8DML As String = "UPDATE CustomerCategoryLog SET Category = 'Exploding' WHERE Unit = @Unit And MemberNo = @MemberNo AND Custno = @CustNo"

    Dim coName As String
    Dim argVals(2) As String
    Dim _Unit As String
    Dim _MemberNo As String
    Dim _CustNo As String
    Dim curCheckboxIDVal As String

    For Each cntrl As Control In Me.Controls
            If TypeOf cntrl Is CheckBox Then
                If DirectCast(cntrl, CheckBox).Checked = True Then
                    curCheckboxIDVal = CStr(DirectCast(cntrl, CheckBox).ID)
                    coName = GetLabelTextForID(curCheckboxIDVal)
                    argVals = GetArgValsForCompanyName(coName)
                    _Unit = argVals(0)
                    _MemberNo = argVals(1)
                    _CustNo = argVals(2)
                    Using conn As New SqlConnection(connStr), _
                        cmd As New SqlCommand(upd8DML, conn)
                        cmd.Parameters.Add("@Unit", SqlDbType.VarChar, 50).Value = _Unit
                        cmd.Parameters.Add("@MemberNo", SqlDbType.VarChar, 50).Value = _MemberNo
                        cmd.Parameters.Add("@CustNo", SqlDbType.VarChar, 50).Value = _CustNo
                        conn.Open
                        cmd.ExecuteScalar()
                    End Using
                End If
            End If
        Next
End Sub

Protected Function GetLabelTextForID(ckbxIDVal As String) As String
    Dim CoName As String = ""
    Dim _idVal As String = ckbxIDVal
    Dim numberLen As Integer = _idVal.Length - "ckbx".Length
    _idVal = _idVal.Substring("ckbx".Length, numberLen)
    LabelDebug.Text = _idVal

    For Each cntrl As Control In Me.Controls
        If TypeOf cntrl Is Label Then
            If DirectCast(cntrl, Label).ID = "lbl" + _idVal Then
                CoName = DirectCast(cntrl, Label).Text
                Exit For
            End If
        End If
    Next
    Return CoName
End Function

Protected Function GetArgValsForCompanyName(coName As String) As String()
    Dim args(2) As String

    Using con As New SqlConnection("SERVER=PLATYPUS42;DATABASE=duckbilldata;UID=schnozz;PWD=pondscum"), _
          cmd As New SqlCommand("select Unit, MemberNo, CustNo from Customers WHERE CompanyName = @CoName", con)

        con.Open()

        cmd.CommandType = CommandType.Text
        cmd.Parameters.Add("@CoName", SqlDbType.VarChar, 50).Value = coName

        Using reader As SqlDataReader = cmd.ExecuteReader

            While reader.Read
                args(0) = reader.Item(0).ToString()
                args(1) = reader.Item(1).ToString()
                args(2) = reader.Item(2).ToString()
            End While

        End Using
    End Using

    Return args
End Function

As you can see, the code is virtually identical, yet the results (success/failure) are diametrically opposed. Why?

UPDATE

Apparently this line is failing:

If TypeOf cntrl Is CheckBox Then

Although there are checkboxes on the page, that test fails. Why?

I know this because I added some "debug" tests inside the Button1_Click handler like so (can't step through the code):

For Each cntrl As Control In Me.Controls
    Label2.Text="label 2 text from foreach"
    If TypeOf cntrl Is CheckBox Then
        Label2.Text="label 2 text from is checkbox"
        If DirectCast(cntrl, CheckBox).Checked = True Then
            Label2.Text="label 2 text from checked"
            . . .

The last text written to Label2 is "label 2 text from foreach".

So, "If TypeOf cntrl Is CheckBox Then" fails.

Are the checkboxes not seen because they were created dynamically? If so, how can I get around this?

UPDATE 2

When I add this to the corresponding .aspx file:

<%@ Page Language="VB" AutoEventWireup="true" IsPostback="true" CodeFile="custmaint_categoryadmin.aspx.vb" 
Inherits="pages_custmaint_categoryadmin" %>

(added the "IsPostback="true"" part)

..."IsPostback" is underscored with the red squigglies, and when I run it, I get:

Parser Error 
Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately. 

Parser Error Message: Error parsing attribute 'ispostback': The 'ispostback' property is read-only and cannot be set.

Source Error: 

Line 1:  <%@ Page Language="VB" AutoEventWireup="true" IsPostback="true" CodeFile="custmaint_categoryadmin.aspx.vb" Inherits="pages_custmaint_categoryadmin" %>
Line 2:  
Line 3:  <!DOCTYPE html>

UPDATE 3

Now here is something super-bizarre, it seems to me: I dropped a checkbox onto the Webform, and ran it again. Even with the visible-at-design-time checkbox there on the form, it STILL doesn't get past the "If TypeOf cntrl Is CheckBox Then" test; the last update to Label2.Text is still "label 2 text from foreach"

How can it be that a Checkbox, especially a "concrete" rather than dynamic one, does not equate as a checkbox?!?

B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862

0 Answers0