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

作者 :斯科特·米切尔

下载 PDF

在本教程中,我们将逐步讲解如何设置 DataList 和 Repeater 控件的外观格式的示例,无论是在模板中使用格式设置函数还是处理 DataBound 事件。

介绍

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

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

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

DataList 和 Repeater 控件提供了这两种格式设置技术。 在本教程中,我们将逐步介绍使用这两种控件的方法的示例。

使用ItemDataBound事件处理器

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

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

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

  1. DataListDataBinding事件触发

  2. 数据被绑定到 DataList

    对于数据源中的每条记录

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

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

注释

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

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

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

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

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

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

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

产品在 DataList 控件中列出

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

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

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

由于只有价格低于 $20.00 的产品才会应用自定义格式,因此我们必须能够确定每个产品的价格。 将数据绑定到 DataList 时,DataList 会枚举其数据源中的记录,并为每个记录创建一个 DataListItem 实例,将数据源记录绑定到该 DataListItem记录。 将特定记录的数据绑定到当前 DataListItem 对象后,将触发 DataList s 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自定义格式基于数据 教程中使用的概念和语义相同,但语法略有不同。 ItemDataBound事件触发时,刚绑定到数据的DataListItem通过e.Item传递到相应的事件处理程序中,而不是像GridView的RowDataBound事件处理程序通过e.Row一样。 DataList 的 ItemDataBound 事件处理程序会针对添加到 DataList 的每一行触发,其中包括页眉行、页脚行和分隔符行。 但是,产品信息仅绑定到数据行。 因此,使用 ItemDataBound 事件检查绑定到 DataList 的数据时,首先需要确保我们正在处理一个数据项。 这可以通过检查 DataListItem s ItemType 属性来实现,该属性可以具有以下 八个值之一:

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

ItemAlternatingItem``DataListItem共同组成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中所需的格式。这些格式是在基于数据的自定义格式教程中创建并讨论的。

若要应用格式设置,只需将两个标签 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 控件的 s 不提供此类样式级别属性。 因此,将自定义格式应用于 Repeater 需要将样式属性应用于 Repeater 模板中的 Web 控件,就像我们在图 2 中所做的那样。

价格低于 20.00 美元的产品中,整个产品项目都被突出显示

图 3:20.00 美元以下产品的整个产品项突出显示(单击以查看全尺寸图像

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

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

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

显示 DataList 控件中列出的产品的屏幕截图,其中价格超过 20.00 美元的产品,其价格被替换为文本“请致电获取价格”。

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

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

对于此示例,我们需要两个格式化函数:一个用于显示产品名称以及文本 “[已停产]”(如果需要),另一个则在价格低于 $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该方法接受数据字段的值productNamediscontinued作为标量值,而DisplayPrice该方法接受ProductsRow实例(而不是unitPrice标量值)。 任一方法都可能起作用;但是,如果格式功能处理可包含数据库 NULL 值的标量值(例如 UnitPriceProductNameDiscontinued 都不允许 NULL 值),则必须特别注意处理这些标量输入。

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

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类型,并且条件语句已被修改,以确定unitPrice是否是DBNull。 此外,由于 unitPrice 输入参数作为 Object 传入,因此必须将其强制转换为十进制值。

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

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

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

ItemTemplate DataList 中,ProductNameLabel标签 Web 控件当前通过将其Text属性设置为<%# Eval("ProductName") %>的结果来显示产品名称。 为了使其显示名称加上文本 [DISCONTINUED](如果需要),请更新声明性语法,以便改为将 Text 属性的值赋予 DisplayProductNameAndDiscontinuedStatus 方法。 在进行此操作时,必须使用Eval("columnName")语法传入产品名称和停用的值。 Eval返回的值是Object类型,但DisplayProductNameAndDiscontinuedStatus方法期望的输入参数为StringBoolean类型;因此,必须将Eval方法返回的值类型转换为预期的输入参数类型,如下所示:

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

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

<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 美元的,替换为文本“请致电询价”,并将文本“[已停产]”追加到已停产产品的名称。

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

概要

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

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

快乐编程!

关于作者

斯科特·米切尔,七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自1998年以来一直在与Microsoft Web 技术合作。 斯科特担任独立顾问、教练和作家。 他的最新书是 《Sams Teach Yourself ASP.NET 2.0 in 24 Hours》。 可以通过 mitchell@4GuysFromRolla.com 联系到他。

特别致谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是 Yaakov Ellis、Randy Schmidt 和 Liz Shulok。 有兴趣查看即将发布的 MSDN 文章? 如果是这样,请给我写信。mitchell@4GuysFromRolla.com