'vb.net oncheckedchanged - Error: Object reference not set to an instance of an object

So basically I have a check box and a HTMLSELECT (DropdownList). When the checkedbox is checked, I need the drop down list to become visible.

I've declared the dropdown list object in the class (outside of the drop-down sub), so that the "onchecked" sub can use this drop down object. When I check the checkbox, I get an "Object reference not set to an instance of an object." error.

How do I use this htmlselect object in the "onchecked" sub, so that the drop down becomes visible when the checkbox is checked?

Here's the checkbox:

<itemtemplate>
  <asp:checkbox ID="checkInActive" runat="server" Enabled="true" 
       AutoPostBack="true" 
       OnCheckedChanged="checkInActive_CheckedChanged"></asp:checkbox>
</itemtemplate>

Heres the sub that triggers the OnCheckedChange (Making the drop down visible)

Protected Sub checkInActive_CheckedChanged(sender As Object, e As EventArgs)


        objDdlGrv.Visible = True

    End Sub

And here's a sample of the sub where the HTMLSELECT object is created:

For Each objGridItem In dgHeader2.Items

                    'Main DropDown for GRV Number
                    objDdlGrv = CType(objGridItem.Cells(6).FindControl("ddlGrv"), HtmlSelect)
                    objDdlGrv.DataSource = dtBranchGrvs
                    objDdlGrv.DataTextField = "GrvNo"
                    objDdlGrv.DataValueField = "GrvId"
                    objDdlGrv.DataBind()
                    objDdlGrv.Items.Insert(0, "Not Selected")
                    objDdlGrv.SelectedIndex = 0
                    objDdlGrv.Visible = False
                        


Solution 1:[1]

Ok, I'll take a whack at this. But you should have provided more details. You do NOT HAVE ANYTHING close to "just" a check box, and "just" a drop down. This is like saying you have a rope, but leave out the details that a heard of cattle is attached to that rope. A MASSIVE difference here!

so, it looks like we have a grid view.

And one of the columns in the GV is a check box, and I assume the next column is the drop down list?

Ok, so then we want that if you check the box (on the given GV row), then we display the combo box for that given row.

I mean, given this is a grid, then of course we can't JUST reference ONE check box by name, since what row are you actually talking about? And since the combo box (drop down list) is also on that same row, then once again, what row and what "instance" of the combo box is ALSO a HUGE deal.

So, we will assume a list of hotels. And if the active (a check box is checked) then we will also display the combo box (drop down).

And for rows that NOT YET have the check box (checked), and we check that box on that row? Then of course we need to display the combo box that not displayed for that row (and of course fill the combo box).

So, this is how we approach this.

First up our grid view (that huge, massive, mount Everest detail you left out). So, the fact of a grid here is of course quite much everything in this issue.

The reason of course, is that we not only having one check box, and one combo box, but we going to have "many" rows of each. And thus how you get/use and reference the controls VERY much will change as a result.

So, first up, here is our grid view markup. It has the check box, and the combo box.

Obviously, for each row, we need to load up "each" instance of the combo box with data, and furthermore, we have to display (or not) the combo box for that given row.

You also don't mention if the check box is data driven, or bound or has a value from the database, but it actually will not matter for this example.

In our case, our combo box will also be filled from the database - it will be a hotel rating (good, bad, etc.).

So, our markup:

        <asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False" 
            DataKeyNames="ID" cssclass="table">
            <Columns>
                <asp:BoundField DataField="FirstName" HeaderText="FirstName" />
                <asp:BoundField DataField="LastName" HeaderText="LastName"   />
                <asp:BoundField DataField="City" HeaderText="City"           />
                <asp:BoundField DataField="HotelName" HeaderText="HotelName" />
                <asp:BoundField DataField="Description" HeaderText="Description"  />

                <asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center">
                    <ItemTemplate>
                        <asp:CheckBox ID="chkActive" runat="server"
                            Checked='<%# Eval("Active") %>'
                            AutoPostBack="true" OnCheckedChanged="chkActive_CheckedChanged"
                            />
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Rating">
                    <ItemTemplate>
                        <asp:DropDownList ID="cboRating" runat="server" style="display:normal"
                            DataValueField="ID"
                            DataTextField="Rating" >
                        </asp:DropDownList>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>

And our code to load:

Dim rstCboChoice As DataTable
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then
        LoadGrid()
    End If

End Sub

Sub LoadGrid()

    ' first load up our table for the comb box
    ' NOTE the page level scope - we declared rstCboChoice global to these
    ' routines

    rstCboChoice = MyRst("SELECT ID, Rating FROM tblRating ORDER BY ID")
    ' Now load our grid
    GHotels.DataSource = MyRst("SELECT * FROM tblHotelsA ORDER BY HotelName")
    GHotels.DataBind()

End Sub

And note we use the row data bound event. This event is typical used for formatting each row, change color, or fill out a combo box for each row.

This setting:

enter image description here

(so display property sheet for GV, double click in above event - and we get a row data bound event. That's were we do the magic.

This:

Protected Sub GHotels_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GHotels.RowDataBound

    If e.Row.RowType = DataControlRowType.DataRow Then

        ' get data base row data
        Dim gData As DataRowView = e.Row.DataItem

        ' first check check box for this row, ad combo box
        Dim chkBox As CheckBox = e.Row.FindControl("chkActive")
        Dim cboRating As DropDownList = e.Row.FindControl("cboRating")

        cboRating.DataSource = rstCboChoice
        cboRating.DataBind()
        cboRating.Items.Insert(0, "Not Selected")
        ' our combo box does have a value from the database, so set that
        cboRating.SelectedValue = gData.Item("Ranking")

        If chkBox.Checked Then
            cboRating.Visible = True
        Else
            cboRating.Visible = False
        End If
    End If

End Sub

And now we have/get this:

enter image description here

Now, the only code left is our check box event. When we click on it, we want to show (or hide) the combo box).

So, that code will look like this: (don't forget the autopost back for the check box).

Protected Sub chkActive_CheckedChanged(sender As Object, e As EventArgs)

    ' display or hide cbo box for this row when check box changes.
    Dim ckBox As CheckBox = sender
    Dim gRow As GridViewRow = ckBox.NamingContainer

    Dim cboRating As DropDownList = gRow.FindControl("cboRating")

    If ckBox.Checked Then
        cboRating.Visible = True
    Else
        cboRating.Visible = False
    End If

End Sub

Now, we could add code to say fill out the items in teh check box (say a data table), but we took care of that by ALWAYS loading it up, and on row data bound event, we hide/show the box. But, as above event shows, ONCE we have that reference to the correct row instance of the combo box, then we could fill the data and data bind or do whatever to that one row combo box.

Just keep in mind that for each row of the GridView, there are SEPERATE instances of the controls. So when using a ListView, Repeater, GridView?

Then the controls are repeated, and you can NOT USE me.ControlName anymore, since that does not "resolve" to the one row of the grid view.

And in place of that "row bound" event, we could load the grid AND THEN load up each combo box on each row. The loop will look VERY similar to the loop you had, and in place of row data bound, we could load/bind the grid, and then setup + fill the combo box like this:

Sub TEst()

    Dim rstCboChoice As DataTable
    rstCboChoice = MyRst("SELECT ID, Rating FROM tblRating ORDER BY ID")

    For Each gRow As GridViewRow In GHotels.Rows

        Dim chkBox As CheckBox = gRow.FindControl("chkActive")
        Dim cboRating As DropDownList = gRow.FindControl("cboRating")

        cboRating.DataSource = rstCboChoice
        cboRating.DataBind()
        cboRating.Items.Insert(0, "Not Selected")
        ' our combo box does have a value from the database, so set that
        cboRating.SelectedValue = gData.Item("Ranking")

        If chkBox.Checked Then
            cboRating.Visible = True
        Else
            cboRating.Visible = False
        End If
    Next

End Sub

Last but not least, I did use this routine to help:

Public Function MyRst(strSQL As String) As DataTable

    Dim rstData As New DataTable
    Using conn As New SqlConnection(My.Settings.TEST4)
        Using cmdSQL As New SqlCommand(strSQL, conn)
            conn.Open()
            rstData.Load(cmdSQL.ExecuteReader)
            rstData.TableName = strSQL
        End Using
    End Using
    Return rstData
End Function

so the above is a "handy" routine to return a data table based on the passed SQL.

And do note, that while I used row databound to fill out ALL of the cbo boxes I could fill out the combo box on the check box click. So, say like this:

Protected Sub chkActive_CheckedChanged(sender As Object, e As EventArgs)

    ' display or hide cbo box for this row when check box changes.
    Dim ckBox As CheckBox = sender
    Dim gRow As GridViewRow = ckBox.NamingContainer

    Dim cboRating As DropDownList = gRow.FindControl("cboRating")

    dim rstCboData as DataTable
    rstCboData = MyRst("SELECT ID, Rating FROM tblRating")
    
    If ckBox.Checked Then
        cboRating.Visible = True
        cboRating.DataSource = rstCboData
        cboRating.DataBind
        cboRating.Items.Insert(0, "Not Selected")
    Else
        cboRating.Visible = False
    End If

End Sub

So how the grid view works?

For databound fields/columns, you use gridview1.Cells

But, for ANY templated column, then you do NOT use .cells, and have to use findcontrol as per above.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1