在ASP.NET 2.0中操作数据之三十:格式化DataList和Repeater的数据_自学过程

导言

  在前面的教程里我们学习了DataList提供了一些风格样式的属性.而且我们还学习了如何定义HeadStyle, ItemStyle, AlternatingItemStyle, 和SelectedItemStyle等属性的默认CSS.除了这四个属性外,DataList还提供了其它属性,比如Font, ForeColor, BackColor, 和BorderWidth.而Repeater没有提供任何这样的属性.如果你需要用Reperter来实现这些效果,你就需要在templates里直接写标记语言.

  通常,数据需要怎样的格式取决于数据本身.比如,我们可能使用灰色的字体列出那些被停止使用的product,或者在UnitsInStock等于0的时候显示高亮.前面的教程里我们已经学习了GridView, DetailsView, 和FormView 都提供了两种截然不同的格式化数据的方法.

  DataBound 事件— 为DataBound 事件创建一个合适的event handler, 它在数据绑定到item的时候激发(对GridView来说是RowDataBound 事件; 对 DataList 和Repeater来说是 ItemDataBound 事件). 在这些事件里, 刚刚绑定的数据可以被格式化. 参见《基于数据的自定义格式化》 这章.

  Templates 的格式化功能— 在DetailsView 或GridView 里使用TemplateFields , 或 在FormView 里使用template , 我们可以在ASP.NET page的code-behind class里或者BLL里,或者任何其它web程序里可以调用的类库里加格式化信息. 这种格式化功能可以接收任意的输入参数, 但是在template里比如返回HTML . 格式化功能最早在在GridView控件中使用TemplateField 这章里谈到过. 这两种方法都可以在DataList和Repeater里使用.在本章里我们将一步步用这两种方法在这两个控件里做示例.

使用 ItemDataBound Event Handler

  当数据绑定到 DataList时, 无论是使用数据源控件或者 直接在代码里使用DataSource 和 DataBind() , DataList的DataBinding 事件都会被激发.  DataList 为数据源的每条记录创建一个 DataListItem 对象,然后绑定到当前记录. 在这个过程中DataList 激发两个事件:

ItemCreated — 在创建DataListItem 后激发
ItemDataBound — 当前记录绑定到DataListItem 后激发

下面列出了DataList数据绑定过程的大概步骤

DataList的DataBinding event 被激发
DataList
对数据源的每条记录...
For each record in the data source…
创建一个DataListItem 对象
激发ItemCreated event
绑定记录到DataListItem
激发ItemDataBound event
将DataListItem 添加到Items collection

  当数据绑定到Repeater时,和上面所说的情况一样.唯一的区别在于,DataListItem换成了RepeaterItem.

  注意:细心的读者可能注意到了DataList和Repeater绑定到数据时的步骤顺序和GridView有些许差别.在数据绑定过程的后期,GridView会激发DataBound事件,而DataList和Repeater则都没有这个事件.

  和GridView一样,可以为ItemDataBound事件创建一个event handler 来格式化数据.这个event handler 可以处理刚刚绑定到DataListItem或RepeaterItem的数据,来按照需要进行格式化.

  对DataList来说,可以使用风格样式相关的属性,如Font, ForeColor, BackColor, CssClass等,来格式化item.而如果你想格式化Datalist里的template里的web控件,你需要编程去获取这些控件,然后来控制.我们在《Custom Formatting Based Upon Data》里已经看过怎样做.和Repeater控件一样,RepeaterItem类也没有风格样式相关的属性,因此,你需要在ItemDataBound event handler里编程去实现.

由于在DataList和Repeater里使用ItemDataBound格式化技术从本质上来说是由于的,因此我们的示例主要讲DataList.

第一步: 在DataList显示Product  信息

  在学习格式化之前,我们首先创建一个使用DataList显示product信息的页面.在前面一章里,我们创建了一个ItemTemplate显示product 的name,category, supplier, quantity和price的DataList.我们在本章来重复做一次.你可以重新创建DataList和它的ObjectDataSource ,或者直接把前面一章里的Basics.aspx里的控件复制到本章的页面(Formatting.aspx)里.当你完成了Formatting.aspx后,将DataList的ID从DataList1改为ItemDataBoundFormattingExample.下面,在浏览器里看看DataList.如图1所示,唯一的格式在于每个product的交替的背景色.

图 1: 在DataList 里列出product信息

在本章教程里,我们来将价格小于 $20.00 的product的名字和单价用黄色 高亮来显示.

第二步: 在 ItemDataBound Event Handler里编程判断数据的值

  由于只有价格低于$20.00 的product会被格式化,因此我们首先要判断每个product的价格.在绑定数据到DataList时,DataList 为每条数据源的记录创建一个DataListItem实例,并绑定数据.当记录绑定到DataListItem对象后,ItemDataBound事件被激发.我们可以为这个事件创建一个event handler来判断当前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 event handler在概念和语义上来说,和GridView的RowDataBound event handler一样(见基于数据的自定义格式化),语法上有一点差别.当ItemDataBound事件激发时,刚刚绑定数据的DataListItem通过e.Item(在GridView里是e.Row和RowDataBound)传递给相关的event handler.DataList的ItemDataBound event handler影响到每一行,包括 header , footer 和separator.但是product信息只绑定到data行.因此,在处理ItemDataBound事件前,我们首先要判断处理的是否是data行.这个可以通过检查DataListItem的ItemType 属性来完成,它可以有以下八个值:

AlternatingItem
EditItem
Footer
Header
Item
Pager
SelectedItem
Separator

  Item和AlternatingItem都表示DataList的data item.假设我们在处理Item或AlternatingItem,我们可以获取绑定到当前DataListItem的ProductsRow的实例.DataListItem的DataItem属性包含了DataRowView对象的引用,通过它的Row属性可以获取ProductsRow对象.

  下面我们来检查ProductsRow实例的单价属性.由于Product表的UnitPrice字段允许空值,所以在获取UnitPrice属性前我们应该先用IsUnitPriceNull()方法检查这个值是否为空.如果不是,我们再检查看它是否低于$20.00.如果是,我们就进行格式化处理.

第三步: 是Product的 Name 和Price高亮显示

  一旦我们发现Product的price低于$20.00,我们将使它的name和price显示高亮.首先我们要编程获得ItemTemplate里显示Product的name和price的Label控件.然后我们将它的背景色显示为黄色.这个可以直接通过修改Label空间的BackColor属性(LabelID.BackColor = Color.Yellow).当然最理想的做法是所有的显示相关的行为都通过CSS来实现.实际上我们在基于数据的自定义格式化一章里创建的Styles.css - AffordablePriceEmphasis已经提供了这个功能.

使用以下代码设置两个Label控件的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 的product的name和prict都高亮显示了.

图2: 价格低于$20.00 的product都被高亮显示

  注意:由于DataList使用 HTML <table>, DataListItem实例有可以设置整个item风格的属性.比如,如果我们想在price低于$20.00时将所有的item都用黄色来高亮显示,我们可以用e.Item.CssClass = "AffordablePriceEmphasis"来代替上面的代码(见图3).

  而组成Repeater的RepeaterItem并没有提供这样的属性.因此,在Repeater里自定义格式需要设置templates里的控件的格式,象在图2里所做的那样.

图 3: The Entire Product Item is Highlighted for Products Under $20.00

使用 Template的格式化功能

  在在GridView控件中使用TemplateField 一章里,我们学习了如何使用GridView TemplateField的格式化功能来格式化GridView的数据.格式化功能是一种可以从template里调用并返回HTML显示的方法.格式化功能可以写在ASP.NET page的 code-behind class 或App_Code 文件夹里的类文件里或单独的类库项目里.如果你想在其它ASP.NET web程序或多个ASP.NET 页用到同样的功能,那么不要把它下在ASP.NET page的 code-behind class 里.

  为了演示这个功能,我们将修改product信息.如果product被停用,我们在product的name后面增加一个“[DISCONTINUED]”的text.同样的,如果price低于 $20.00 我们将会用黄色来高亮显示(如我们在ItemDataBound event handler例子里做的那样).如果price等于或高于 $20.00,我们将不显示实际的价格,而是在text里显示“Please call for a price quote”. 图4是完成以上功能的页面截图.

图 4: 将比较贵的Products 的价格用文本“Please call for a price quote”来代替.

第一步: 创建格式化功能

  这个例子里我们需要两个格式化功能,其一是在被停用的product name后面加上“[DISCONTINUED]”, 其二是对价格低于$20.00的product高亮显示,其它则显示“Please call for a price quote”.我们将在ASP.NET page的code-behind class 里创建这些功能,并给它们取名为DisplayProductNameAndDiscontinuedStatus 和DisplayPrice.这两个方法都需要返回HTML,而且为了在ASP.NET page的声明语法里调用,都需要标记为Protected (or Public).下面是这两个方法的代码:

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 方法接收productName 和discontinued 的值.而DisplayPrice 方法接收ProductsRow (而不是UnitPrice).如果格式化功能处理可能包含数据库空值(比如UnitPrice,而ProductName和Discontinued都不允许空)的量值,要特别小心处理.

  输入的值可能是一个DBNull而不是你期望的数据类型,因此输入参数的类型必须为Object.而且比如检查传进来的值是否为database 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传进来的,所以必须要类型转换为decimal.

第二步: 在DataList 的ItemTemplate调用格式化方法

在完成以上代码后,剩下的工作就是在DataList的ItemTemplate里调用这些格式化功能.我们需要使用以下代码:

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

  在DataList的ItemTemplate里,ProductNameLabel Label通过指定text属性为<%# Eval("ProductName") %>显示的product的name.为了在需要的情况下加上“[DISCONTINUED]” ,修改代码,使用DisplayProductNameAndDiscontinuedStatus 方法来指定text属性.我们需要使用Eval("columnName") 语法来将product的name和discontinued的值传进去.Eval 返回的值为Object类型,而DisplayProductNameAndDiscontinuedStatus 的参数为String 和Boolean.因此,我们需要将Eval 方法返回的值转换为需要的参数类型,代码如下:

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

和显示product的name和“[DISCONTINUED]” 文本一样,我们设置UnitPriceLabel label的属性为DisplayPrice 的返回值来显示价格.我们将ProductsRow作为参数,而不是UnitPrice:

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

完成以上代码后,在浏览器里看一下页面.你的页面应该和图5看起来差不多.

图 5: 将比较贵的Products 的价格用文本“Please call for a price quote”来代替

总结

  基于数据格式化DataList或Repeater有两种方法.一种是为ItemDataBound 创建event handler .ItemDataBound 在数据源的每条记录绑定到DataListItem 或RepeaterItem时被激发.在ItemDataBound  event handler里,可以判断当前item的数据并格式化,而对DataListItem可以格式化整个item.

  另一种是通过格式化功能来完成自定义格式化.格式化功能是一种可以从template里调用并返回HTML显示的方法.通常,通过判断绑定到当前item的值来决定返回什么样的HTML.这些值或者绑定到item的对象可以传递到格式化功能里.祝编程快乐!

作者简介

  Scott Mitchell,著有六本ASP/ASP.NET方面的书,是4GuysFromRolla.com的创始人,自1998年以来一直应用 微软Web技术。Scott是个独立的技术咨询顾问,培训师,作家,最近完成了将由Sams出版社出版的新作,24小时内精通ASP.NET 2.0。他的联系电邮为mitchell@4guysfromrolla.com,也可以通过他的博客http://scottonwriting.net/与他联系。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索asp.net
, datalist
, repeater
格式化
,以便于您获取更多的相关知识。

时间: 2024-09-17 04:18:38

在ASP.NET 2.0中操作数据之三十:格式化DataList和Repeater的数据_自学过程的相关文章

在ASP.NET 2.0中操作数据之六十二:GridView批量更新数据_自学过程

导言: 在前面的教程,我们对数据访问层进行扩展以支持数据库事务.数据库事务确保一系列的操作要么都成功,要么都失败.本文我们将注意力转到创建一个批更新数据界面. 在本文,我们将创建一个GridView控件,里面的每一行记录都可以进行编辑(见图1),因此我们没有必要多添加一列来包含Edit, Update,和Cancel按钮,而是在页面包含2个"Update Products"按钮,被点击时,遍历所有的产品并对数据库进行更新.让我们开始吧. 图1:GridView控件里的每一行记录都可以编

在ASP.NET 2.0中操作数据之六十四:GridView批量添加数据_自学过程

导言: 在前面的第62章<GridView批量更新数据>里,我们用GridView控件里定制了一个批编辑界面,同样的我们也可以定制一个批添加界面.假设有这种情况,我们接受一批从Tokyo(东京)发过来的货物:6种不同的tea 和 coffee,如果用户在一个DetailsView控件里一次输入一个产品,他将会重复的输入很多相同的值,比如相同的种类(Beverages),相同的供应商(Tokyo Traders),相同的discontinued值(False),以及相同的order值(0).重复

在ASP.NET 2.0中操作数据之十四:使用FormView 的模板_自学过程

导言 在上两节教程中,我们看到了如何使用TemplateField来自定义GridView和DetailsView的输入.TemplateField使我们可以高度自主的定义某个特定的列,但不管是GridView还是DetailsView,都会有点太规则了,简单的说就是它们都有着四四方方的格子一样的外观.很多情况下这样的格子一样的外观是很不错的,不过有的时候我们却需要使用一个不规则的显示外观.当需要显示一个单独的记录时,使用FormView控件就可以实现这种比较随意的外观呈现. 跟DetailsV

在ASP.NET 2.0中操作数据之六十九:处理Computed Columns列_自学过程

导言: Microsoft SQL Server里有一种computed columns列.这种列的值是通过一个表达式来计算,而表达式引用的是同一张表的其它列的值.打个比方,有一张ServiceLog表,其包含了ServicePerformed, EmployeeID, Rate, Duration等列. 虽然我们可以在一个web页面或其它什么界面里计算每笔服务的费用(也就是 比率 rate乘以时间段duration),不过我们也可以手动向ServiceLog表添加一个 AmountDue列以反

在ASP.NET 2.0中操作数据之六十三:GridView实现批量删除数据_自学过程

导言: 在前面的教程,我们用GridView创建了一个批编辑界面.在用户需要一次性编辑多条记录的情况下,批编辑界面很有用.同理,当用户需要同时删除多条记录时,该技术也很有用. 如果你使用过邮件系统的话,你应该对这种最常见的批删除界面很熟悉:界面里每一行都包含一个checkbox,此外,还有一个"Delete All Checked Items"按钮(如图1).本教程比较短,因为我们在前面的教程已经完成大体的框架,在前面的第50章<为GridView控件添加Checkbox>

在ASP.NET 2.0中操作数据之三十五:使用Repeater和DataList单页面实现主/从报表_自学过程

导言 在前面一章里我们学习了如何用两个页分别显示主/从信息.在"主"页里我们用Repeater来显示category.每个category的name都是一个链到"从"页的hyperlink.在从页里用一个两列的DataList显示选中的category下的product.本章我们将还是使用单页,在左边显示category列表,category的名字用LinkButton显示.点击其中一个时页面postback,在右边以两列的DataList显示出相关的product

在ASP.NET 2.0中操作数据之二:创建一个业务逻辑层_自学过程

导言 本教程的第一节所描述的数据访问层(Data Access Layer,以下简称为DAL)已经清晰地将表示逻辑与数据访问逻辑区分开了.不过,即使DAL将数据访问的细节从表示层中分离出来了,可它却不能处理任何的业务规则.比如说,我们可能不希望产品表中那些被标记为"停用"的产品的"分类编号"或"供应商编号"被更新:我们还可能需要应用一些资历规则,比如说我们都不希望被比自己的资历还要浅的人管理.另外一个比较常见的情况就是授权,比如说只有那些具有特殊

在ASP.NET 2.0中操作数据之二十七:创建自定义排序用户界面_自学过程

简介 显示大量已经按类别(不是很多)排序的数据但没有类别分界线,用户很难找到所需要的类别.例如,数据库中只有9个类别(8个不同的类别和1个null),共81种产品.现在用一个GridView列出所有产品,假设有用户对类别Seafood的产品感兴趣,她一定会按类别排序,把Seafood产品排列在一起.排序后,用户便寻找Seafood产品开始和结束的地方.虽然是按英文字母排列类别不难找到Seafood,但仍要花些时间在GridView寻找.为了进一步的区分类别,许多网站使用类别分界线这种排序用户界面

在ASP.NET 2.0中操作数据之五十:为GridView控件添加Checkbox_自学过程

导言: 在前面的教程里我们探讨了如何为GridView控件添加radio buttons列.当用户最多只能选择一项数据时,我们可以在用户界面里添加radio buttons列,而有时候,我们需要选择任意多项数据.比如,基于Web的邮箱客户端列出了一系列的邮件,及一列checkboxes,用户可选择任意封邮件并执行相同的操作,比如移动到另一个文件夹或将之删除. 在本教程,我们将探讨如何添加checkboxes列,以及发生页面回传后如何确定到底选择了哪些checkboxes.特别的,我们将练习一个类