posts - 37,  comments - 228,  trackbacks - 7
在ASP.NET 2.0中操作数据:在GridView控件中使用TemplateField

英文原版  |   本教程的代码(C#)   |   翻译目录   |   原文目录

导言

GridView是由一组字段(Field)组成的,它们都指定的了来自DataSource中的什么属性需要用到自己的输出呈现中。最简单的字段类型是BoundField,它仅将数据简单的显示为文本。其他的字段类型使用交互HTML元素(alternate HTML elements)来显示数据。比如说,CheckBoxField将被呈现为一个CheckBox,其选中状态由某特定数据字段的值来决定;ImageField则将某特定数据字段呈现为一个图片,当然,这个数据字段中应该放的是图片类型的数据。超级链接和按钮的状态取决于使用HyperLinkFieldButtonField字段类型的数据字段的值。

 

虽然CheckBoxFieldImageFieldHyperLinkFieldButtonField考虑到了数据的交互视图,但它们仍然有一些相关的格式化的限制。CheckBoxField只可以显示为一个单个的CheckBox,而一个ImageField则只可以显示为一张图片。如果某个字段要显示一些文本、复选框、图片还有一些其他基于不同数据的东西的时候,我们要做什么?或者说,如果我们需要使用除了CheckBoxImageHyperLink以及Button之外的Web控件来显示数据时,我们该怎么办?此外,BoundField只能显示一个单独的数据字段。如果我们想要在一个GridView列中显示两个或者更多的数据字段的值的时候该怎么办呢?

 

为了适应这样的一个复杂的情况,GridView提供了使用模板来进行呈现的TemplateField。模板可以包括静态的HTMLWeb控件以及数据绑定的代码。此外,TemplateField还拥有各种可以用于不同情况的页面呈现的模板。比如说,ItemTemplate是默认的用于呈现每行中的单元格的,而EditItemTemplate则用于编辑数据时的自定义界面。


在本节教程中,我们将解释如何使用TemplateField来更加高级的自定义GridView控件。在上一节教程中,我们看到了如何使用DataBoundRowDataBound事件处理方法自定义基于数据的格式化。另一个办法就是在模板中调用一个格式化方法。在本节中,我们就会看到这种技术。

 

在本节中,我们将使用一些TemplateField来自定义雇员信息的呈现。特别的,我们将列出所有的雇员,但我们将会把雇员的姓和名字放在一列中,把他们的雇佣日期放在一个Calendar控件中,还将用一个状态列来表明他们来到公司有多久了。

 

图一:使用三个TemplateField来自定义信息的显示方式

 

第一步:将数据绑定到GridView

当你需要使用一些TemplateField来自定义显示时,我发现最简单的就是先创建一个仅包含BoundFieldGridView控件,然后添加一些TemplateField,如果需要的话,也可以将某些BoundField直接转换成TemplateField。好了,让我们开始本节教程吧。首先,通过设计器往页面上添加一个GridView控件,并将一个返回雇员信息的ObjectDataSource绑定到它上面。这些步骤将创建一个带有一些BoundFieldGridView,这些BoundField对应雇员信息中不同的字段。

 

打开GridViewTemplateField.aspx,并从工具箱中拖一个GridView到设计器上。从GridView的智能标签(smart tag)上选择并添加一个新的调用EmployeesBLL 类的GetEmployees()方法的ObjectDataSource控件。



图二:添加一个新的调用GetEmployees()方法的ObjectDataSource控件

用这种方式绑定GridView将会自动的为雇员信息的每一个属性添加一个BoundFieldEmployeeIDLastNameFirstNameTitleHireDateReportsTo以及Country。在这个报表中,我们不希望看到EmployeeIDReportsTo以及Country属性。要删除这些BoundField的话,你可以:

 

·         使用字段对话框 GridView的智能标签的弹出菜单中点击“编辑列”(Edit Columns)。然后,在左下角的列表中选中你想要删除的BoundField并点击那个带红叉的按钮,就可以删除这个BoundField了。

·         手工编辑GridView的声明语句 在源视图(Source view)中,找到你想要删除的BoundField,就是那些<asp:BoundField>元素,删了就行了

 

在你删了EmployeeIDReportsToCountryBoundField之后,你的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

 

让我们花点时间在浏览器中来看看我们的成果。这时,你将看到一个表格,表格中每一个记录都是一个雇员的信息,一共有四列:一个是雇员的姓,一个是名字,一个是头衔,还有一个是他们的受雇日期。


图三:每一个雇员信息都显示了LastNameFirstNameTitleHireDate


第二步:将姓和名显示在一列中

现在,每一个雇员的姓和名都是分开在两列中显示的。把它们放到一个列中显示出来也许是一个不错的主意。要做到这一点,我们需要用到TemplateField。我们可以添加一个新的TemplateField,给它加上一些必须的标记语言和数据绑定代码,然后删除原来的FirstName LastName这两个BoundField;当然,我们也可以将FirstName这个BoundField直接转换成一个TemplateField,编辑它以加上LastName的值,然后再删除LastName这个BoundField

 

两种办法都行,不过我个人还是比较喜欢直接转换的那种,因为这种方式可以自动的添加一个含有Web控件和相应的数据绑定代码的ItemTemplateEditItemTemplate,它们可以用来模仿一个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,从工具箱中拖一个LabelFirstName模板列的ItemTemplate中即可,当然,这要在GridView的模板编辑界面中才行的,如下图所示:


图六:向FirstName模板列的ItemTemplate中添加一个Label

 

现在,添加到TemplateFieldLabel控件的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绑定列转换成一个模板列

 

就像我们在第二步中看到的那样,这个操作会将绑定列替换成一个含有ItemTemplateEditItemTemplate的模板列,其中的ItemTemplateEditItemTemplate分别带有一个Label和一个TextBox,而这个LabelTextBoxText属性都使用了数据绑定语句<%# Bind("HiredDate")%>来将HireDate绑定到自己身上。

 

要用Calendar控件来替换这个文本的话,我们可以编辑模板:删除Label控件,并添加上一个Calendar控件。在设计器中,从GridView的智能标签的弹出菜单中选择“编辑模板”(Edit Templates),并在下拉列表中选择HireDate模板列的ItemTemplate。然后,删除Label控件并从工具箱中拖一个Calendar控件到模板编辑界面中。



图十二:给HireDate模板列的ItemTemplate添加一个Calendar控件

 

这个时候,GridView中每一行的HireDate模板列都会包含一个Calendar控件。不过,雇员的实际雇佣日期还没有设置到Calendar控件上,这就让Calendar控件默认的显示为当前的日期。我们可以通过将雇员的HireDate赋值给Calendar控件的SelectedDateVisibleDate属性来修正这个问题。

 

Calendar