为什么需要自定义模板?

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

asp.net 自定义模板
(图片来源网络,侵删)
  1. 定制化布局和样式:你可能需要根据数据值动态改变行、单元格的颜色、字体,或者添加自定义的 HTML 结构(如添加图标、徽章等)。
  2. 嵌入复杂内容:你可能想在数据行中嵌入其他控件,
    • 一个按钮或链接,用于执行“编辑”、“删除”或“查看详情”等操作。
    • 一个下拉列表或文本框,用于在页面上直接编辑数据。
    • 一个图片控件,用于显示从数据库路径读取的图片。
    • 一个用户控件或自定义服务器控件。
  3. 条件渲染:你可能只想在满足特定条件时才显示某些内容,当某个产品的“库存”为 0 时,显示“缺货”标签。
  4. 数据格式化:虽然 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. 在“姓名”列前添加一个用户图标。
  2. 根据“性别”显示“男”或“女”,并为它们设置不同的颜色。
  3. 在“状态”列,如果员工是“在职”,则显示一个绿色的“在职”标签;如果是“离职”,则显示一个红色的“离职”标签。
  4. 在“操作”列添加一个“编辑”按钮。

步骤 1:准备数据源

你需要一个数据源,这可以是一个 Entity Framework 数据库上下文、一个 Linq to SQL 数据上下文,或者一个简单的 ObjectDataSource,为了演示,我们假设你已经有了一个可以绑定到 GridView 的数据源。

asp.net 自定义模板
(图片来源网络,侵删)

步骤 2:在 ASPX 页面中配置 GridView

.aspx 页面中,拖放一个 GridView 控件,并设置其 DataSourceID 或在代码后台进行数据绑定。

<asp:GridView ID="gvEmployees" runat="server" AutoGenerateColumns="False" DataKeyNames="EmployeeID">
    <!-- Columns 将在这里定义 -->
</asp:GridView>

注意:我们将 AutoGenerateColumns="False",因为我们希望手动定义每一列及其模板。

步骤 3:手动定义列并使用模板

我们为 GridView 添加 BoundFieldTemplateField,对于需要自定义样式的列,我们使用 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" %>,并且通常需要使用 ListViewRepeater 等更灵活的控件。
    • 示例:<%# ((Employee)Container.DataItem).Name %>

进阶技巧

  1. 在模板中访问父容器数据: 有时你需要根据父行的数据来决定子项或模态框的显示,可以使用 FindControl 结合 NamingContainer 来找到父控件,然后获取其数据键。

    // 在模态框的 ItemTemplate 或事件处理程序中
    LinkButton btnShowDetail = (LinkButton)sender;
    GridViewRow row = (GridViewRow)btnShowDetail.NamingContainer;
    int employeeId = Convert.ToInt32(gvEmployees.DataKeys[row.RowIndex].Value);
  2. 使用 ListView 实现更灵活的布局ListView 是功能最强大的数据绑定控件之一,它使用 LayoutTemplate 定义整体结构,然后用 ItemTemplate, GroupTemplate 等来填充内容,这使得你可以轻松地将数据渲染为 <ul>, <div> 等任何你想要的 HTML 结构,而不仅仅是 <table>

  3. 使用 DataBinder.Eval 的第二个参数进行格式化Eval 可以接受第二个参数作为格式化字符串。

    <asp:Label ID="lblHireDate" runat="server" Text='<%# Eval("HireDate", "{0:yyyy-MM-dd}") %>'></asp:Label>

ASP.NET 的自定义模板功能是构建动态、丰富用户界面的基石,它将数据展示逻辑与页面布局紧密地结合在一起,赋予了开发者极大的灵活性,通过熟练运用 TemplateField、数据绑定表达式(Eval, Bind)以及后台事件处理,你可以轻松应对绝大多数复杂的数据展示和编辑需求。