Zack Peterson
Zack Peterson

Reputation: 57373

How do I best populate an HTML table in ASP.NET?

This is what I've got. It works. But, is there a simpler or better way?

ASPX Page…

<asp:Repeater ID="RepeaterBooks" runat="server">
    <HeaderTemplate>
        <table class="report">
            <tr>
                <th>Published</th>
                <th>Title</th>
                <th>Author</th>
                <th>Price</th>
            </tr>
    </HeaderTemplate>
    <ItemTemplate>
            <tr>
                <td><asp:Literal ID="LiteralPublished" runat="server" /></td>
                <td><asp:Literal ID="LiteralTitle" runat="server" /></td>
                <td><asp:Literal ID="LiteralAuthor" runat="server" /></td>
                <td><asp:Literal ID="LiteralPrice" runat="server" /></td>
            </tr>
    </ItemTemplate>
    <FooterTemplate>
        </table>
    </FooterTemplate>
</asp:Repeater>

ASPX.VB Code Behind…

Protected Sub Page_Load( ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Dim db As New BookstoreDataContext
    RepeaterBooks.DataSource = From b In db.Books _
                               Order By b.Published _
                               Select b
    RepeaterBooks.DataBind()
End Sub

Sub RepeaterBooks_ItemDataBound( ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles RepeaterBooks.ItemDataBound
    If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
        Dim b As Book = DirectCast(e.Item.DataItem, Book)
        DirectCast(e.Item.FindControl("LiteralPublished"), Literal).Text = "<nobr>" + b.Published.ToShortDateString + "</nobr>"
        DirectCast(e.Item.FindControl("LiteralTitle"), Literal).Text = "<nobr>" + TryNbsp(HttpContext.Current.Server.HtmlEncode(b.Title)) + "</nobr>"
        DirectCast(e.Item.FindControl("LiteralAuthor"), Literal).Text = "<nobr>" + TryNbsp(HttpContext.Current.Server.HtmlEncode(b.Author)) + "</nobr>"
        DirectCast(e.Item.FindControl("LiteralPrice"), Literal).Text = "<nobr>" + Format(b.Price, "c") + "</nobr>"
    End If
End Sub

Function TryNbsp(ByVal s As String) As String
    If s = "" Then
        Return "&nbsp;"
    Else
        Return s
    End If
End Function

Upvotes: 5

Views: 18660

Answers (8)

Serhat Ozgel
Serhat Ozgel

Reputation: 23766

The ListView control introduced with framework 3.5 might be a little bit better solution. Your markup would look like this:

<asp:ListView runat="server" ID="ListView1"
    DataSourceID="SqlDataSource1">
  <LayoutTemplate>
    <table runat="server" id="table1" runat="server" >
      <tr runat="server" id="itemPlaceholder" ></tr>
    </table>
  </LayoutTemplate>
  <ItemTemplate>
    <tr runat="server">
      <td runat="server">
        <asp:Label ID="NameLabel" runat="server"
          Text='<%#Eval("Name") %>' />
      </td>
    </tr>
  </ItemTemplate>
</asp:ListView>

You'll want to set your data source ID from a public or private property in the code-behind class.

Upvotes: 3

mattruma
mattruma

Reputation: 16687

I agree with Geoff, the only time we use Literals is if we want to do something different with the data.
For example, we might want a DueDate field to say "Today" or "Yesterday" instead of the actual date.

Upvotes: 1

mattruma
mattruma

Reputation: 16687

If you don't need ASP.NET handled edit cabilities I would stay away from the DataGrid and the GridView ... they provide unnecessary bloat.

Upvotes: 0

EndangeredMassa
EndangeredMassa

Reputation: 17528

I would use a GridView (or DataGrid, if you are using an older version of ASP.NET).

<asp:GridView ID="gvBooks" runat="server" AutoGenerateColumns="False">
    <Columns>
        <asp:BoundField HeaderText="Published" DataField="Published" />
        <asp:BoundField HeaderText="Title" DataField="Title" />                     
        <asp:BoundField HeaderText="Author" DataField="Author" />
        <asp:BoundField HeaderText="Price" DataField="Price" />
    </Columns>
</asp:GridView>

With some code-behind:

Private Sub gvBooksRowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvBooks.RowDataBound
     Select Case e.Row.RowType
        Case DataControlRowType.DataRow

            ''' Your code here '''

     End Select
End Sub

You can bind it in a similar way. The RowDataBound event is what you need.

Upvotes: 1

Mark Cidade
Mark Cidade

Reputation: 100037

This is what the GridView is for.

<asp:GridView runat="server" DataSourceID="SqlDataSource1">
   <Columns>
      <asp:BoundField HeaderText="Published" DataField="Published" />
      <asp:BoundField HeaderText="Author" DataField="Author" />
   </Columns>
</asp:GridView>

Upvotes: 1

Geoff
Geoff

Reputation: 9340

In .Net 3.0+ you can replace your ItemDataBound to the asp:Literal by doing something like this:

<ItemTemplate>
            <tr>
                <td><%# Eval("published") %></td>
                ...

where "published" is the name of a field in the data you have bound to the repeater

Edit: @Alassek: I think the performance hit of reflection is often over-emphasized. Obviously you need to benchmark performance of your app, but the hit of the Eval is likely measured in milliseconds. Unless your app is serving many concurrent hits, this probably isn't an issue, and the simplicity of the code using Eval, along with it being a good separation of the presentation, make it a good solution.

Upvotes: 2

Zack Peterson
Zack Peterson

Reputation: 57373

ALassek wrote:

…generate the table in code…

I like the look of that! It seems MUCH less likely to produce a run-time exception due to a typo or field name change.

Upvotes: 0

Adam Lassek
Adam Lassek

Reputation: 35515

@Geoff

That sort of Eval statement was actually added in 2.0, but if performance is important Eval should be avoided since it uses Reflection.

The repeater is a pretty good way of doing it, although it might be faster to generate the table in code:

ASPX Page:

<table class="report" id="bookTable" runat="server">
        <tr>
            <th>Published</th>
            <th>Title</th>
            <th>Author</th>
            <th>Price</th>
        </tr>
 </table>

Code Behind:

Protected Sub Page_Load( ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    If Not Page.IsPostback Then
        BuildTable()
    End If
End Sub

Private Sub BuildTable()
    Dim db As New BookstoreDataContext
    Dim bookCollection = from b in db.Books _
                         Order By b.Published _
                         Select b
    Dim row As HtmlTableRow
    Dim cell As HtmlTableCell

    For Each book As Books In bookCollection
        row = New HtmlTableRow()
        cell = New HtmlTableCell With { .InnerText = b.Published.ToShortDateString }
        row.Controls.Add(cell)
        cell = New HtmlTableCell With { .InnerText = TryNbsp(HttpContext.Current.Server.HtmlEncode(b.Title)) }
        row.Controls.Add(cell)
        cell = New HtmlTableCell With { .InnerText = TryNbsp(HttpContext.Current.Server.HtmlEncode(b.Author))
        row.Controls.Add(cell)
        cell = New HtmlTableCell With { .InnerText = Format(b.Price, "c") }
        row.Controls.Add(cell)
        bookTable.Controls.Add(row)
    Next

I guess it depends on how important speed is to you. For simplicity's sake I think I would go with the Repeater.

Upvotes: 4

Related Questions