为什么需要自定义模板?
ASP.NET 提供了许多数据绑定控件,它们开箱即用地提供了基本的布局,但现实世界的需求往往更复杂:

- 定制化布局和样式:你可能需要根据数据值动态改变行、单元格的颜色、字体,或者添加自定义的 HTML 结构(如添加图标、徽章等)。
- 嵌入复杂内容:你可能想在数据行中嵌入其他控件,
- 一个按钮或链接,用于执行“编辑”、“删除”或“查看详情”等操作。
- 一个下拉列表或文本框,用于在页面上直接编辑数据。
- 一个图片控件,用于显示从数据库路径读取的图片。
- 一个用户控件或自定义服务器控件。
- 条件渲染:你可能只想在满足特定条件时才显示某些内容,当某个产品的“库存”为 0 时,显示“缺货”标签。
- 数据格式化:虽然
DataFormatString可以处理简单的格式化,但对于更复杂的逻辑(如根据值显示不同的文本),模板提供了更灵活的方式。
常见的模板类型
不同的数据绑定控件支持不同的模板,以下是一些最常用的模板:
| 模板名称 | 常用控件 | 描述 |
|---|---|---|
ItemTemplate |
Repeater, ListView, GridView, DataList | 定义数据列表中每一项的主要显示内容,这是最核心、最常用的模板。 |
AlternatingItemTemplate |
Repeater, ListView, GridView, DataList | 定义交替项的显示内容,通常用于实现斑马线效果。 |
HeaderTemplate / FooterTemplate |
Repeater, ListView, GridView, DataList | 定义列表的头部和尾部,通常用于显示表头或汇总信息。 |
SeparatorTemplate |
Repeater, ListView, DataList | 定义每一项之间的分隔符,<hr> 或一个逗号。 |
EditItemTemplate |
GridView, ListView, DetailsView | 当某一行进入编辑模式时,使用此模板来显示编辑控件(如 TextBox, DropDownList)。 |
InsertItemTemplate |
ListView, DetailsView | 在插入新数据时,使用此模板来显示输入控件。 |
EmptyDataTemplate |
GridView, ListView, FormView | 当数据源没有返回任何数据时,显示此模板的内容,而不是显示一个空的表格。 |
LayoutTemplate |
ListView | 定义 ListView 的整体布局结构,通常包含一个作为容器(如 <table>, <div>)的根元素和占位符控件(如 Placeholder)。 |
实践示例:在 GridView 中使用自定义模板
我们将通过一个经典的 GridView 示例来展示如何使用模板。
场景:显示一个员工列表,并实现以下功能:
- 在“姓名”列前添加一个用户图标。
- 根据“性别”显示“男”或“女”,并为它们设置不同的颜色。
- 在“状态”列,如果员工是“在职”,则显示一个绿色的“在职”标签;如果是“离职”,则显示一个红色的“离职”标签。
- 在“操作”列添加一个“编辑”按钮。
步骤 1:准备数据源
你需要一个数据源,这可以是一个 Entity Framework 数据库上下文、一个 Linq to SQL 数据上下文,或者一个简单的 ObjectDataSource,为了演示,我们假设你已经有了一个可以绑定到 GridView 的数据源。

步骤 2:在 ASPX 页面中配置 GridView
在 .aspx 页面中,拖放一个 GridView 控件,并设置其 DataSourceID 或在代码后台进行数据绑定。
<asp:GridView ID="gvEmployees" runat="server" AutoGenerateColumns="False" DataKeyNames="EmployeeID">
<!-- Columns 将在这里定义 -->
</asp:GridView>
注意:我们将 AutoGenerateColumns="False",因为我们希望手动定义每一列及其模板。
步骤 3:手动定义列并使用模板
我们为 GridView 添加 BoundField 和 TemplateField,对于需要自定义样式的列,我们使用 TemplateField。
<asp:GridView ID="gvEmployees" runat="server" AutoGenerateColumns="False" DataKeyNames="EmployeeID" Width="100%">
<Columns>
<!-- 1. 姓名列 (使用 TemplateField 添加图标) -->
<asp:TemplateField HeaderText="姓名">
<ItemTemplate>
<!-- 使用 Image 控件添加图标 -->
<asp:Image ID="imgIcon" runat="server" ImageUrl="~/images/user.png" ImageAlign="AbsMiddle" style="margin-right: 5px;" />
<!-- 使用 Eval 绑定数据 -->
<asp:Label ID="lblName" runat="server" Text='<%# Eval("Name") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<!-- 2. 性别列 (使用 TemplateField 实现条件渲染和样式) -->
<asp:TemplateField HeaderText="性别">
<ItemTemplate>
<asp:Label ID="lblGender" runat="server" Text='<%# Eval("Gender") %>'
CssClass='<%# Eval("Gender").ToString() == "男" ? "gender-male" : "gender-female" %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<!-- 3. 状态列 (使用 TemplateField 实现复杂的条件渲染) -->
<asp:TemplateField HeaderText="状态">
<ItemTemplate>
<asp:Label ID="lblStatus" runat="server"
Text='<%# Eval("IsOnDuty").ToString() == "True" ? "在职" : "离职" %>'
CssClass='<%# Eval("IsOnDuty").ToString() == "True" ? "status-active" : "status-inactive" %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<!-- 4. 操作列 (使用 TemplateField 添加按钮) -->
<asp:TemplateField HeaderText="操作">
<ItemTemplate>
<asp:Button ID="btnEdit" runat="server" Text="编辑" CommandName="Edit" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
步骤 4:添加 CSS 样式
在页面的 <head> 部分或外部 CSS 文件中,为我们在模板中使用的 CssClass 定义样式。
<style type="text/css">
.gender-male {
color: blue;
font-weight: bold;
}
.gender-female {
color: pink;
font-weight: bold;
}
.status-active {
background-color: #d4edda;
color: #155724;
padding: 3px 8px;
border-radius: 4px;
font-size: 0.9em;
}
.status-inactive {
background-color: #f8d7da;
color: #721c24;
padding: 3px 8px;
border-radius: 4px;
font-size: 0.9em;
}
</style>
步骤 5:处理事件(可选)
如果你想在点击“编辑”按钮时执行一些逻辑,可以在后台代码中处理 RowCommand 事件。
// 在 .cs 文件中
protected void gvEmployees_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Edit")
{
// 获取被点击行的数据键(EmployeeID)
int employeeId = Convert.ToInt32(gvEmployees.DataKeys[e.RowIndex].Value);
// 在这里执行编辑逻辑,例如打开一个模态框或导航到编辑页面
// Response.Redirect($"EditEmployee.aspx?id={employeeId}");
// 或者直接进入 GridView 的编辑模式
// gvEmployees.EditIndex = e.RowIndex;
// BindData(); // 重新绑定数据
}
}
数据绑定表达式
在模板中,我们使用了 <%# ... %> 语法,这是 ASP.NET 的数据绑定表达式,常用的表达式有:
-
Eval("PropertyName"):- 只读:从数据源中读取指定属性的值。
- 工作方式:它使用反射,语法简单但性能稍差,适用于只显示数据的场景。
- 示例:
Text='<%# Eval("Name") %>'
-
Bind("PropertyName"):- 双向:既可以读取数据用于显示,也可以在用户修改后,将新值写回数据源(通常用于编辑模板)。
- 工作方式:性能比
Eval好,因为它不使用反射。 - 示例:
Text='<%# Bind("Name") %>'(通常放在TextBox中)
-
Container.DataItem:- 强类型访问:在模板中,
Container是一个指向当前数据项容器的对象。Container.DataItem就是当前的数据对象本身。 - 优点:可以获得编译时检查和智能提示,性能最好。
- 使用前提:需要在页面顶部添加
<%@ Import Namespace="YourModelNamespace" %>,并且通常需要使用ListView或Repeater等更灵活的控件。 - 示例:
<%# ((Employee)Container.DataItem).Name %>
- 强类型访问:在模板中,
进阶技巧
-
在模板中访问父容器数据: 有时你需要根据父行的数据来决定子项或模态框的显示,可以使用
FindControl结合NamingContainer来找到父控件,然后获取其数据键。// 在模态框的 ItemTemplate 或事件处理程序中 LinkButton btnShowDetail = (LinkButton)sender; GridViewRow row = (GridViewRow)btnShowDetail.NamingContainer; int employeeId = Convert.ToInt32(gvEmployees.DataKeys[row.RowIndex].Value);
-
使用
ListView实现更灵活的布局:ListView是功能最强大的数据绑定控件之一,它使用LayoutTemplate定义整体结构,然后用ItemTemplate,GroupTemplate等来填充内容,这使得你可以轻松地将数据渲染为<ul>,<div>等任何你想要的 HTML 结构,而不仅仅是<table>。 -
使用
DataBinder.Eval的第二个参数进行格式化:Eval可以接受第二个参数作为格式化字符串。<asp:Label ID="lblHireDate" runat="server" Text='<%# Eval("HireDate", "{0:yyyy-MM-dd}") %>'></asp:Label>
ASP.NET 的自定义模板功能是构建动态、丰富用户界面的基石,它将数据展示逻辑与页面布局紧密地结合在一起,赋予了开发者极大的灵活性,通过熟练运用 TemplateField、数据绑定表达式(Eval, Bind)以及后台事件处理,你可以轻松应对绝大多数复杂的数据展示和编辑需求。
