Chapter11 Custom Formatting Based Upon Data
1. 绑定数据到控件事件过程
不管是从数据控件或编码填充数据到DataSource属性并调用其DataBind()方法。以下几种事件将触发
- DataBinding事件触发
- 数据绑定到数据绑定控件
- DataBound事件触发
2. DetailsView如何实现当UnitPrice大于75的行,用粗体,italic字体显示出来?
用DetailsView的DataBound事件
protected
void
ExpensiveProductsPriceInBoldItalic_DataBound(
object
sender, EventArgs e)
{
//
Get the ProductsRow object from the DataItem property
Northwind.ProductsRow product
=
(Northwind.ProductsRow)((System.Data.DataRowView) ExpensiveProductsPriceInBoldItalic.DataItem).Row;
if
(
!
product.IsUnitPriceNull()
&&
product.UnitPrice
>
75m)
{
//
TODO: Make the UnitPrice text bold and italic
ExpensiveProductsPriceInBoldItalic.Rows[
4
].Font.Bold
=
true
;
ExpensiveProductsPriceInBoldItalic.Rows[
4
].Font.Italic
=
true
;
或者设置CSS的方法
}
}
注意DataItem属性,见下面的解释。
而对于FormView控件, 因为没有行的集合,是静态HTML,web控件的集合,所以,它的方法是这样的
页面中
asp:FormView ID="LowStockedProductsInRed" runat="server" DataKeyNames="ProductID"
DataSourceID="ObjectDataSource1" AllowPaging="True" EnableViewState="False">
<
ItemTemplate
>
<
b
>
Product:
</
b
>
<
asp:Label
ID
="ProductNameLabel"
runat
="server"
Text
='<%# Bind("ProductName") %>'
>
</
asp:Label
><
br
/>
<
b
>
Units In Stock:
</
b
>
<
asp:Label
ID
="UnitsInStockLabel"
runat
="server"
Text
='<%# Bind("UnitsInStock") %>'
>
</
asp:Label
>
</
ItemTemplate
>
</
asp:FormView
>
方法是在ItemTempelete中使用FindControl(“controlID”)方法查找控件, 这里要找的ControlID就是 上面的 UnitsInStockLabel
protected
void
LowStockedProductsInRed_DataBound(
object
sender, EventArgs e)
{
//
Get the ProductsRow object from the DataItem property
Northwind.ProductsRow product
=
(Northwind.ProductsRow)((System.Data.DataRowView)LowStockedProductsInRed.DataItem).Row;
if
(
!
product.IsUnitsInStockNull()
&&
product.UnitsInStock
<=
10
)
{
Label unitsInStock
=
(Label)LowStockedProductsInRed.FindControl(
"
UnitsInStockLabel
"
);
if
(unitsInStock
!=
null
)
{
unitsInStock.CssClass
=
"
LowUnitsInStockEmphasis
"
;
}
}
}
GridView事件触发过程
对于GridView,
1. DataBinding事件触发
2. 数据绑定到数据绑定控件
对于每一行数据..
a. 创建GridViewRow
b. 触发RowCreated 事件
c. 绑定数据到GridViewRow
d. 触发RowDataBound事件
e. 添加GridViewRow到Rows 集合
3. DataBound事件触发
注意: GridView由各种类型不同的行组成
DataRow
– a row that is bound to a record from the GridView's DataSource
EmptyDataRow
– the row displayed if the GridView's DataSource
is empty
Footer
– the footer row; shown if the GridView's ShowFooter
property is set to true
Header
– the header row; shown if the GridView's ShowHeader property is set to true
(the default)
Pager
– for GridView's that implement paging, the row that displays the paging interface
Separator
– not used for the GridView, but used by the RowType
properties for the DataList and Repeater controls, two data Web controls we'll discuss in future tutorials
所以在处理的时候要先进行check
protected
void
HighlightCheapProducts_RowDataBound(
object
sender, GridViewRowEventArgs e){
//
Make sure we are working with a DataRow
if
(e.Row.RowType
==
DataControlRowType.DataRow)
{
//
Get the ProductsRow object from the DataItem property
Northwind.ProductsRow product
=
(Northwind.ProductsRow)((System.Data.DataRowView)e.Row.DataItem).Row;
if
(
!
product.IsUnitPriceNull()
&&
product.UnitPrice
<
10m)
e.Row.CssClass
=
"
AffordablePriceEmphasis
"
;
}
DataItem
Northwind.ProductsRow product=(Northwind.ProductsRow)((System.Data.DataRowView) ExpensiveProductsPriceInBoldItalic.DataItem).Row;
Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView)e.Row.DataItem).Row;
DetailView和FormView是通过ForView1.DataItem, DetailView1.DataItem得到DataRowView object,
而GridView是通过参数e.Row得到DataRowView object,
DataSource的某条记录绑定到GridViewRow,DataRowView object是对应于这条记录的。它的Row返回这条强类型记录,例如返回ProductsRow
Chapter12 Using TemplateFields in the GridView Control
TemplateFields的应用
1. 将两个数据合并到一个列中,姓和名字展示在一栏里
2. 用一个Web控件来展示数据,而不是用一个简单的文本,例如日历控件
3. 展示数据的元数据,统计每个员工工作多久了
后台代码,接受一个EmployeesRow参数,计算到现在的间隔天数
protected
string
DisplayDaysOnJob(Northwind.EmployeesRow employee)
{
if
(employee.IsHireDateNull())
{
return
"
Unknown
"
;
}
else
{
TimeSpan ts
=
DateTime.Now.Subtract(employee.HireDate);
return
ts.Days.ToString(
"
#,###
"
);
}
}
前台代码,调用前台的函数DisplayDaysOnJob,参数是当前行的EmployeesRow
<
asp:TemplateField
HeaderText
="Days On The Job"
>
<
ItemTemplate
>
<%# DisplayDaysOnJob((Northwind.EmployeesRow) ((System.Data.DataRowView) Container.DataItem).Row) %>
<ItemTemplate>
</asp:TemplateField>
Container.DataItem returns a DataRowView
object
corresponding to the DataSource
record
bound to the GridViewRow
.
Its Row
property ((System.Data.DataRowView) Container.DataItem).Row
returns the strongly-typed Northwind.EmployeesRow
, which is passed to the DisplayDaysOnJob
method.
除了传递一个EmployeesRow的实例,其实我们也可以仅仅传递HireDate的值,使用<%# DisplayDaysOnJob(Eval("HireDate")) %>就可以了。不过呢,Eval方法将返回一个object类型,所以我们就必须要修改DisplayDaysOnJob方法的签名以使其可以接受一个object类型的参数。我们不能将Eval("HireDate")调用的结果隐式的转换成一个DateTime类型,因为Employees表的HireDate字段是允许为空的。因此,我们需要使DisplayDaysOnJob方法可以接受一个object类型的参数,并判断这个参数是不是空值(我们可以使用Convert.IsDBNull(objectToCheck)来完成这个验证工作),然后再进行后面的操作。
对比这个:将discontinued显示为"Yes"/"No", 而不是Checkbox
protected string DisplayDiscontinuedAsYESorNO(bool discontinued)
{
if (discontinued) { return "yes"; }
else { return "no"; }
}
对比上面的相关内容,传递给格式化方法的参数可能是空值,所以我们需要在访问雇员的HiredDate之前对它进行空值检查。这样的检查在这里却是不需要的,因为Discontinued字段永远不会是空值。此外,这也是为什么这个方法接受的是一个布尔值而不是ProductsRow实例或object类型的参数的原因
1
<
asp:TemplateField
HeaderText
="Discontinued"
SortExpression
="Discontinued"
>
2
<
ItemTemplate
>
3
<%
# DisplayDiscontinuedAsYESorNO((bool) Eval("Discontinued"))
%>
4
</
ItemTemplate
>
5
</
asp:TemplateField
>
6
Chapter13 Using the FormView's Templates
这一章没什么意思,在显示一个单独的记录的时候,FormView提供了一种更加复杂的的呈现方式。而不想DetailView和GridView一样都是一个个格子。
Chapter14 Displaying Summary Information in the GridView's Footer
这一章讲了怎么在GridView的Footer里显示统计信息,总量,平均价格等。
统计信息两种方法:
1. SQL语句
1
SELECT
CategoryID,
AVG
(UnitPrice),
SUM
(UnitsInStock),
SUM
(UnitsOnOrder)
2
FROM
Products
3
WHERE
CategoryID
=
categoryID
4
GROUP
BY
CategoryID
2. 数据绑定之后,计算
1
//
类范围,累积合计的变量……
2
decimal
_totalUnitPrice
=
0m;
3
int
_totalNonNullUnitPriceCount
=
0
;
4
int
_totalUnitsInStock
=
0
;
5
int
_totalUnitsOnOrder
=
0
;
6
7
protected
void
ProductsInCategory_RowDataBound(
object
sender, GridViewRowEventArgs e)
8
{
9 if (e.Row.RowType == DataControlRowType.DataRow)
10 {
11 // 通过e.Row.DataItem 属性引用ProductsRow
12 Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView)e.Row.DataItem).Row;
13
14 // 增加累积合计(如果它们不为NULL的话!)
15 if (!product.IsUnitPriceNull())
16 {
17 _totalUnitPrice += product.UnitPrice;
18 _totalNonNullUnitPriceCount++;
19 }
20
21 if (!product.IsUnitsInStockNull())
22 _totalUnitsInStock += product.UnitsInStock;
23
24 if (!product.IsUnitsOnOrderNull())
25 _totalUnitsOnOrder += product.UnitsOnOrder;
26 }
27}
在页脚中显示统计数据,可以仍然通过RowDataBound事件,只要判断是否是Footer就行了
1
protected
void
ProductsInCategory_RowDataBound(
object
sender, GridViewRowEventArgs e)
2
{
3 if (e.Row.RowType == DataControlRowType.DataRow)
4 {
5 //……增加累积合计……
6 }
7 else if (e.Row.RowType == DataControlRowType.Footer)
8 {
9 // 确定平均单价
10 decimal avgUnitPrice = _totalUnitPrice / (decimal) _totalNonNullUnitPriceCount;
11
12 // 在相应的单元格中显示统计数据
13 e.Row.Cells[1].Text = "Avg.: " + avgUnitPrice.ToString("c");
14 e.Row.Cells[2].Text = "Total: " + _totalUnitsInStock.ToString();
15 e.Row.Cells[3].Text = "Total: " + _totalUnitsOnOrder.ToString();
16 }
17}