Getting HTML Table Rows in VB.NET

2019-08-21 01:11发布

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">&nbsp;</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

1条回答
来,给爷笑一个
2楼-- · 2019-08-21 01:41

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.

查看更多
登录 后发表回答