Null reference dropdown in gridview
Solution 1:
A a few things.
You could have the user make all changes, and the below the grid, one save button.
however, since you have a button on each row, to save the row back to database?
Then no need exists to loop all rows in the one save button row????
However, what happens if the user changes several rows - forgets to hit save, and then does hit save? In other words, the user going to be somewhat confused here?
So, it not clear that clicking on the save button should only save the current row?
If that is the goal, then we could have say this setup:
<asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table" Width="50%">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Rate">
<ItemTemplate>
<asp:DropDownList ID="cboRank" runat="server"
DataValueField="ID"
DataTextField="Rating" >
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Save" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Button ID="cmdSave" runat="server" Text="Save" CssClass="btn" Width="60"
OnClick="cmdSave_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And code to load would be:
Dim rstRank As New DataTable ' to load cbo box
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadData()
End If
End Sub
Sub LoadData()
' load combo box data
rstRank = MyRst("SELECT ID, Rating from tblRating ORDER BY ID")
Dim strSQL As String =
"SELECT ID, FirstName, LastName, HotelName, Description, Ranking from tblHotels"
GHotels.DataSource = MyRst(strSQL)
GHotels.DataBind()
End Sub
Function MyRst(strSQL As String) As DataTable
Dim rst As New DataTable
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand(strSQL, conn)
conn.Open()
rst.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rst
End Function
Protected Sub GHotels_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GHotels.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim cboRank As DropDownList = e.Row.FindControl("cboRank")
cboRank.DataSource = rstRank
cboRank.DataBind()
' add blank row
cboRank.Items.Insert(0, New ListItem("Select", "0"))
Dim v As Object = e.Row.DataItem
Dim rData As DataRowView = e.Row.DataItem
If Not IsDBNull(rData("Ranking")) Then
cboRank.SelectedValue = rData("Ranking")
End If
End If
End Sub
and we now have this:
Ok, so the save button - to save the one row?
this works:
Protected Sub cmdSave_Click(sender As Object, e As EventArgs)
Dim btn As Button = sender
Dim gRow As GridViewRow = btn.NamingContainer
Dim cboRank As DropDownList = gRow.FindControl("cboRank")
Dim strSQL As String = "UPDATE tblHotels SET Ranking = @Rating WHERE ID = @ID"
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand(strSQL, conn)
cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = GHotels.DataKeys(gRow.RowIndex).Value
cmdSQL.Parameters.Add("@Rating", SqlDbType.Int).Value = cboRank.SelectedItem.Value
conn.Open()
cmdSQL.ExecuteNonQuery()
End Using
End Using
End Sub
So, as you can see, no real need to loop and save ALL rows, is there?
I would think that if you want ONE save button?
Then move the save button OUT of the grid, and then save have this:
<asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table" Width="50%">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Rate">
<ItemTemplate>
<asp:DropDownList ID="cboRank" runat="server"
DataValueField="ID"
DataTextField="Rating" >
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<br />
<asp:Button ID="cmdSave" runat="server" Text="Save" CssClass="btn" Width="60"
OnClick="cmdSave_Click" />
And now this:
And the one save button (which I think after saving should say navagate to some other page - since we are done). That code to now save all rows, would be:
Protected Sub cmdSave_Click(sender As Object, e As EventArgs)
Using conn As New SqlConnection(My.Settings.TEST4)
Dim strSQL As String = "UPDATE tblHotels SET Ranking = @Rating WHERE ID = @ID"
conn.Open()
For Each gRow As GridViewRow In GHotels.Rows
Dim cboRank As DropDownList = gRow.FindControl("cboRank")
Using cmdSQL As New SqlCommand(strSQL, conn)
cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = GHotels.DataKeys(gRow.RowIndex).Value
cmdSQL.Parameters.Add("@Rating", SqlDbType.Int).Value = cboRank.SelectedItem.Value
cmdSQL.ExecuteNonQuery()
End Using
Next
End Using
End Sub
So, again the code is rather simular for saving "all" rows, or just the one row.
However, we could also drop in a button beside "save" called "un-do" or "cancel"
So, the above shows how to get the row click - for ONE row save, and the 2nd code shows how do to this for all rows.