GridView
是由一组字段(
Field
)组成的,它们都指定的了来自
DataSource
中的什么属性需要用到自己的输出呈现中。最简单的字段类型是
BoundField
,它仅将数据简单的显示为文本。其他的字段类型使用交互
HTML
元素(
alternate HTML elements
)来显示数据。比如说,
CheckBoxField
将被呈现为一个
CheckBox
,其选中状态由某特定数据字段的值来决定;
ImageField
则将某特定数据字段呈现为一个图片,当然,这个数据字段中应该放的是图片类型的数据。超级链接和按钮的状态取决于使用
HyperLinkField
或
ButtonField
字段类型的数据字段的值。
虽然
CheckBoxField
、
ImageField
、
HyperLinkField
和
ButtonField
考虑到了数据的交互视图,但它们仍然有一些相关的格式化的限制。
CheckBoxField
只可以显示为一个单个的
CheckBox
,而一个
ImageField
则只可以显示为一张图片。如果某个字段要显示一些文本、复选框、图片还有一些其他基于不同数据的东西的时候,我们要做什么?或者说,如果我们需要使用除了
CheckBox
、
Image
、
HyperLink
以及
Button
之外的
Web
控件来显示数据时,我们该怎么办?此外,
BoundField
只能显示一个单独的数据字段。如果我们想要在一个
GridView
列中显示两个或者更多的数据字段的值的时候该怎么办呢?
为了适应这样的一个复杂的情况,
GridView
提供了使用模板来进行呈现的
TemplateField
。模板可以包括静态的
HTML
、
Web
控件以及数据绑定的代码。此外,
TemplateField
还拥有各种可以用于不同情况的页面呈现的模板。比如说,
ItemTemplate
是默认的用于呈现每行中的单元格的,而
EditItemTemplate
则用于编辑数据时的自定义界面。
在本节教程中,我们将解释如何使用
TemplateField
来更加高级的自定义
GridView
控件。在
上一节教程
中,我们看到了如何使用
DataBound
和
RowDataBound
事件处理方法
来
自定义基于数据的格式化。另一个办法就是在模板中调用一个格式化方法。在本节中,我们就会看到这种技术。
在本节中,我们将使用一些
TemplateField
来自定义雇员信息的呈现。特别的,我们将列出所有的雇员,但我们将会把雇员的姓和名字放在一列中,把他们的雇佣日期放在一个
Calendar
控件中,还将用一个状态列来表明他们来到公司有多久了。
图一:使用三个
TemplateField
来自定义信息的显示方式
第一步:将数据绑定到GridView
当你需要使用一些
TemplateField
来自定义显示时,我发现最简单的就是先创建一个仅包含
BoundField
的
GridView
控件,然后添加一些
TemplateField
,如果需要的话,也可以将某些
BoundField
直接转换成
TemplateField
。好了,让我们开始本节教程吧。首先,通过设计器往页面上添加一个
GridView
控件,并将一个返回雇员信息的
ObjectDataSource
绑定到它上面。这些步骤将创建一个带有一些
BoundField
的
GridView
,这些
BoundField
对应雇员信息中不同的字段。
打开
GridViewTemplateField.aspx
,并从工具箱中拖一个
GridView
到设计器上。从
GridView
的智能标签(
smart tag
)上选择并添加一个新的调用
EmployeesBLL
类的
GetEmployees()
方法的
ObjectDataSource
控件。
图二:添加一个新的调用
GetEmployees()
方法的
ObjectDataSource
控件
用这种方式绑定
GridView
将会自动的为雇员信息的每一个属性添加一个
BoundField
:
EmployeeID
、
LastName
、
FirstName
、
Title
、
HireDate
、
ReportsTo
以及
Country
。在这个报表中,我们不希望看到
EmployeeID
、
ReportsTo
以及
Country
属性。要删除这些
BoundField
的话,你可以:
·
使用字段对话框
-
在
GridView
的智能标签的弹出菜单中点击“编辑列”(
Edit Columns
)。然后,在左下角的列表中选中你想要删除的
BoundField
并点击那个带红叉的按钮,就可以删除这个
BoundField
了。
·
手工编辑
GridView
的声明语句
-
在源视图(
Source view
)中,找到你想要删除的
BoundField
,就是那些
<asp:BoundField>
元素,删了就行了
。
在你删了
EmployeeID
、
ReportsTo
和
Country
等
BoundField
之后,你的
GridView
的标记语言代码应该像这个样子:
1
<
asp:GridView
ID
="GridView1"
runat
="server"
AutoGenerateColumns
="False"
DataKeyNames
="EmployeeID"
2
DataSourceID
="ObjectDataSource1"
>
3
<
Columns
>
4
<
asp:BoundField
DataField
="LastName"
HeaderText
="LastName"
SortExpression
="LastName"
/>
5
<
asp:BoundField
DataField
="FirstName"
HeaderText
="FirstName"
SortExpression
="FirstName"
/>
6
<
asp:BoundField
DataField
="Title"
HeaderText
="Title"
SortExpression
="Title"
/>
7
<
asp:BoundField
DataField
="HireDate"
HeaderText
="HireDate"
SortExpression
="HireDate"
/>
8
</
Columns
>
9
</
asp:GridView
>
10
让我们花点时间在浏览器中来看看我们的成果。这时,你将看到一个表格,表格中每一个记录都是一个雇员的信息,一共有四列:一个是雇员的姓,一个是名字,一个是头衔,还有一个是他们的受雇日期。
图三:每一个雇员信息都显示了
LastName
、
FirstName
、
Title
和
HireDate
第二步:将姓和名显示在一列中
现在,每一个雇员的姓和名都是分开在两列中显示的。把它们放到一个列中显示出来也许是一个不错的主意。要做到这一点,我们需要用到
TemplateField
。我们可以添加一个新的
TemplateField
,给它加上一些必须的标记语言和数据绑定代码,然后删除原来的
FirstName
和
LastName
这两个
BoundField
;当然,我们也可以将
FirstName
这个
BoundField
直接转换成一个
TemplateField
,编辑它以加上
LastName
的值,然后再删除
LastName
这个
BoundField
。
两种办法都行,不过我个人还是比较喜欢直接转换的那种,因为这种方式可以自动的添加一个含有
Web
控件和相应的数据绑定代码的
ItemTemplate
和
EditItemTemplate
,它们可以用来模仿一个
BoundField
的呈现和功能。这样做的好处自然是不言而喻的,因为转换的过程已经帮我们做了很多事情,那我们当然就可以节约不少的时间了。
要将一个
BoundField
转换成
TemplateField
,我们可以在
GridView
的智能标签的弹出菜单中点击“编辑列”(
Edit Columns
)。在弹出对话框的左下角的列表中选择需要转换的
BoundField
,然后点击右下角的“将此列转换成模板列”(
Convert this field into a TemplateField
)即可。
图四:在字段对话框中,将一个绑定列转换成一个模板列
让我们继续将
FirstName
这个
BoundField
转换成
TemplateField
。在这个更改之后,设计器中并没有什么明显的不同。这是因为将
BoundField
转换成
TemplateField
时,其实是创建了一个维持之前的
BoundField
的外观和感觉的
TemplateField
。尽管在设计器中没有视觉上的变化,但是这个转换的过程已经将
BoundField
的声明代码——
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
——改成了如下所示的
TemplateField
的声明代码:
1
<
asp:TemplateField
HeaderText
="FirstName"
SortExpression
="FirstName"
>
2
<
EditItemTemplate
>
3
<
asp:TextBox
ID
="TextBox1"
runat
="server"
Text
='<%#
Bind("FirstName") %
>
'>
</
asp:TextBox
>
4
</
EditItemTemplate
>
5
<
ItemTemplate
>
6
<
asp:Label
ID
="Label1"
runat
="server"
Text
='<%#
Bind("FirstName") %
>
'>
</
asp:Label
>
7
</
ItemTemplate
>
8
</
asp:TemplateField
>
9
就像你看到的那样,
TemplateField
由两个模板组成——一个
ItemTemplate
,它有一个
Label
控件,其
Text
属性被设置为
FirstName
数据字段的值;还有一个
EditItemTemplate
,它有一个
TextBix
控件,其
Text
属性也被设置为
FirstName
数据字段的值。数据绑定语法——
<%# Bind("fieldName") %>
——说明数据字段
fieldName
被绑定到了这个特定的
Web
控件的属性上。
要将
LastName
添加到
TemplateField
中,我们需要为
ItemTemplate
添加一个
Label
控件并将其
Text
属性绑定到
LastName
上。通过设计器或是手工编写代码都可以做到这一点。要手工写代码的话,只需简单的将相应的声明代码添加到
ItemTemplate
中即可,如下所示:
1
<
asp:TemplateField
HeaderText
="FirstName"
SortExpression
="FirstName"
>
2
<
EditItemTemplate
>
3
<
asp:TextBox
ID
="TextBox1"
runat
="server"
Text
='<%#
Bind("FirstName") %
>
'>
</
asp:TextBox
>
4
</
EditItemTemplate
>
5
<
ItemTemplate
>
6
<
asp:Label
ID
="Label1"
runat
="server"
Text
='<%#
Bind("FirstName") %
>
'>
</
asp:Label
>
7
<
asp:Label
ID
="Label2"
runat
="server"
Text
='<%#
Bind("LastName") %
>
'>
</
asp:Label
>
8
</
ItemTemplate
>
9
</
asp:TemplateField
>
10
要通过设计器来添加的话,还是在
GridView
的智能标签的弹出菜单中点击“编辑列”(
Edit Templates
)。这样会显示
GridView
的模板编辑界面。在这个界面中,智能标签是
GridView
中模板的列表。因为这个时候我们只有一个
TemplateField
,所以下拉列表中只有
FirstName
的各种模板和
EmptyDataTemplate
以及
PagerTemplate
。如果指定了
EmptyDataTemplate
模板的话,它将用于绑定到
GridView
的数据源中没有任何记录时的输出呈现;如果指定了
PagerTemplate
,它将用于呈现
GridView
的分页界面。
图五:
GridView
的模板列可以通过设计器来编辑
要在
FirstName
模板列中同时显示
LastName
,从工具箱中拖一个
Label
到
FirstName
模板列的
ItemTemplate
中即可,当然,这要在
GridView
的模板编辑界面中才行的,如下图所示:
图六:向
FirstName
模板列的
ItemTemplate
中添加一个
Label
现在,添加到
TemplateField
的
Label
控件的
Text
属性还是“
Label
”。我们需要修改这个以使这个属性绑定到数据源中的
LastName
字段上。我们可以通过在
Label
控件的智能标记上点击一下,然后在弹出菜单中选择“编辑数据绑定”(
Edit DataBindings
)选项,如下图所示:
图七:从
Label
的智能标签上选择
Edit DataBindings
选项
在弹出的数据绑定对话框中,你可以在左边的列表中选择需要绑定的属性,然后在右边的下来框中选择一个数据字段。好了,我们现在在左边选择
Text
属性,然后在右边选择
LastName
字段,点击
OK
。
图八:将
Text
属性绑定到
LastName
字段上
注意:
数据绑定对话框允许你声明一个双向的数据绑定。如果你保持“双向数据绑定”
(
Two-way databinding
)这个复选框为未选中的话,数据绑定的代码将会是
<%# Eval("LastName")%>
而不是
<%# Bind("LastName")%>
。不过,对于本节教程来说,两个种做法的效果都是
OK
的。双向数据绑定在插入和编辑数据的时候将会比较重要。但是如果仅仅是简单的显示数据的话,两种做法都是一样的。我们将在今后的章节中详细的讨论一下双向数据绑定。
让我们再花一些时间到浏览器中看看这个页面。就像你看到的那样,
GridView
仍然包含
4
列,不过,
FirstName
列里面显示了姓和名两个数据。
图九:姓和名显示在同一列里面了
要完成这一步,我们先删除
LastName
这个绑定列,并将
FirstName
这个模板列的列头文本(
HeaderText
)改成“
Name
”。在这之后,
GridView
的声明代码将会像下面这样:
1
<
asp:GridView
ID
="GridView1"
runat
="server"
AutoGenerateColumns
="False"
DataKeyNames
="EmployeeID"
2
DataSourceID
="ObjectDataSource1"
>
3
<
Columns
>
4
<
asp:TemplateField
HeaderText
="Name"
SortExpression
="FirstName"
>
5
<
EditItemTemplate
>
6
<
asp:TextBox
ID
="TextBox1"
runat
="server"
Text
='<%#
Bind("FirstName") %
>
'>
</
asp:TextBox
>
7
</
EditItemTemplate
>
8
<
ItemTemplate
>
9
<
asp:Label
ID
="Label1"
runat
="server"
Text
='<%#
Bind("FirstName") %
>
'>
</
asp:Label
>
10
<
asp:Label
ID
="Label2"
runat
="server"
Text
='<%#
Eval("LastName") %
>
'>
</
asp:Label
>
11
</
ItemTemplate
>
12
</
asp:TemplateField
>
13
<
asp:BoundField
DataField
="Title"
HeaderText
="Title"
SortExpression
="Title"
/>
14
<
asp:BoundField
DataField
="HireDate"
HeaderText
="HireDate"
SortExpression
="HireDate"
/>
15
</
Columns
>
16
</
asp:GridView
>
17
图十:每一个雇员的姓和名都显示在同一列里面了
第三步:使用Calendar控件显示HiredDate字段
在
GridView
中将数据显示为文本的话,只需要简单的使用
BoundField
就可以了。然而,在某些特定的场合,数据最好是展示为一个特殊的
Web
控件而不是一个简单的文本。这样的自定义的数据显示就可以用
TemplateField
来做。比如说,比起将雇员的雇佣日期显示成文本来说,我们觉得将其高亮的显示在一个
Calendar
(使用
Calendar控件
)中会更爽一些。
要做到这一点,先将
HiredDate
这个绑定列转换成一个模板列。像之前做的那样转换就是了,大家应该还没有忘记吧?在
GridView
的智能标签那里下手就可以了。
图十一:将
HiredDate
绑定列转换成一个模板列
就像我们在第二步中看到的那样,这个操作会将绑定列替换成一个含有
ItemTemplate
和
EditItemTemplate
的模板列,其中的
ItemTemplate
和
EditItemTemplate
分别带有一个
Label
和一个
TextBox
,而这个
Label
和
TextBox
的
Text
属性都使用了数据绑定语句
<%# Bind("HiredDate")%>
来将
HireDate
绑定到自己身上。
要用
Calendar
控件来替换这个文本的话,我们可以编辑模板:删除
Label
控件,并添加上一个
Calendar
控件。在设计器中,从
GridView
的智能标签的弹出菜单中选择“编辑模板”(
Edit Templates
),并在下拉列表中选择
HireDate
模板列的
ItemTemplate
。然后,删除
Label
控件并从工具箱中拖一个
Calendar
控件到模板编辑界面中。
图十二:给
HireDate
模板列的
ItemTemplate
添加一个
Calendar
控件
这个时候,
GridView
中每一行的
HireDate
模板列都会包含一个
Calendar
控件。不过,雇员的实际雇佣日期还没有设置到
Calendar
控件上,这就让
Calendar
控件默认的显示为当前的日期。我们可以通过将雇员的
HireDate
赋值给
Calendar
控件的
SelectedDate
和
VisibleDate
属性来修正这个问题。
从
Calendar
控件的智能标签中选择“编辑数据绑定”。然后,把
SelectedDate
和
VisibleDate
这两个属性都绑定到
HireDate
字段上。
图十三:将
SelectedDate
和
VisibleDate
都绑定到
HireDate
字段上
注意:
Calendar
控件的选定日期不一定要可见。举个例子来说,某个
Calendar
控件的选定日期为
1999
年
4
月
1
日,但却显示的是现在的年月。选定日期和可见日期是由
Calendar
控件的
SelectedDate
和
VisibleDate
属性来指定的。因为我们不仅希望选中雇员的
HireDate
,还希望它是可见的,那么我们就需要将这两个属性都绑定到
HireDate
字段上。
现在,我们再到浏览器中看看这个页面,
Calendar
现在显示的是雇员的雇员受雇日期的月份并选中了一个指定的日期。
图十四:雇员的受雇日期显示到了
Calendar
控件上
注意:
和我们一直所见到的那些例子相反,在本节教程中我们并没有将
GridView
的
EnableViewState
属性设置为
false
。这样做的原因是,在
Calendar
控件上的点击将会产生一个回发(
PostBack
),并将
Calendar
的选定日期设置为刚才所点击的那个日期。如果禁用了
GridView
的
ViewState
,那么每一次回发都将导致
GridView
使用原来的数据重新绑定,这样
Calendar
的选定日期就会变成原来的雇员受雇日期。
在本教程中,这是一个没有意义的议题,因为用户本来就不应该可以修改雇员的受雇日期。可能直接配置
Calendar
控件为不可选是最好的办法。不过不管怎么说,在本教程中可以看到,某些情况下还是将控件的
ViewState
启用才能提供某些特定的功能的。
第四步:显示雇员在公司工作了多少天
到现在,我们已经看到了
TemplateField
的两个应用:
·
将两个数据合并到一个列中
·
用一个
Web
控件来展示数据,而不是用一个简单的文本
第三种
TemplateField
的用法是,显示
GridView
中数据的元数据。比如说,除了显示雇员的受雇日期,我们可能还希望用一列来显示这个雇员在公司干了多久。
另外还有一种用法,它将在某些情况下需要用到,比如说在页面上某个数据的显示格式需要用一种不同于其在数据库中的存储格式的时候。想象一下,雇员表中有一个性别字段,其中存储了
M
或是
F
这样的字符用于表示此雇员是男的还是女的。当我们需要将这个信息显示在页面上的时候,我们可能希望能够将其显示为“男”或“女”而不是“
M
”或“
F
”。
这两种用法都可以采用在
ASP.NET
页面的后置代码类(或者是在一个独立的类库中,将其实现为一个静态方法)创建一个供模板调用的格式化方法(
formatting method
)来做到。这样的格式化方法将在模板中调用,语法跟前面的数据绑定语法是一样的。格式化方法可以接受若干个参数,但是必须返回一个字符串。这个返回的字符串是一个用于插入到模板中的
HTML
。
让我们增加一点内容来说明这个概念。主要是增加一列以显示雇员在公司干活的天数。这个格式化方法接受一个
Northwind.EmployeesRow
对象,然后返回以字符串的形式返回这个雇员在公司干活的天数。这个方法可以添加到
ASP.NET
页面的后置代码类中,不过一定要记得将其标记为
protected
或
public
,不然模板就访问不到它了。
1
protected
string
DisplayDaysOnJob(Northwind.EmployeesRow employee)
2
{
3
//
确保HiredDate不为空……如果为空的话,返回“Unknown”
4
if
(employee.IsHireDateNull())
5
return
"
Unknown
"
;
6
else
7
{
8
//
返回当前日期/时间与HireDate之间所隔的天数
9
TimeSpan ts
=
DateTime.Now.Subtract(employee.HireDate);
10
return
ts.Days.ToString(
"
#,##0
"
);
11
}
12
}
13
由于
HiredDate
可能会含有空值,所以我们必须在进行计算之前首先保证其值不为空。如果
HiredDate
值为空的话,直接返回一个“
Unknown
”就是了;如果不为空的话呢,就计算当前时间跟
HiredDate
的值之间所隔的天数,并把它作为一个字符串返回即可。
要使用这个方法,我们需要在
GridView
的
TemplateField
中使用数据绑定语法来调用它。同样,我们还是先给
GridView
添加一个新的模板列。
图十五:给
GridView
添加一个新的模板列
将这个新的模板列的页眉文本(
HeaderText
)设置成“
Days on the Job
”,并将其
ItemStyle
的水平对齐(
HorizontalAlign
)设置为居中(
Center
)。要调用
DisplayDaysOnJob
方法,我们需要给这个模板列添加一个
ItemTemplate
并加上如下的数据绑定代码:
<%
# DisplayDaysOnJob((Northwind.EmployeesRow) ((System.Data.DataRowView) Container.DataItem).Row)
%>
Container.DataItem
返回数据源对象中的一个相应的
DataRowView
对象给
GridView
。它的
Row
属性返回一个强类型化的
Nothwind.EmployeesRow
,然后再将其传递给
DisplayDaysOnJob
方法。这个数据绑定语法可以直接出现再
ItemTemplate
(就像下面的代码中那样)中或是赋值给
Label
控件的
Text
属性。
注意:
除了传递一个
EmployeesRow
的实例,其实我们也可以仅仅传递
HireDate
的值,使用
<%# DisplayDaysOnJob(Eval("HireDate")) %>
就可以了。不过呢,
Eval
方法将返回一个
object
类型,所以我们就必须要修改
DisplayDaysOnJob
方法的签名以使其可以接受一个
object
类型的参数。我们不能将
Eval("HireDate")
调用的结果隐式的转换成一个
DateTime
类型,因为
Employees
表的
HireDate
字段是允许为空的。因此,我们需要使
DisplayDaysOnJob
方法可以接受一个
object
类型的参数,并判断这个参数是不是空值(我们可以使用
Convert.IsDBNull(
objectToCheck
)
来完成这个验证工作),然后再进行后面的操作。
就是因为这个,所以我还是选择了传递整个
EmployeesRow
实例。在下一节教程中,我们会看到一个更加合适使用
Eval("columnName")
来传递参数给格式化方法的例子。
在给我们的
GridView
添加了模板列并在
ItemTemplate
中添加了调用
DisplayDaysOnJob
方法的代码后,声明代码应该是这个样子:
1
<
asp:GridView
ID
="GridView1"
runat
="server"
AutoGenerateColumns
="False"
DataKeyNames
="EmployeeID"
2
DataSourceID
="ObjectDataSource1"
>
3
<
Columns
>
4
<
asp:TemplateField
HeaderText
="Name"
SortExpression
="FirstName"
>
5
<
EditItemTemplate
>
6
<
asp:TextBox
ID
="TextBox1"
runat
="server"
Text
='<%#
Bind("FirstName") %
>
'>
</
asp:TextBox
>
7
</
EditItemTemplate
>
8
<
ItemTemplate
>
9
<
asp:Label
ID
="Label1"
runat
="server"
Text
='<%#
Bind("FirstName") %
>
'>
</
asp:Label
>
10
<
asp:Label
ID
="Label2"
runat
="server"
Text
='<%#
Eval("LastName") %
>
'>
</
asp:Label
>
11
</
ItemTemplate
>
12
</
asp:TemplateField
>
13
<
asp:BoundField
DataField
="Title"
HeaderText
="Title"
SortExpression
="Title"
/>
14
<
asp:TemplateField
HeaderText
="HireDate"
SortExpression
="HireDate"
>
15
<
EditItemTemplate
>
16
<
asp:TextBox
ID
="TextBox2"
runat
="server"
Text
='<%#
Bind("HireDate") %
>
'>
</
asp:TextBox
>
17
</
EditItemTemplate
>
18
<
ItemTemplate
>
19
<
asp:Calendar
ID
="Calendar1"
runat
="server"
SelectedDate
='<%#
Bind("HireDate") %
>
'
20
VisibleDate='
<%
#
Eval
(
"
HireDate
"
)
%>
'>
</
asp:Calendar
>
21
</
ItemTemplate
>
22
</
asp:TemplateField
>
23
<
asp:TemplateField
HeaderText
="Days On The Job"
>
24
<
ItemTemplate
>
25
<%
# DisplayDaysOnJob((Northwind.EmployeesRow) ((System.Data.DataRowView) Container.DataItem).Row)
%>
26
</
ItemTemplate
>
27
<
ItemStyle
HorizontalAlign
="Center"
/>
28
</
asp:TemplateField
>
29
</
Columns
>
30
</
asp:GridView
>
31
完成了整节教程之后,页面在浏览器中的样子应该是图十六的这个样子。
图十六:“雇员在公司干了多久“也显示出来了
总结
在
GridView
控件中,相对于其他的列控件来说,模板列可以处理更加复杂的数据呈现。模板列主要用于这样一些情况:
·
一个
GridView
列中需要显示多个数据列
·
使用一个
Web
控件来展示数据比一段简单的文本更好
·
页面的输出取决于绑定到
GridView
的数据,比如说元数据或者说是数据的重新格式化
除了自定义数据的显示,模板列也用于编辑和插入数据时的用户界面的自定义,这个我们在后面的章节中将会讲到。
接下来的两节中,我们会继续讨论模板,我们会先看看在
DetailsView
中使用模板列的情况。跟着我们再去看看
FormView
,这玩意儿就是用模板来实现一个更加复杂的呈现,当然,用的是一大堆的字段。
posted on 2006-09-20 14:03
圣域飞侠 阅读(2716)
评论(0) 编辑 收藏 所属分类:
转载