基于数据设置 DataList 和 Repeater 的格式 (C#)

作者 :Scott Mitchell

下载 PDF

在本教程中,我们将逐步说明如何设置 DataList 和 Repeater 控件的外观格式,方法是在模板中使用格式设置函数或通过处理 DataBound 事件。

简介

正如我们在前面的教程中看到的,DataList 提供了许多与样式相关的属性,这些属性会影响其外观。 具体而言,我们了解了如何将默认 CSS 类分配给 DataList 的 HeaderStyleItemStyleAlternatingItemStyleSelectedItemStyle 属性。 除了这四个属性之外,DataList 还包括许多其他与样式相关的属性,例如 FontForeColorBackColorBorderWidth,仅举几例。 Repeater 控件不包含任何与样式相关的属性。 任何此类样式设置都必须直接在 Repeater 模板中的标记中进行。

但是,数据的格式通常取决于数据本身。 例如,在列出产品时,如果产品已停产,我们可能希望以浅灰色字体颜色显示产品信息;如果值为零,则可能需要突出显示 UnitsInStock 该值。 正如我们在前面的教程中看到的,GridView、DetailsView 和 FormView 提供了两种不同的方法来根据数据设置其外观格式:

  • 事件DataBound为相应的DataBound事件创建事件处理程序,该处理程序在数据绑定到每个项后触发, (GridView RowDataBound 是事件;对于 DataList 和 Repeater,它是ItemDataBound事件) 。 在该事件处理程序中,可以检查刚刚绑定的数据并做出格式设置决策。 我们在 基于数据的自定义格式 设置教程中介绍了此方法。
  • 当在 DetailsView 或 GridView 控件中使用 TemplateFields 或 FormView 控件中的模板时,我们可以将格式设置函数添加到 ASP.NET 页的代码隐藏类、业务逻辑层或可从 Web 应用程序访问的任何其他类库。 此格式设置函数可以接受任意数量的输入参数,但必须返回要在模板中呈现的 HTML。 首先在 GridView 控件教程中使用 TemplateFields 中 检查了格式设置函数。

这两种格式设置方法都可用于 DataList 和 Repeater 控件。 在本教程中,我们将逐步演示这两种技术用于这两种控件的示例。

使用ItemDataBound事件处理程序

将数据绑定到 DataList 时,无论是从数据源控件或通过以编程方式将数据分配给控件 的 DataSource 属性并调用其 DataBind() 方法,都会触发 DataList 事件 DataBinding ,枚举数据源,并且每个数据记录都绑定到 DataList。 对于数据源中的每条记录,DataList 将创建一个 DataListItem 对象,该对象随后绑定到当前记录。 在此过程中,DataList 会引发两个事件:

  • ItemCreated 创建 后 DataListItem 引发
  • ItemDataBound 在当前记录绑定到 后触发 DataListItem

以下步骤概述了 DataList 控件的数据绑定过程。

  1. DataList 事件DataBinding触发

  2. 数据绑定到 DataList

    对于数据源中的每条记录

    1. 创建 DataListItem 对象
    2. 触发 ItemCreated 事件
    3. 将记录绑定到 DataListItem
    4. 触发 ItemDataBound 事件
    5. DataListItem 添加到 Items 集合

将数据绑定到 Repeater 控件时,它会执行完全相同的步骤序列。 唯一的区别是, DataListItem Repeater 使用 RepeaterItem不是正在创建的实例。

注意

精明的读取器可能已注意到在 DataList 和 Repeater 绑定到数据与 GridView 绑定到数据时出现的步骤序列之间存在轻微异常。 在数据绑定过程的结尾,GridView 引发 DataBound 事件;但是,DataList 和 Repeater 控件都没有此类事件。 这是因为 DataList 和 Repeater 控件是在 ASP.NET 1.x 时间范围中创建的,在前级别和后级别事件处理程序模式变得常见之前。

与 GridView 一样,基于数据进行格式设置的一个选项是为事件创建事件处理程序 ItemDataBound 。 此事件处理程序将检查刚刚绑定到 DataListItemRepeaterItem 的数据,并根据需要影响控件的格式设置。

对于 DataList 控件,可以使用与样式相关的属性(包括标准 Font、、ForeColorCssClassBackColor、 等)实现DataListItem整个项的格式设置更改。 若要影响 DataList 模板中特定 Web 控件的格式设置,我们需要以编程方式访问和修改这些 Web 控件的样式。 在 基于数据的自定义格式 设置教程中,我们了解了如何完成此操作。 与 Repeater 控件一样, RepeaterItem 类没有与样式相关的属性;因此,对事件处理程序中的 ItemDataBound 所做的RepeaterItem所有与样式相关的更改都必须通过以编程方式访问和更新模板中的 Web 控件来完成。

ItemDataBound由于 DataList 和 Repeater 的格式设置技术几乎完全相同,我们的示例将重点介绍如何使用 DataList。

步骤 1:在 DataList 中显示产品信息

在担心格式设置之前,让我们先创建一个使用 DataList 显示产品信息的页面。 在 上一教程中 ,我们创建了一个 DataList,其中 ItemTemplate 显示了每个产品的名称、类别、供应商、每个单位的数量和价格。 让我们在本教程中重复此功能。 为此,可以从头开始重新创建 DataList 及其 ObjectDataSource,也可以从上一教程中创建的页面复制这些控件, (Basics.aspx) 并将其粘贴到本教程 (Formatting.aspx) 的页面。

将 DataList 和 ObjectDataSource 功能从 Basics.aspx 复制到 后,请花点时间将 DataList 的 ID 属性从 DataList1 更改为更具描述性的 ItemDataBoundFormattingExampleFormatting.aspx。 接下来,在浏览器中查看 DataList。 如图 1 所示,每种产品之间的唯一格式差异是背景色交替。

产品在 DataList 控件中列出

图 1:产品列在 DataList 控件 (单击以查看全尺寸图像)

在本教程中,让我们设置 DataList 的格式,使价格低于 20.00 美元的任何产品的名称和单价都突出显示为黄色。

步骤 2:以编程方式确定 ItemDataBound 事件处理程序中的数据值

由于只有价格低于 20.00 美元的产品才会应用自定义格式,因此我们必须能够确定每个产品的价格。 将数据绑定到 DataList 时,DataList 枚举其数据源中的记录,并为每个记录创建一个 DataListItem 实例,将数据源记录 DataListItem绑定到 。 将特定记录的数据绑定到当前 DataListItem 对象后,将触发 DataList 事件 ItemDataBound 。 我们可以为此事件创建事件处理程序来检查当前 DataListItem 的数据值,并根据这些值进行必要的格式设置更改。

为 DataList 创建事件 ItemDataBound 并添加以下代码:

protected void ItemDataBoundFormattingExample_ItemDataBound
    (object sender, DataListItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Item ||
        e.Item.ItemType == ListItemType.AlternatingItem)
    {
        // Programmatically reference the ProductsRow instance bound
        // to this DataListItem
        Northwind.ProductsRow product =
            (Northwind.ProductsRow)((System.Data.DataRowView)e.Item.DataItem).Row;
        // See if the UnitPrice is not NULL and less than $20.00
        if (!product.IsUnitPriceNull() && product.UnitPrice < 20)
        {
            // TODO: Highlight the product's name and price
        }
    }
}

虽然 DataList ItemDataBound 事件处理程序背后的概念和语义与基于数据的自定义格式设置教程中 GridView 事件处理程序RowDataBound使用的概念和语义相同,但语法略有不同。 当 事件触发时 ItemDataBoundDataListItem 刚绑定到数据的 将通过 e.Item (而不是 e.Row传递到相应的事件处理程序中,就像 GridView 事件处理程序 RowDataBound) 一样。 DataList 事件处理程序 ItemDataBound 针对添加到 DataList 的每 一行触发,包括页眉行、页脚行和分隔符行。 但是,产品信息仅绑定到数据行。 因此,使用 ItemDataBound 事件检查绑定到 DataList 的数据时,需要首先确保重新处理数据项。 这可以通过检查 DataListItem属性ItemType来实现,该属性可以具有以下八个值之一:

  • AlternatingItem
  • EditItem
  • Footer
  • Header
  • Item
  • Pager
  • SelectedItem
  • Separator

AlternatingItem``DataListItem 构成 Item DataList 的数据项。 假设我们使用 ItemAlternatingItem,我们将访问绑定到当前 DataListItem的实际ProductsRow实例。 DataListItem s DataItem 属性包含对 DataRowView 对象的引用,该Row对象的 属性提供对实际ProductsRow对象的引用。

接下来,我们检查 ProductsRow 实例 的 UnitPrice 属性。 由于 Products 表 的 UnitPrice 字段允许NULL值,因此在尝试访问 UnitPrice 属性之前,应首先检查,以便使用 IsUnitPriceNull() 方法查看它是否具有NULL值。 UnitPrice如果值不NULL为 ,则检查查看该值是否小于 20.00 美元。 如果确实低于 20.00 美元,则需要应用自定义格式。

步骤 3:突出显示产品名称和价格

一旦我们知道某个产品的价格低于 20.00 美元,剩下的就是突出其名称和价格。 为此,我们必须首先以编程方式引用 中 ItemTemplate 显示产品名称和价格的 Label 控件。 接下来,我们需要让它们显示黄色背景。 可以通过直接修改标签 BackColor 属性 (LabelID.BackColor = Color.Yellow) 来应用此格式设置信息;理想情况下,所有与显示相关的事项都应通过级联样式表来表示。 事实上,我们已经有一个样式表,该样式表提供在 中 Styles.css - AffordablePriceEmphasis定义的所需格式,该格式是在 基于数据的自定义格式 教程中创建和讨论的。

若要应用格式设置,只需将两个 Label Web 控件 CssClass 属性设置为 AffordablePriceEmphasis,如以下代码所示:

// Highlight the product name and unit price Labels
// First, get a reference to the two Label Web controls
Label ProductNameLabel = (Label)e.Item.FindControl("ProductNameLabel");
Label UnitPriceLabel = (Label)e.Item.FindControl("UnitPriceLabel");
// Next, set their CssClass properties
if (ProductNameLabel != null)
    ProductNameLabel.CssClass = "AffordablePriceEmphasis";
if (UnitPriceLabel != null)
    UnitPriceLabel.CssClass = "AffordablePriceEmphasis";

ItemDataBound事件处理程序完成后,在浏览器中重新访问Formatting.aspx页面。 如图 2 所示,价格低于 20.00 美元的产品的名称和价格均突出显示。

突出显示了低于 $20.00 的产品

图 2:突出显示了那些低于 20.00 美元的产品 (单击以查看全尺寸图像)

注意

由于 DataList 呈现为 HTML <table>,因此其 DataListItem 实例具有样式相关的属性,这些属性可以设置为将特定样式应用于整个项。 例如,如果我们想要在价格低于 20.00 美元时突出显示 整个 黄色项目,我们可以替换引用标签的代码,并使用以下代码行设置其 CssClass 属性: e.Item.CssClass = "AffordablePriceEmphasis" (见图 3) 。

RepeaterItem但是,构成 Repeater 控件的 不提供此类样式级属性。 因此,将自定义格式应用于 Repeater 需要向 Repeater 模板中的 Web 控件应用样式属性,就像我们在图 2 中所做的那样。

针对低于 $20.00 的产品突出显示整个产品项

图 3:对于低于 20.00 美元的产品,“整个产品项”突出显示 (单击以查看全尺寸图像)

在模板中使用格式设置函数

GridView 控件中使用 TemplateFields 教程中,我们了解了如何使用 GridView TemplateField 中的格式设置函数基于绑定到 GridView s 行的数据应用自定义格式。 格式设置函数是一种可从模板调用的方法,并返回要在其位置发出的 HTML。 格式设置函数可以驻留在 ASP.NET 页的代码隐藏类中 App_Code ,也可以集中到文件夹或单独的类库项目中的类文件中。 如果计划在多个 ASP.NET 页面或其他 ASP.NET Web 应用程序中使用相同的格式设置函数,则最好将格式设置函数移出 ASP.NET 页的代码隐藏类。

为了演示格式设置功能,让我们让产品信息包括产品名称旁边的文本 [DISCONTINUED](如果已停用)。 此外,如果价格低于 $20.00 (,则让我们将价格突出显示为黄色,如我们在事件处理程序示例) 中所做的那样 ItemDataBound ;如果价格为 20.00 美元或更高,则不显示实际价格,而是显示文本,请调用报价单。 图 4 显示了应用了这些格式规则的产品列表的屏幕截图。

显示 DataList 控件中列出的产品的屏幕截图,其中产品价格超过 20.00 美元,替换为文本“请调用报价单”。

图 4:对于昂贵产品,价格替换为文本,请调用报价单 (单击以查看全尺寸图像)

步骤 1:创建格式设置函数

对于此示例,我们需要两个格式设置函数,一个显示产品名称以及文本 [DISCONTINUED](如果需要),另一个显示突出显示的价格(如果低于 $20.00),或文本,否则请调用报价单。 让我们在 ASP.NET 页代码隐藏类中创建这些函数,并将其命名为 DisplayProductNameAndDiscontinuedStatusDisplayPrice。 这两种方法都需要返回 HTML 才能呈现为字符串,并且两种方法都需要标记为 Protected (或 Public) ,以便从 ASP.NET 页声明性语法部分调用。 以下为这两种方法的代码:

protected string DisplayProductNameAndDiscontinuedStatus
    (string productName, bool discontinued)
{
    // Return just the productName if discontinued is false
    if (!discontinued)
        return productName;
    else
        // otherwise, return the productName appended with the text "[DISCONTINUED]"
        return string.Concat(productName, " [DISCONTINUED]");
}
protected string DisplayPrice(Northwind.ProductsRow product)
{
    // If price is less than $20.00, return the price, highlighted
    if (!product.IsUnitPriceNull() && product.UnitPrice < 20)
        return string.Concat("<span class=\"AffordablePriceEmphasis\">",
                              product.UnitPrice.ToString("C"), "</span>");
    else
        // Otherwise return the text, "Please call for a price quote"
        return "<span>Please call for a price quote</span>";
}

请注意,DisplayProductNameAndDiscontinuedStatus方法接受 和 discontinued 数据字段的值productName作为标量值,而DisplayPrice该方法接受ProductsRow实例 (而不是unitPrice标量值) 。 两种方法都行之一:但是,如果格式化函数正在处理可以包含数据库 NULL 值的标量值 (,例如 UnitPrice;既不允许 ProductNameDiscontinuedNULL 值) ,则必须在处理这些标量输入时特别小心。

特别是,输入参数的类型必须为 , Object 因为传入值可能是 DBNull 实例,而不是预期的数据类型。 此外,必须进行检查以确定传入值是否为数据库NULL值。 也就是说,如果我们希望 DisplayPrice 方法接受 price 作为标量值,则必须使用以下代码:

protected string DisplayPrice(object unitPrice)
{
    // If price is less than $20.00, return the price, highlighted
    if (!Convert.IsDBNull(unitPrice) && ((decimal) unitPrice) < 20)
        return string.Concat("<span class=\"AffordablePriceEmphasis\">",
                              ((decimal) unitPrice).ToString("C"), "</span>");
    else
        // Otherwise return the text, "Please call for a price quote"
        return "<span>Please call for a price quote</span>";
}

请注意, unitPrice 输入参数的类型为 Object ,条件语句已修改,以确定是否 unitPriceDBNull 。 此外,由于 unitPrice 输入参数作为 Object传入,因此必须将其强制转换为十进制值。

步骤 2:从 DataList s ItemTemplate 调用格式化函数

将格式设置函数添加到 ASP.NET 页代码隐藏类中,剩下的就是从 DataList 中 ItemTemplate调用这些格式设置函数。 若要从模板调用格式化函数,请将函数调用置于数据绑定语法中:

<%# MethodName(inputParameter1, inputParameter2, ...) %>

在 DataList 中,ItemTemplateProductNameLabel标签 Web 控件当前通过分配其Text属性的结果<%# Eval("ProductName") %>来显示产品的名称。 若要使其显示名称加上文本 [DISCONTINUED],请根据需要更新声明性语法,使其改为向 Text 属性分配 方法的值 DisplayProductNameAndDiscontinuedStatus 。 执行此操作时,必须使用 语法传入产品名称和停用的值 Eval("columnName")Eval 返回类型的 Object值,但 DisplayProductNameAndDiscontinuedStatus 方法需要 类型 String 为 和 Boolean的输入参数;因此,我们必须将 方法返回 Eval 的值转换为预期的输入参数类型,如下所示:

<h4>
    <asp:Label ID="ProductNameLabel" runat="server"
        Text='<%# DisplayProductNameAndDiscontinuedStatus((string) Eval("ProductName"),
              (bool) Eval("Discontinued")) %>'>
    </asp:Label>
</h4>

若要显示价格,只需将 UnitPriceLabel Label s Text 属性设置为 方法返回 DisplayPrice 的值,就像在显示产品名称和 [DISCONTINUED] 文本时所做的那样。 但是,我们不是将 作为标量输入参数传入 UnitPrice ,而是传入整个 ProductsRow 实例:

<asp:Label ID="UnitPriceLabel" runat="server"
    Text='<%# DisplayPrice((Northwind.ProductsRow)
          ((System.Data.DataRowView) Container.DataItem).Row) %>'>
</asp:Label>

调用格式设置函数后,请花点时间在浏览器中查看进度。 你的屏幕应类似于图 5,停产的产品包括文本 [DISCONTINUED] 和那些价格超过 $20.00 的产品,其价格替换为文本请调用报价单 。

显示 DataList 控件中列出的产品的屏幕截图,其中产品价格超过 20.00 美元,替换为文本“请调用报价单”,并将文本“[DISCONTINUED]”追加到停产产品的名称。

图 5:对于昂贵产品,价格替换为文本,请调用报价单 (单击以查看全尺寸图像)

总结

可以使用两种方法来完成基于数据设置 DataList 或 Repeater 控件内容的格式。 第一种方法是为 事件创建事件处理程序 ItemDataBound ,当数据源中的每条记录绑定到新的 DataListItemRepeaterItem时,该事件处理程序将触发。 在 ItemDataBound 事件处理程序中,可以检查当前项的数据,然后可以将格式应用于模板的内容或 DataListItem 整个项本身。

或者,可以通过格式设置函数实现自定义格式设置。 格式设置函数是从 DataList 或 Repeater 的模板调用的方法,该方法返回要在其位置发出的 HTML。 通常,格式设置函数返回的 HTML 由绑定到当前项的值确定。 这些值可以作为标量值或通过传入要绑定到项的整个对象 ((例如 ProductsRow 实例) )传递到格式设置函数中。

编程快乐!

关于作者

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

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是雅科夫·埃利斯、兰迪·施密特和 Liz Shulok。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处mitchell@4GuysFromRolla.com放置一行。