I am experimenting with ASP.NET WebForms and data. I am able to post data to the page using a small code snipped in the ASPX, but I cannot get the buttons for deleting, editing, and viewing individual records to work. I believe this is because I cannot add runat="server"
when I create the table row in the code snippet.
<table id="TBL_Albums" class="table table-striped table-bordered table-responsive">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Image</th>
<th>Release Date</th>
<th>Price</th>
<th>Genre</th>
<th>Artist</th>
<th># of Tracks</th>
<th colspan="3"> </th>
</tr>
</thead>
<tbody>
<% For Each album In GetAlbums()
%>
<tr>
<td><%=album.AlbumID%></td>
<td>
<span class="text-primary font-weight-bold"><%=album.AlbumName %></span>
</td>
<td>
<img alt='<%=album.AlbumName %>' title='<%=album.AlbumName %>' style="width: 96px;" class="img-fluid" src="../Content/Images/DB/<%=album.ImagePath %>" />
<!-- Path broken for now. Will get fixed when I rearrange pages? -->
</td>
<td><%=album.ReleaseDate.ToString("MMMM yyyy") %></td>
<td><%=album.UnitPrice.ToString("c") %></td>
<td><%=album.Genre.GenreName %></td>
<td><%=album.Band.BandName %></td>
<td><%=album.TotalTracks %></td>
<td>
<asp:Button ID="BTN_Details" runat="server" CssClass="btn btn-block btn-lg btn-info" Text="Details" OnClick="BTN_Details_Click" />
</td>
<td>
<asp:Button ID="BTN_Edit" runat="server" CssClass="btn btn-block btn-lg btn-warning" Text="Edit" OnClick="BTN_Edit_Click" data-toggle="modal" data-target="#EditAlbum" />
</td>
<td>
<asp:Button ID="BTN_Delete" runat="server" CssClass="btn btn-block btn-lg btn-danger" Text="Delete" OnClick="BTN_Delete_Click" />
</td>
</tr>
<%
Next %>
</tbody>
</table>
When I run the project and click on one of the buttons, I get this exception:
System.InvalidCastException
HResult=0x80004002
Message=Unable to cast object of type 'System.Web.UI.WebControls.ContentPlaceHolder' to type 'System.Web.UI.HtmlControls.HtmlTableRow'.
Source=<Cannot evaluate the exception source>
StackTrace:
<Cannot evaluate the exception stack trace>
My codebehind for the Edit button looks like this:
Protected Sub BTN_Edit_Click(sender As Object, e As EventArgs)
Dim context As New MusicContext
ClientScript.RegisterStartupScript(Page.GetType(), "EditAlbum", "$('#EditAlbum').modal();", True)
Dim buttonDetails As Button = TryCast(sender, Button)
Dim row As HtmlTableRow = DirectCast(buttonDetails.NamingContainer, HtmlTableRow)
Dim img As HtmlImage = TryCast(row.Cells(2).Controls(0), HtmlImage)
LBL_AlbumToUpdate.Text = row.Cells(1).InnerText
HF_AlbumIDEdit.Value = row.Cells(0).InnerText
TB_EditAlbumName.Text = row.Cells(1).InnerText
IMG_AlbumImage.ImageUrl = img.Src
TB_EditAlbumReleaseDate.Text = CDate(row.Cells(3).InnerText).ToString("yyyy-MM")
TB_EditAlbumPrice.Text = CDec(row.Cells(4).InnerText)
row.Cells(5).InnerText = DDL_EditAlbumGenre.SelectedItem.Text
row.Cells(6).InnerText = DDL_EditAlbumBand.SelectedItem.Text
End Sub
You are correct, it is because the NamingContainer is a PlaceHolder and not an HTMLTableRow. You can try using <asp:Table>, <asp:TableRow>, <asp:TableColumn>
controls instead but I think you're going about this the wrong way.
Instead of iterating with a for each, try using a <asp:Repeater>
or <asp:DataList>
control. Something like:
<tbody>
<asp:Repeater id="repAlbums" runat="server">
<ItemTemplate>
<tr>
<td>
<asp:Image id="imgAlbumName" ImageUrl="../Content/Images/DB/<%# Eval("ImagePath") %> runat="server" />
</td>
<td>
<asp:Label id="lblReleaseDate" runat="server" Text="<%#Eval("ReleaseDate.ToString("MMMM yyyy")") %>" />
</td>
<td>
<asp:Button ID="BTN_Edit" runat="server" CssClass="btn btn-block btn-lg btn-warning" Text="Edit" data-toggle="modal" data-target="#EditAlbum" CommandName="Edit" />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</tbody>
Bind the Repeater in the load event:
Me.repAlbums.DataSource = GetAlbums()
Me.repAlbums.DataBind()
And then you would handle the click event in the Repeater's ItemCommand event:
Private Sub repAlbums_ItemCommand(source As Object, e As RepeaterCommandEventArgs) Handles repAlbums.ItemCommand
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
Select Case e.CommandName
Case "Edit"
Dim imgAlbumName As Image = DirectCast(e.Item.FindControl("imgAlbumName"), Image)
Dim lblReleaseDate as Label = DirectCast(e.item.FindControl("lblReleaseDate"), Label)
TB_EditAlbumReleaseDate.Text = CDate(lblReleaseDate.Text).ToString("yyyy-MM")
End Select
End If
End Sub
Put your td cell data within label or literal controls in order to be able to access them via the code behind.
User contributions licensed under CC BY-SA 3.0