在 Repeater、DataList、GridView 三大資料控件中,Repeater 無預設版面、無 ViewState 膨脹、渲染最輕量,是追求 **Web 標準語意化 HTML、高效能、完全掌控輸出** 的首選。本文分享強型別繫結、避開反射效能陷阱、模板結構最佳實踐與實戰技巧。
| 特性 | Repeater | DataList | GridView |
|---|---|---|---|
| HTML 掌控度 | ✅ 完全自訂 (ul/li, table, div 任意) | ⚠️ 表格/流式佈局 | ❌ 僅 Table,難微調 |
| ViewState | ✅ 極小 (無編輯/分頁狀態) | ⚠️ 中等 | ❌ 大 (含排序/分頁/編輯狀態) |
| 效能 | ✅ 最快 | ⚠️ 中等 | ❌ 最慢 |
| 內建功能 | ❌ 無分頁/編輯/排序 | ⚠️ 部分 | ✅ 豐富 |
<asp:Repeater ID="rptCategories" runat="server">
<HeaderTemplate>
<ul class="category-list">
</HeaderTemplate>
<ItemTemplate>
<li class="category-item">
<span class="id"><%# ((CategoryInfo)Container.DataItem).Id %></span>
<span class="name"><%# ((CategoryInfo)Container.DataItem).Name %></span>
</li>
</ItemTemplate>
<AlternatingItemTemplate>
<li class="category-item alt">...</li>
</AlternatingItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
<!-- ❌ 慢:Eval 使用反射,晚繫結,無型別安全 -->
<%# Eval("Name") %>
<!-- ✅ 快:強型別轉型,編譯期檢查,直接存取屬性 -->
<%# ((CategoryInfo)Container.DataItem).Name %>
PropertyInfo.GetValue,大量資料明顯拖慢渲染。List<T>、IEnumerable<T>、IList<T>,避免 DataTable/DataSet 額外轉換層。<%# ((Product)Container.DataItem).IsOnSale ? "<span class='badge'>特價</span>" : "" %>
<ItemTemplate>
<h3><%# ((Category)Container.DataItem).Name %></h3>
<asp:Repeater ID="rptProducts" runat="server"
DataSource='<%# ((Category)Container.DataItem).Products %>'>
<ItemTemplate>
<div><%# ((Product)Container.DataItem).Name %></div>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
protected void rpt_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var product = (Product)e.Item.DataItem;
var lblStock = (Label)e.Item.FindControl("lblStock");
lblStock.Text = product.Stock > 0 ? "有貨" : "缺貨";
lblStock.CssClass = product.Stock > 0 ? "text-success" : "text-danger";
}
}
Repeater 以極簡設計換取極致自由:無 ViewState 包袱、無預設樣式干擾、渲染速度最快。配合 **強型別繫結**、**語意化 HTML 模板**、**按需載入資料**,是建構高效能、易維護、SEO 友善列表頁的利器。下次面對列表需求,請先問自己:「我需要 GridView 的內建功能嗎?」若否,果斷選 Repeater。