Search code examples
asp.netvb.netdatatabledrop-down-menu

Seemingly unable to access a Dropdownlist stored in a datatable


this is going to take some explaining.

I have an asp.net page with 2 dropdown lists. These each postback. I am using vb.net for the code behind. I then have a public datatable which stores some values which relate to the dropdownlists.

The table (tblfilters) looks like this:

Index DBField DDList
0 PurchaseYear ddlYOP
1 SetNumber ddlnumber

The Index datatype is an integer, the DB Field is a string and the DDList is dropdownlist

I can loop through the table records and, using the DDList, bind the values to the controls from SQL which works well. My issue is that I can't seem to get the Selecteditem.Text from the same dropdownlists. If I refer to the controls on the page by ID then I get the selected value however if I try and use the datatable field value all I get back is the top value from the dropdownlist, no matter what is selected.

The binding of the dropdownlists only happens once and is already within the page_load event

If Not IsPostBack Then
    For Each row In tblfilters.Rows
        BindFilterData(row.Item("DBField"), row.Item("DDList"))
    Next
End If

I have tried referencing the DDList values by the following methods:

For Each row In tblfilters.Rows
    lbloutput.Text += row.Item("DDList").Selecteditem.Text
Next

or

For Each row In tblfilters.Rows
    Dim ddltest as dropdownlist = FindControl(row.Item("DDList"))
    lbloutput.Text += ddltest.Selecteditem.Text
Next

It doesn't matter if I've selected anything in the dropdownlist or not I always just get back the first value in the list.

As I say, if I use the following then it works but I really could do with looping through the datatable for what I'm trying to do:

lbloutput.Text += ddlyp.SelectedItem.Text
lbloutput.Text += ddlnumber.SelectedItem.Text

I am sure I'm missing something obvious here and hoping someone can spot the error of my ways.

Thanks in advance


Solution

  • Ok, so the steps in general to display a table in a web form are:

    Load up combo box choices into a DataTable for each combo box.

    Load the display of the table. This could be a GridView, Listview, Repeater or even an older DataGrid (you not find the DataGrid in the tool box anymore, but in markup they can be used).

    For display of a table, then often a GridView is a great choice, but as you have more and more markup and custom controls in that grid display, then I tend to move over to using a ListView, as it has more flexibility for layout and use of controls like a combo box (DropDownList).

    So, for this example, we will have a list of people, and for each row of data, we will have a combo box for the city (a simple text column from the database), and second combo box for the hotel selection. In this second combo box, of course we will store/save/use the PK for the hotel choices, but display the HotelName (so, the combo box has 2 values, the hidden PK value of the hotel, then the text value of HotelName). Upon selection of the Hotel combo box, then we will need to save/store the PK value of the hotel selected into the one data row.

    So, after we load up the ListView we then have to load up the combo boxes for each row, and THEN an additional step is required to set the current grid row combo boxes to the correct underlying values selected for that row.

    So, say this markup:

    <asp:ListView ID="ListView1" runat="server" DataKeyNames="ID"
        OnItemDataBound="ListView1_ItemDataBound">
        <LayoutTemplate>
            <table id="itemPlaceholderContainer" runat="server" border="0" 
                class="table table-bordered table-hover">
                <tr runat="server" style="">
                    <th runat="server" style="width:100px">First</th>
                    <th runat="server" style="width:100px">Last</th>
                    <th runat="server" style="width:160px" >City</th>
                    <th runat="server" style="width:240px">Hotel Name</th>
                </tr>
                <tr id="itemPlaceholder" runat="server">
                </tr>
            </table>
        </LayoutTemplate>
        <ItemTemplate>
            <tr style="">
                <td><asp:Label ID="First" runat="server" Text='<%# Eval("FirstName") %>' /></td>
                <td><asp:Label ID="Last" runat="server" Text='<%# Eval("LastName") %>' /></td>
                <td>
                    <asp:DropDownList ID="cboCity" runat="server"
                        DataTextField="City"
                        width="100%"
                        >
                    </asp:DropDownList>
                </td>
                <td>
                    <asp:DropDownList ID="cboHotel" runat="server"
                        DataTextField="HotelName"
                        DataValueField="ID"
                        width="100%"
                        >
                    </asp:DropDownList>
                </td>
            </tr>
        </ItemTemplate>
    </asp:ListView>
    

    So, note how the above has 2 combo boxes (City, and Hotel)

    Code behind is thus this:

    Dim dtCityList As DataTable
    Dim dtHotelList 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()
    
        dtCityList = MyRst("SELECT City FROM City ORDER BY City")
        dtHotelList = MyRst("SELECT ID, HotelName FROM tblHotels ORDER BY HotelName")
    
        ListView1.DataSource = MyRst("SELECT * FROM People ORDER BY LastName")
        ListView1.DataBind()
    
    End Sub
    
    
    Protected Sub ListView1_ItemDataBound(sender As Object, e As ListViewItemEventArgs)
    
        If e.Item.ItemType = ListViewItemType.DataItem Then
    
            Dim dRow As DataRowView = e.Item.DataItem    ' get binding data source
    
            Dim cboCity As DropDownList = e.Item.FindControl("cboCity")
            cboCity.DataSource = dtCityList
            cboCity.DataBind()
            cboCity.Items.Insert(0, "Select City")
            If Not IsDBNull(dRow("City")) Then
                cboCity.Text = dRow("City")
            End If
    
            Dim cboHotels As DropDownList = e.Item.FindControl("cboHotel")
            cboHotels.DataSource = dtHotelList
            cboHotels.DataBind()
            cboHotels.Items.Insert(0, "Select Hotel")
            If Not IsDBNull(dRow("Hotel_ID")) Then
                cboHotels.Text = dRow("Hotel_ID")
            End If
        End If
    
    End Sub
    

    And the result is now this:

    enter image description here

    So, the important part in above?

    We load up 2 data table objects with the combo box selections for each row.

    We then load the Grid (a ListView in this example), and on item data bound (that runs for each row), then we load up each combo box (using find control to get a reference for the current row). After setting the combo box list of choices, we then set the current selected combo box value to the current underlying value for that given data row.

    So, the above shows all the moving parts you need when having combo boxes on a given row of data.

    For completeness, I also used one of my library helper routines to return a data table for given SQL. That routine was this:

    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)
            End Using
        End Using
        Return rstData
    End Function