在ASP.NET Web Forms开发中,Repeater是一个被广泛使用却又常被低估的数据绑定控件。它不像GridView那样自带分页和编辑界面,但正因为没有多余封装,开发者可以完全掌控HTML输出结构。下面整理出十篇围绕Repeater控件的经典技术文章,分别从基础用法、模板设计、事件处理、性能优化等维度展开,适合不同阶段的读者按需取用。

一、Repeater基础绑定入门
第一篇推荐的文章聚焦于Repeater最简单的使用方式:如何把DataTable或泛型集合绑定到控件上。很多初学者在Page_Load里直接写绑定代码,却忽略了判断IsPostBack,导致回发时重复绑定并丢失交互状态。基础文章通常会给出清晰的页面结构,包括<HeaderTemplate>、<ItemTemplate>和<FooterTemplate>的写法。
这类文章的价值在于帮读者建立“模板驱动”的思维。Repeater本身不生成任何包裹标签,所有ul、li或table都由开发者手写。下面是一段典型的绑定示例:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<string> data = new List<string> { "苹果", "香蕉", "橙子" };
Repeater1.DataSource = data;
Repeater1.DataBind();
}
}
通过这种最基础的练习,读者能理解DataSource与DataBind的调用顺序,以及为什么模板里可以用<%# Container.DataItem %>这类表达式。它为后续复杂用法打下根基。
二、ItemTemplate中的控件查找
第二篇值得读的文章讲解如何在Repeater的ItemDataBound事件中查找模板内的子控件。这是实际开发的高频需求,比如根据数据状态隐藏某个按钮,或者给Label赋值。常见错误是频繁调用FindControl却不做类型判断,引发空引用异常。
优质文章会提醒读者使用e.Item.ItemType来区分表头、普通项和脚注,避免对非数据项执行查找。参考代码如下:
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Label lbl = e.Item.FindControl("lblName") as Label;
if (lbl != null)
{
lbl.Text = "编号:" + DataBinder.Eval(e.Item.DataItem, "ID");
}
}
}
这类内容通常还会对比DataBinder.Eval与强类型转换的性能差异,指出在大数据量下应优先使用后置代码赋值而非页面端Eval,从而减少反射开销。
三、嵌套Repeater实现主从结构
第三篇文章探讨用嵌套Repeater展示一对多关系,例如订单与订单明细。外层Repeater绑定订单列表,内层在ItemDataBound中根据当前订单ID重新查库并绑定。这里容易踩的坑是N+1查询问题,文章一般会给出批量预加载或字典缓存的改进方案。
示例代码展示内层数据源的绑定时机:
protected void Outer_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var order = e.Item.DataItem as Order;
Repeater inner = e.Item.FindControl("rptDetail") as Repeater;
if (inner != null)
{
inner.DataSource = order.Details;
inner.DataBind();
}
}
}
通过这类文章,读者能掌握父子模板通信的基本模式,并意识到把数据一次性组织好再绑定比循环查库更优。
四、Repeater与分页控件结合
第四篇推荐材料介绍如何给Repeater手工加上分页。由于Repeater没有内置分页,作者通常用PagedDataSource或数据库存储过程取当前页数据。文章会对比两种做法:前者简单但占用内存,后者高效但写起来繁琐。
使用PagedDataSource的片段如下:
PagedDataSource pds = new PagedDataSource(); pds.DataSource = allList; pds.AllowPaging = true; pds.PageSize = 10; pds.CurrentPageIndex = pageIndex; Repeater1.DataSource = pds; Repeater1.DataBind();
这类文章对老系统维护者尤其有用,因为很多内部系统仍要求用Repeater输出干净表格,同时又不能缺失分页体验。
五、模板中用代码块做逻辑判断
第五篇文章专门讲<ItemTemplate>里写<%# %>表达式的技巧,比如根据字段值输出不同样式。新手常把过多逻辑塞进页面,导致维护困难;好文章会建议把判断封装成后台方法,模板只调用。
页面端简洁写法示例:
<ItemTemplate>
<span class="<%# GetCss(Eval("Status")) %>"><%# Eval("Name") %></span>
</ItemTemplate>
后台方法返回字符串,既隔离了逻辑,也方便单元测试。该主题帮助团队建立前后端职责分离的共识。
六、Repeater性能对比评测
第六篇是性能向的横向评测,把Repeater、DataList、GridView放在相同数据量下测试渲染时间和视图状态大小。结论往往是Repeater因不记录控件树而最轻量,但开发效率最低。文章用数据表呈现差异,让读者按需选型。
| 控件 | 视图状态大小 | 绑定耗时(ms) |
|---|---|---|
| Repeater | 最小 | 12 |
| DataList | 中等 | 18 |
| GridView | 最大 | 25 |
这类文章适合架构师在技术方案评审时引用,说明为何遗留系统坚持使用Repeater而非升级到更强控件。
七、清空Repeater与内存释放
第七篇短文关注一个细节:动态变更数据源后如何彻底清空Repeater。直接把DataSource设为null再DataBind虽可行,但若有事件委托未解绑会造成泄漏。文章给出Dispose模式的提醒。
Repeater1.DataSource = null; Repeater1.DataBind(); // 若之前动态添加了事件,需手动移除 Repeater1.ItemDataBound -= Repeater1_ItemDataBound;
该内容虽短,却填补了多数教程忽略的资源管理空白。
八、Repeater生成JSON供前端使用
第八篇视角独特,讲如何借助Repeater把服务端数据拼成JSON片段,再交给JavaScript框架。这种做法在渐进式改造老项目时很实用,不必一次性重写前端。
<ItemTemplate>
{ "id": "<%# Eval("ID") %>", "name": "<%# Eval("Name") %>" }
</ItemTemplate>
文章会警告注意引号转义,否则生成的JSON非法。它体现了Repeater的灵活性边界。
九、错误处理与空数据模板
第九篇强调<EmptyDataTemplate>和异常捕获。当查询结果为空或数据库超时,用户体验取决于是否有友好提示。文章示范在绑定前判断集合数量,并给出兜底UI。
if (data == null || data.Count == 0)
{
Repeater1.Visible = false;
lblEmpty.Visible = true;
}
else
{
Repeater1.DataSource = data;
Repeater1.DataBind();
}
该主题让开发者意识到健壮性比炫技更重要。
十、Repeater在.NET Core时代的替代思路
最后一篇跳出Web Forms,讨论如果迁移到ASP.NET Core,原本Repeater的场景如何用Razor视图的foreach替代。文章列出语法映射表,缓解老开发者的迁移焦虑。
@foreach (var item in Model.Items)
{
<div>@item.Name</div>
}
这类文章虽不直接讲Repeater,但帮读者看清技术演进路线,知道旧知识如何转化而非作废。
以上十篇文章从浅入深覆盖了Repeater控件的绝大多数实际课题。无论是刚接手旧系统的新人,还是做技术决策的负责人,都能从中找到对应答案。建议先读基础与事件处理两篇,再按项目痛点选读性能或嵌套相关主题。