在 DetailsView 控件中使用 TemplateField (VB)

作者 :Scott Mitchell

下载 PDF

GridView 提供的相同 TemplateFields 功能也可用于 DetailsView 控件。 在本教程中,我们将使用包含 TemplateFields 的 DetailsView 一次显示一个产品。

简介

与 BoundField、CheckBoxField、HyperLinkField 和其他数据字段控件相比,TemplateField 在呈现数据方面具有更高的灵活性。 在 上一教程中 ,我们了解了如何在 GridView 中使用 TemplateField 来:

  • 在一列中显示多个数据字段值。 具体而言,和 FirstNameLastName 字段合并为一个 GridView 列。
  • 使用备用 Web 控件来表示数据字段值。 我们了解了如何使用 Calendar 控件显示 HiredDate 值。
  • 显示基于基础数据的状态信息。 尽管该 Employees 表不包含返回员工在作业中的天数的列,但我们能够使用 TemplateField 和格式设置方法在上一教程的 GridView 示例中显示此类信息。

GridView 提供的相同 TemplateFields 功能也可用于 DetailsView 控件。 在本教程中,我们将使用包含两个 TemplateField 的 DetailsView 一次显示一个产品。 第一个 TemplateField 会将 、 UnitsInStock和数据UnitsOnOrder字段合并UnitPrice为一个 DetailsView 行。 第二个 TemplateField 将显示字段的值Discontinued,但如果 为 True,则使用格式设置方法显示“YESDiscontinued”,否则将显示“NO”。

两个 TemplateField 用于自定义显示

图 1:两个 TemplateField 用于自定义显示 (单击以查看全尺寸图像)

现在就开始吧!

步骤 1:将数据绑定到 DetailsView

如上一教程中所述,使用 TemplateFields 时,通常最简单的方法是创建仅包含 BoundFields 的 DetailsView 控件,然后添加新的 TemplateFields 或根据需要将现有 BoundField 转换为 TemplateFields。 因此,请首先通过 Designer 将 DetailsView 添加到页面,并将其绑定到返回产品列表的 ObjectDataSource。 这些步骤将为每个产品的非布尔值字段创建带有 BoundFields 的 DetailsView,并为一个布尔值字段创建一个 CheckBoxField, (已停用) 。

打开页面并将DetailsViewTemplateField.aspx“详细信息”视图从“工具箱”拖到Designer。 从 DetailsView 的智能标记中,选择添加调用 ProductsBLL 类的 GetProducts() 方法的新 ObjectDataSource 控件。

添加调用 GetProducts () 方法的新 ObjectDataSource 控件

图 2:添加一个新的 ObjectDataSource 控件,该控件调用 GetProducts() 方法 (单击以查看全尺寸图像)

对于此报表, ProductID请删除 、 SupplierIDCategoryIDReorderLevel BoundFields。 接下来,对 BoundField 进行重新排序, CategoryName 使 和 SupplierName BoundField 紧跟在 BoundField 之后 ProductName 。 根据需要随意调整 HeaderText BoundFields 的属性和格式设置属性。 与 GridView 一样,可以通过“字段”对话框执行这些 BoundField 级别的编辑, (单击 DetailsView 的智能标记中的“编辑字段”链接) 或通过声明性语法进行访问。 最后,清除 DetailsView 的 HeightWidth 属性值,以便根据显示的数据扩展 DetailsView 控件,并检查智能标记中的“启用分页”复选框。

进行这些更改后,DetailsView 控件的声明性标记应如下所示:

<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True"
    EnableViewState="False">
    <Fields>
        <asp:BoundField DataField="ProductName" HeaderText="Product"
          SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category"
          ReadOnly="True" SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="Supplier"
          ReadOnly="True" SortExpression="SupplierName" />
        <asp:BoundField DataField="QuantityPerUnit"
          HeaderText="Qty/Unit" SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice" HeaderText="Price"
          SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock"
          HeaderText="Units In Stock" SortExpression="UnitsInStock" />
        <asp:BoundField DataField="UnitsOnOrder"
          HeaderText="Units On Order" SortExpression="UnitsOnOrder" />
        <asp:CheckBoxField DataField="Discontinued"
          HeaderText="Discontinued" SortExpression="Discontinued" />
    </Fields>
</asp:DetailsView>

花点时间通过浏览器查看页面。 此时,应会看到一个产品 (Chai) 列出,其中行显示产品的名称、类别、供应商、价格、库存单位、订单数量及其停产状态。

使用一系列 BoundFields 显示产品的详细信息

图 3:使用一系列 BoundFields 显示产品的详细信息 (单击查看全尺寸图像)

步骤 2:将“价格”、“库存单位”和“订单单位”合并为一行

DetailsView 有一行用于 UnitPriceUnitsInStockUnitsOnOrder 字段。 可以通过添加新 TemplateField 或将现有 UnitPriceUnitsInStockUnitsOnOrder BoundField 之一转换为 TemplateField,将这些数据字段合并为单个行。 虽然我个人更喜欢转换现有的 BoundField,但让我们通过添加新的 TemplateField 来练习。

首先,单击 DetailsView 的智能标记中的“编辑字段”链接,打开“字段”对话框。 接下来,添加新的 TemplateField 并将其 HeaderText 属性设置为“Price and Inventory”,并移动新的 TemplateField,使其位于 BoundField 上方 UnitPrice

向 DetailsView 控件添加新 TemplateField

图 4:将新 TemplateField 添加到 DetailsView 控件 (单击以查看全尺寸图像)

由于此新 TemplateField 将包含 、 和 UnitsOnOrder BoundFields 中UnitPriceUnitsInStock当前显示的值,因此让我们删除它们。

此步骤的最后一个任务是定义 ItemTemplate Price 和 Inventory TemplateField 的标记,这可以通过Designer中的 DetailsView 模板编辑界面来完成,也可以手动通过控件的声明性语法来完成。 与 GridView 一样,可以通过单击智能标记中的“编辑模板”链接来访问 DetailsView 的模板编辑界面。 在此处,可以从下拉列表选择要编辑的模板,然后从“工具箱”添加任何 Web 控件。

在本教程中,首先将 Label 控件添加到 Price 和 Inventory TemplateField 的 ItemTemplate。 接下来,单击 Label Web 控件的智能标记中的“编辑数据绑定”链接,并将 Text 属性绑定到 字段 UnitPrice

将标签的文本属性绑定到 UnitPrice 数据字段

图 5:将标签的 Text 属性绑定到 UnitPrice 数据字段 (单击以查看全尺寸图像)

将价格格式设置为货币

添加此项后,标签 Web 控件“价格”和“库存模板字段”现在仅显示所选产品的价格。 图 6 显示了通过浏览器查看到目前为止的进度的屏幕截图。

“价格和库存模板”字段显示价格

图 6:“价格和库存模板”字段显示“价格” (单击以查看全尺寸图像)

请注意,产品的价格未格式化为货币。 使用 BoundField 时,通过将 属性设置为 ,DataFormatString{0:formatSpecifier}将 属性设置为 HtmlEncodeFalse 可以进行格式设置。 但是,对于 TemplateField,任何格式设置说明都必须在数据绑定语法中指定,或者通过使用在应用程序代码 ((如 ASP.NET 页的代码隐藏类) 中)中定义的格式设置方法。

若要指定标签 Web 控件中使用的数据绑定语法的格式,请从标签的智能标记中单击“编辑数据绑定”链接,返回到“数据绑定”对话框。 可以直接在“格式”下拉列表中键入格式设置说明,也可以选择已定义的格式字符串之一。 与 BoundField 的 DataFormatString 属性一样,使用 指定 {0:formatSpecifier}格式设置。

对于字段, UnitPrice 请使用指定的货币格式,方法是选择相应的下拉列表值或通过手动键入 {0:C}

将价格格式设置为货币

图 7:将价格格式化为货币 (单击以查看全尺寸图像)

以声明方式将格式规范指示为 或 Eval 方法中的第二个参数Bind。 刚通过 Designer设置会导致声明性标记中出现以下数据绑定表达式:

<asp:Label ID="Label1" runat="server" Text='<%# Eval("UnitPrice", "{0:C}") %>'/>

将剩余数据字段添加到 TemplateField

此时,我们已在“价格”和“库存模板”字段中显示数据字段并设置了 UnitPrice 格式,但仍需要显示 UnitsInStockUnitsOnOrder 字段。 让我们在价格下方的一行和括号中显示这些内容。 在Designer的模板编辑界面中,可以通过将光标置于模板中并键入要显示的文本来添加此类标记。 或者,可以直接在声明性语法中输入此标记。

添加静态标记、标签 Web 控件和数据绑定语法,使价格和库存模板字段显示价格和库存信息,如下所示:

UnitPrice
(库存/订单中:UnitsInStock / UnitsOnOrder)

执行此任务后,DetailsView 的声明性标记应如下所示:

<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True"
    EnableViewState="False">
    <Fields>
        <asp:BoundField DataField="ProductName"
          HeaderText="Product" SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category"
          ReadOnly="True" SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName"
          HeaderText="Supplier" ReadOnly="True"
          SortExpression="SupplierName" />
        <asp:BoundField DataField="QuantityPerUnit"
          HeaderText="Qty/Unit" SortExpression="QuantityPerUnit" />
        <asp:TemplateField HeaderText="Price and Inventory">
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server"
                  Text='<%# Eval("UnitPrice", "{0:C}") %>'></asp:Label>
                <br />
                <strong>
                (In Stock / On Order: </strong>
                <asp:Label ID="Label2" runat="server"
                  Text='<%# Eval("UnitsInStock") %>'></asp:Label>
                <strong>/</strong>
                <asp:Label ID="Label3" runat="server"
                  Text='<%# Eval("UnitsOnOrder") %>'>
                </asp:Label><strong>)</strong>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:CheckBoxField DataField="Discontinued"
           HeaderText="Discontinued" SortExpression="Discontinued" />
    </Fields>
</asp:DetailsView>

通过这些更改,我们已将价格和库存信息合并到单个 DetailsView 行中。

价格和库存信息显示在单个行中

图 8:价格和库存信息显示在单行 (单击以查看全尺寸图像)

步骤 3:自定义已停用的字段信息

ProductsDiscontinued 列是一个位值,指示产品是否已停产。 将 DetailsView (或 GridView) 绑定到数据源控件时,布尔值字段(如 Discontinued)实现为 CheckBoxFields,而非布尔值字段(如 ProductIDProductName等)实现为 BoundFields。 如果数据字段的值为 True,则 CheckBoxField 呈现为禁用的复选框,否则将选中该复选框。

与其显示 CheckBoxField,不如显示指示产品是否停产的文本。 为此,我们可以从 DetailsView 中删除 CheckBoxField,然后添加属性设置为 DiscontinuedDataField BoundField。 花点时间执行此操作。 此更改后,对于已停用的产品,DetailsView 将显示文本“True”,对于仍处于活动状态的产品,则显示文本“False”。

字符串 True 和 False 用于显示已停止状态

图 9:字符串 True 和 False 用于显示停用状态 (单击以查看全尺寸图像)

假设我们不希望使用字符串“True”或“False”,而是使用“YES”和“NO”。 可以在 TemplateField 和格式设置方法的帮助下执行此类自定义。 格式设置方法可以采用任意数量的输入参数,但必须将 HTML (作为字符串返回,) 注入到模板中。

将格式设置方法添加到DetailsViewTemplateField.aspx页面的代码隐藏类中,该类接受DisplayDiscontinuedAsYESorNONorthwind.ProductsRow对象作为输入参数并返回字符串。 如上一教程中所述, 必须Protected 此方法标记为 或 Public 才能从模板访问。

Protected Function DisplayDiscontinuedAsYESorNO(discontinued As Boolean) As String
    If discontinued Then
        Return "YES"
    Else
        Return "NO"
    End If
End Function

此方法检查输入参数 (discontinued) ,如果为 True,则返回“YES”,否则返回“NO”。

注意

在上一教程中介绍的格式设置方法中,我们传入了可能包含 NULL 的数据字段,因此需要在访问 EmployeesRowHiredDate 的 属性之前检查员工的HiredDate属性值是否具有数据库NULL值。 此处不需要此类检查,Discontinued因为该列永远不会分配数据库NULL值。 此外,这就是为什么 方法可以接受布尔输入参数,而不必接受 ProductsRow 实例或类型的 Object参数。

完成此格式设置方法后,剩下的就是从 TemplateField 的 ItemTemplate调用它。 若要创建 TemplateField, Discontinued 请删除 BoundField 并添加新的 TemplateField 或将 Discontinued BoundField 转换为 TemplateField。 然后,从声明性标记视图中编辑 TemplateField,使其仅包含一个调用 DisplayDiscontinuedAsYESorNO 方法的 ItemTemplate,并传入当前 ProductRow 实例的 Discontinued 属性的值。 这可以通过 方法进行访问 Eval 。 具体而言,TemplateField 的标记应如下所示:

<asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
    <ItemTemplate>
        <%#DisplayDiscontinuedAsYESorNO(Convert.ToBoolean(Eval("Discontinued")))%> 
    </ItemTemplate>
</asp:TemplateField>

这将导致在 DisplayDiscontinuedAsYESorNO 呈现 DetailsView 时调用 方法,并 ProductRow 传入实例的值 DiscontinuedEval由于 方法返回类型的Object值,但DisplayDiscontinuedAsYESorNO该方法需要类型的Boolean输入参数,因此我们将方法返回值强制转换为 EvalBoolean。 然后,方法 DisplayDiscontinuedAsYESorNO 将返回“YES”或“NO”,具体取决于它收到的值。 返回的值是此 DetailsView 行中显示的值, (请参阅图 10) 。

“是”或“否”值现在显示在“停用行”中

图 10:“是”或“否”值现在显示在“已停用的行” (单击以查看全尺寸图像)

总结

与其他字段控件相比,DetailsView 控件中的 TemplateField 在显示数据方面具有更高的灵活性,非常适合以下情况:

  • 需要在一个 GridView 列中显示多个数据字段
  • 最好使用 Web 控件而不是纯文本来表示数据
  • 输出取决于基础数据,例如显示元数据或重新格式化数据

虽然 TemplateFields 允许在呈现 DetailsView 的基础数据时具有更大的灵活性,但 DetailsView 输出仍然有点开箱,因为每个字段都呈现为 HTML <table>中的一行。

FormView 控件在配置呈现的输出方面提供了更大的灵活性。 FormView 不包含字段,而只包含一系列 (ItemTemplate、、 EditItemTemplateHeaderTemplate等) 模板。 在下一教程中,我们将了解如何使用 FormView 实现对呈现布局的更多控制。

编程快乐!

关于作者

斯科特·米切尔是七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自 1998 年以来一直在使用 Microsoft Web 技术。 Scott 担任独立顾问、培训师和作家。 他的最新一本书是 山姆斯在 24 小时内 ASP.NET 2.0。 可以在 上mitchell@4GuysFromRolla.com联系他,也可以通过他的博客(可在 中找到http://ScottOnWriting.NET)。

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的首席审阅者是 Dan Jagers。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处mitchell@4GuysFromRolla.com放置一行。