根据数据格式化 DataList 控件和 Repeater 控件30

简介

正如我们在前面教程中看到的那样,DataList 控件提供了许多与风格相关的属性,这些属性可以影响它的外观。我们还看到了如何为 DataList 控件的 HeaderStyle 、 ItemStyle 、 Alternating ItemStyle 和 Selected ItemStyle 属性分配默认的 CSS 类。除了这四个属性外,DataList 控件还包括许多其它的与风格相关的属性,例如 Font (字体)、 ForeColor (字体颜色)、 BackColor (背景颜色)和 BorderWidth (边界宽度)等。Repeater 控件不包含任何与风格相关的属性。任何风格设置必须直接通过 Repeater 空间模板中的标记来完成。

尽管这样,但是对于如何格式化数据常常是由数据本身决定的。例如,当编目产品列表时,我们可能想用浅灰色的颜色来显示断货的产品,或高亮显示值为零的 UnitsInStock 。正如我们在前面的教程中所看到的,GridView 控件、 DetailsView 控件和 FormView 控件根据它们数据的不同提供了两种不同的方法来格式化它们的外观:

  • DataBound事件— 为 DataBound 事件创建一个Event Handler ,DataBound 事件在数据被绑定到每一项后被触发(对于GridView 控件来说它是Row DataBound 事件;对于 DataList 控件和 Repeater 控件来说它是Item DataBound 事件)。在该 Event Handler中,可检验刚才被绑定的数据并确定格式化工作程序。在 基于数据自定义格式教程中我们研究了这种方法。
  • Formatting模板中的格式化函数 — 在 DetailsView 控件或 GridView 控件中使用TemplateFields 、或在 FormView 控件中使用模板时,我们可以为ASP.NET 页面的代码文件类添加一个格式化函数,业务逻辑层或者任何其它可以从Web 应用程序中访问的类库。这个格式化函数可以接受任意的输入参数,但是必须返回 HTML 以便在模板中进行解析。 在 GridView 控件中使用 TemplateField 教程中首次对格式化函数进行了研究。

这两种格式化技术 DataList 控件和 Repeater 控件都可以使用。在本教程中,我们将通过例子一步步的介绍这两个控件是如何使用这两种方法的。

使用Item DataBound Event Handler

您可以从一个数据源控件或通过编程为控件的DataSource 属性分配数据并调用其 DataBind() 方法,将数据绑定到DataList 控件中,绑定数据时 DataList 控件的DataBinding 事件被触发,数据源会逐一列举记录,每一条数据记录都会被绑定到 DataList 控件中。对于数据源中的每一条记录, DataList 会创建一个 DataList Item 对象,然后将该对象绑定到当前记录上。在这个过程中,DataList 控件会产生两个事件:

  • ItemCreated — DataList Item 创建之后被触发。
  • Item DataBound  — 当前记录被绑定到 DataList Item 后触发。

下面列出了DataList 控件绑定数据过程中的几个步骤:

  1. DataList 控件的 DataBinding 事件触发
  2. 数据源中每一条记录的数据绑定到 DataList 控件中
    1. 创建一个 DataList Item 对象
    2. 触发 ItemCreated 事件
    3. 将记录绑定到 DataList Item
    4. 触发 Item DataBound  事件
    5. 把 DataList Item 添加到条目集( Items collection )中。

当把数据绑定到 Repeater 控件时,它也需要按照同样的步骤顺序进行。唯一的区别就是不创建 DataList Item 实例,而是创建Repeater Item 实例,这是因为Repeater 控件使用 Repeater Item 。

注意:一些敏锐的读者可能已经注意到了DataList 控件和Repeater 控件在绑定数据时和GridView 控件绑定数据时在步骤顺序上的一些细微差别。在数据绑定的末尾, GridView 控件产生 DataBound 事件,然而 DataList 控件和 Repeater 控件都不会产生这样的事件。这是因为 DataList 控件和 Repeater 控件创建在 ASP.NET 1.x timeframe 之后,而之前 pre- and post-level Event Handler模型已经非常普遍。

和 GridView 控件一样,对于根据数据进行格式化,有一个选择就是为 Item DataBound 事件创建一个Event Handler 。该 Event Handler会检查已经绑定到 DataList Item 和 Repeater Item 上的数据,并根据需要作用于控件的格式化过程。

对于DataList 控件来说,要对整个条目进行格式化更改,可以使用  DataList Item 的与风格相关的属性来完成,这些属性包括:标准Font 、ForeColor、BackColor 和CssClass 等等。要影响 DataList 控件模板内的某个特定 Web 控件的格式化,我们需要通过编码来访问和修改这个 Web控件的风格。我们可以在基于数据自定义格式教程的后面部分看到如何完成这些操作。和 Repeater 一样, Repeater Item 类没有与风格相关的属性,所以在 Item DataBound Event Handler中对 Repeater Item 所做的与风格相关的更改都必须通过编码来访问并更新模板内的 Web 控件。

因为DataList 控件和 Repeater 控件的Item DataBound 格式化技术在本质上是一样的,所以我们的例子重点放在 DataList 控件的使用上。

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

在我们担心格式化之前,让我们首先创建一个页面,该页面使用DataList 控件来显示产品信息。在 前一篇教程 中,我们创建了一个 DataList 控件,该控件的 ItemTemplate 显示了每一个产品的 name (名称)、 category (类别)、 supplier (供应商)、 quantity per unit (每单元数量)和 price (价格)。在本教程中,我们再来实现这个功能。要完成这个功能,你可以选择重新创建 DataList 控件和它最开始的对象数据源( ObjectDataSource )或者从之前的教程( Basics.aspx )中创建的页面中复制这些控件,然后将其粘贴到本教程中的页面里( Formatting.aspx )。

将DataList 控件和 ObjectDataSource( 对象数据源) 功能从 Basics.aspx 页面复制到Formatting.aspx 页面后,花点时间将 DataList 控件的 ID 属性由 DataList 1 更改为描述性的 Item DataBound FormattingExample 。接下来在浏览器中浏览 DataList 控件。如图  1 所示,每一个产品的格式化差别仅仅在于背景色的变化。

图1 :列在 DataList 控件中的产品

对于本教程,我们对DataList 控件进行一些格式化操作,这样任何价格低于20 美元的产品的名称和单位价格都会被以黄色高亮显示.

步骤2 :通过编码确定DataBound Event Handler 中数据的值

因为只对价格低于 20 美元的产品应用格式化操作,所以我们必须能够确定每一种产品的价格。在将数据绑定到 DataList 控件时,DataList 控件逐条列举了它数据源中的每一条记录,并为每一条记录创建了一个  DataList Item 实例,然后将数据源记录绑定到 DataList Item 中。这个特定记录的数据被绑定到当前 DataList Item 对象后, DataList 控件的 Item DataBound 事件被触发。我们可以为这个事件创建一个 Event Handler,利用这个句柄为当前的 DataList Item 检查数据值,然后根据这些数据值再做一些任何必要的格式化更改。

为 DataList 控件创建一个Item DataBound 事件,并添加以下代码:

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 控件的Item DataBound Event Handler 用到的原理(concept) 和语义(semantics) 和在基于数据自定义格式教程中GridView 控件的Row DataBound Event Handler 用到的是相同的,只是语法有些轻微差别。Item DataBound 事件触发时,刚被绑定到数据的 DataList Item 通过 e.Item 被传递给相应的Event Handler(不是通过 e.Row 而是 GridView 控件的 Row DataBound Event Handler)。对于每一个添加到 DataList 控件的行,包括标题行、脚注行和分隔行, DataList 控件的 Item DataBound Event Handler都会触发。由于产品信息只绑定到数据行中,所以,当您使用 Item DataBound 事件来检查已绑定到 DataList 控件的数据时,我们首先需要确定我们正在作用于一个数据条目。通过检查 DataList Item 的 ItemType 属性 就可以做到这一点,其中ItemType 属性 包含一下 8 个值:

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

Item 和AlternatingItem 这两个 DataList Items 值组成了 DataList 控件的数据项。假设我们正在操作一个Item 或AlternatingItem ,那么我们访问的实际的ProductsRow 实例是绑定到当前 DataList Item 上的实例。 DataList Item 的 DataItem 属性 包含了一个DataRowView 对象的参照对象,DataRowView 对象会为实际的ProductsRow 对象提供一个参照对象。

接下来,检查 ProductsRow 实例的UnitPrice 属性。因为产品标签的 UnitPrice 字段的值允许为 NULL ,所以在试图访问 UnitPrice 属性之前,我们应该首先使用IsUnitPriceNull() 方法来检验一下是否为 NULL 值。UnitPrice 的值不为 NULL ,接下来我们在检查这个值是不是小于 20 美元,如果这个值确实小于 20 美元,那么我们就需要应用用户自定义的格式化操作。

步骤3 :高亮显示产品的名称和价格

一旦我们获知产品的价格低于 20 美元,那么接下来我们要做的就是高亮显示他的名称和价格。要实现这一点,我们必须首先通过编码核对显示产品名称和价格的 ItemTemplate 中的标签控件。接下来,我们需要将它们以黄色背景显示出来。可以直接通过修改标签控件的 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";

Item DataBound Event Handler 完成之后,在浏览器内重新访问 Formatting.aspx 页面。如图 2 所示,这些价格低于20 美元的产品的名字和价格都被高亮显示。

图2 :价格低于20 美元的产品被高亮显示

注意:因为 DataList 控件表现为 HTML 标签(<table>) ,所以它的 DataList Item 实例都拥有一个与风格相关的属性,可以设置这些属性将特定的风格应用到整个条目。例如,如果当产品的价格低于20 美元时,您想用黄色高亮显示整个产品条目,我们可以替换相关的代码,将其 CssClass 属性设置成下面这行代码 e.Item.CssClass = "AffordablePriceEmphasis" (请参见图 3 )。

然而,构成Repeater 控件的 Repeater Items 并不提供这样的风格属性。所以,要将用户自定义的格式化风格应用到 Repeater 控件,需要将风格属性应用到位于 Repeater 控件内的 Web 控件上,就像我们在图2 中所做的那样。

图3 :高亮显示价格低于20 美元的产品的整个产品条目

使用模板内的格式化函数

在GridView 控件中使用TemplateField 教程中,我们学会了如何使用位于GridView TemplateField 字段内的格式化函数,根据绑定到 GridView 控件行上的数据将应用用户自定义的格式化风格。格式化函数是一个方法,该方法可以从一个模板调用,并且会在它的位置上返回要输出的 HTML 。格式化函数可以放置在 ASP.NET 页面的代码文件类内,或集中到 App_Code 文件夹下的各个类文件中或放置在一个单独的类库项目中。如果想在多个 ASP.NET 页面或者在其它的 ASP.NET web 应用程序中使用相同的格式化函数,那么将该函数移出 ASP.NET 页面的代码文件类是非常明智的。

为了能够演示一下格式化函数,如果产品已经断货,那么我们应在产品的信息中包含 “[DISCONTINUED]” 字样,并使其紧挨产品的名称。同样,如果价格低于 20 美元,我们将价格用黄色高亮显示(如同我们在 Item DataBound Event Handler例子中所做的那样);如果价格是 20 美元或更高,就不显示实际的价格,而是显示“请致电询问报价”。图 4 所示的是应用了这些格式化规则的产品列表。

图4 :对于昂贵的产品,其价格被替换为“请致电查询报价”

步骤1 :创建格式化函数

对于本示例,我们需要两个格式化函数,一个用来显示产品的名称和“[DISCONTINUED]” 文本(如果需要的话),另一个用来高亮显示价格(如果价格低于20 美元)或 “请致电询问报价”( 如果价格不低于20 美元) 。首先我们要在 ASP.NET 页面的代码文件类中创建这两个函数,并将它们命名为: DisplayProductNameAndDiscontinuedStatus 和 DisplayPrice 。这两个方法都需要将 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 方法将产品名称和断货数据字段的值当作标量值使用,而DisplayPrice 方法使用ProductsRow 实例(而不是 unitPrice 标量值)。这两种方法都有效;但是如果该格式化函数使用包含数据库NULL 值的标量值时(例如UnitPrice ;ProductName 和 Discontinued 都不允许为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 控件的 ItemTemplate 中调用格式化函数

格式化函数添加到我们的 ASP.NET 页面的代码文件类后 , 剩下要做的就是从 DataList 控件的 ItemTemplate 中调用这些格式化函数。为了能够从模板中调用格式化函数,请使用下面的数据绑定语句进行函数调用:

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

DataList 控件的 ItemTemplate 中,ProductNameLabel Web 标签控件根据分配给它的文本属性显示产品的名称,显示结果是:<%# Eval("ProductName") %> 。 为了能够让它显示名称和 “[DISCONTINUED]” (如果需要的话),更新声明语句以便它为文本属性分配 DisplayProductNameAndDiscontinuedStatus 方法的值。如果要这样做,我们必须使用 Eval("columnName") 语句来传递产品的名称和断货产品值。 Eval 会返回一个对象类型,但是 DisplayProductNameAndDiscontinuedStatus 方法却期望输入参数的类型为 String 类型和 Boolean 类型,所以我们必须将 Eval 方法返回的值计算转换为期望的输入参数类型,像这样:

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

为了显示价格,我们可以简单的将 UnitPriceLabel Label 的文本属性设置为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 美元的产品它们的价格被替换为 “请致电查询报价”。

图5 :对于昂贵的产品,其价格被替换为“请致电查询报价”

小结

根据数据完成DataList 控件和 Repeater 控件内容的格式化有两种方法。第一种方法是为Item DataBound 事件(每当数据源中的一条数据被绑定到一个新的DataList Item 或 Repeater Item 中时,这个事件被触发)创建一个Event Handler , 在Item DataBound Event Handler 中,对当前条目的数据进行检验查,然后将格式化应用到模板的内容上或对DataList Items 来说应用到整个条目本身。

作为选择,用户自定义格式化可以通过格式化函数来实现。一个格式化函数就是一个方法,该方法可以从 DataList 控件或 Repeater 控件的模板(该模板会返回 HTML 以便在它的位置上输出)中调用。通常,格式化函数返回的 HTML 由绑定到当前条目上的数据决定。这些值可以传递给格式化函数,要么作为标量值传递,要么按绑定到条目的整个对象传递(例如 ProductsRow 实例)。

快乐编程!

posted @ 2016-05-01 23:07  迅捷之风  阅读(124)  评论(0编辑  收藏  举报