编辑模式下显示一个Drop-Down List
这里将提供给用户的一个常用需求——一个某行处于编辑状态下的Drop-Down List。举例来说,一个DataGrid可能显示一个书籍清单,其中包括每本书的类别,当用户编辑一条书籍记录时,可能要为该书指定一个不同的类别,理想情况下,他们可以从Drop-Down List中选择可能的类别值,比如“小说”、“生物”或者“参考书目”。
显示一个Drop-Down List需要在DataGrid中设定一个模板列。典型的情况是:项模板包含了一个控件,比如一个数据绑定的Label控件来显示记录中某个字段的当前值。然后,向编辑项模板中添加一个Drop-Down List,在VS中,你可以通过DataGrid的属性生成器添加一个模板列,然后通过“编辑模板”移除编辑项模板中默认的TextBox控件,并拖入一个Drop-Down List控件,你还可以在HTML视图下添加模板列。
在创建了含有Drop-Down List的模板列后还有两个任务:首先,要产生一个列表,其次要设定列表中的预选项。举例来说,如果本书的类别设为“小说”,当Drop-Down List显示时,往往需要“小说”是预选的(预选一个项并不是在所有情况下都要讨论的问题)。
可以有多种生成Drop-Down List的方法。下面的几个例子说明了三种方式:使用静态项;使用DataSet中的记录集合;使用DataReader直接从数据库中读取信息。
l 静态项:在Drop-Down List中显示静态项不需要绑定数据到控件。你可以很简单地在控件的项集合中定义项。在VS中,可以通过属性窗口中的Items属性触发项集合编辑器,也可以在HTML视图中编辑项。
下面是一个显示模式下显示类别的模板列和编辑模式下类别的静态列表的完整定义。项模板包含了一个Label控件,其Text属性被设置为当前记录的“genre”(类别)字段,编辑项模板中的静态项定义高亮显示。
<asp:TemplateColumn HeaderText="genre">
<ItemTemplate>
<asp:Label id=Label4 runat="server"
Text='<%# DataBinder.Eval(Container, "DataItem.genre") %>'>
</asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList id="DropDownList2" runat="server" Width="172px">
<asp:ListItem Value="fiction">fiction</asp:ListItem>
<asp:ListItem Value="biography">biography</asp:ListItem>
<asp:ListItem Value="reference">reference</asp:ListItem>
</asp:DropDownList>
</EditItemTemplate>
</asp:TemplateColumn>
l DataSet
如果你想要在Drop-Down List中显示的数据处于一个DataSet里,那么你可以采用通用的数据绑定方式。下面是它的声明语法。Drop-Down List绑定了数据集DsBooks1中的类别表。数据绑定的设置高亮显示。
<asp:TemplateColumn HeaderText="genre (dataset)">
<ItemTemplate>
<asp:Label id=Label3 runat="server"
Text='<%# DataBinder.Eval(Container, "DataItem.genre") %>'>
</asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList id=DropDownList4 runat="server"
DataSource="<%# DsBooks1 %>" DataMember="Genre"
DataTextField="genre" DataValueField="genre" Width="160px">
</asp:DropDownList>
</EditItemTemplate>
</asp:TemplateColumn>
l DataReader
你也可以直接从数据库生成Drop-Down List。这种方式更为复杂但效率也更高。原因在于只有在需要的时候才去读数据库。
实现的一个相当简便的方法是利用WEB窗体数据绑定表达式。尽管最常用的是在数据绑定表达式中调用DataBinder.Eval 方法,但事实上你可以使用该页任何可用的public成员。下面的例子告诉你如何创建一个函数来创建、填充以及返回一个DataTable对象,Drop-Down List可以对它进行绑定。
这种情况下,你需要能够执行一个能得到你需要的记录集的数据命令。比如说,你可能需要定义一个Command,并把它的CommandText属性设为“SELECT * FROM Genres”。为了简化例子,假设在页面中已经有了一个Connection对象和一个Command对象。
由创建页面中的一个共有函数开始。这个函数创建了一个DataTable对象并定义了你需要的列集合。然后打开连接,执行Command命令来返回一个DataReader,并且遍历DataReader,复制数据到DataTable,最后,将DataTable作为该函数的返回值返回。
下面说明了如何实现。该例中返回的DataTable中只有一列(“genre”)。通常只需要一个列来生成Drop-Down List。如果需要将其Text和Value设成不同的值,就需要两个列。
public DataTable GetGenreTable()
{
DataTable dtGenre = new DataTable();
if(Application["GenreTable"] == null)
{
DataRow dr;
DataColumn dc = new DataColumn("genre");
dtGenre.Columns.Add(dc);
this.sqlConnection1.Open();
System.Data.SqlClient.SqlDataReader dreader =
this.sqlCommand1.ExecuteReader();
while(dreader.Read())
{
dr = dtGenre.NewRow();
dr[0] = dreader[0];
dtGenre.Rows.Add(dr);
}
this.sqlConnection1.Close();
}
else
{
dtGenre = (DataTable) Application["GenreTable"];
}
return dtGenre;
}
注意:该函数将它创建的DataTable保存于Application态,由于这里的DataTable就象一个静态的查询表,所以并不需要在每次一个不同行转为编辑模式时都重新读取它,而且,由于同一个DataTable可以被多用户使用,可以将其保存在全局的Application态而不是保存在根据用户不同而不同的Session态。
下面是模板列的声明,你会发现这与绑定DataSet中表的语法非常相似,唯一的真正区别就是数据源的绑定调用的是你自己的函数。这种技术的稍有不利之处在于,在VS中,得不到太多的设计类型服务。由于是通过代码定义DataTable来绑定,VS不会提供任何方式来对DataMember、DataTextField和DataValueField属性进行设置,需要你自己来确定这些属性,使它们与你在代码中创建的成员名字相匹配。
<asp:TemplateColumn HeaderText="genre (database)">
<ItemTemplate>
<asp:Label id=Label1 runat="server"
Text='<%# DataBinder.Eval(Container, "DataItem.genre") %>'>
</asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList id=DropDownList1 runat="server"
DataSource="<%# GetGenreTable() %>"
DataMember="Genre"
DataTextField="genre"
DataValueField="genre"
Width="120px">
</asp:DropDownList>
</EditItemTemplate>
</asp:TemplateColumn>
预选中Drop-Down List中的一项
多数情况下,你可能要设定Drop-Down List中的选定项来匹配特定值——通常是显示模式中的单元格的值。你可以将它的SelectedIndex属性设定成你想要显示的值的索引值来实现。
下例在DataGrid Item的ItemDataBound事件句柄中采取了一种可靠的方式来实现它。这样使用这个事件是正确的,因为它保证了Drop-Down List已经被生成,不管它使用了什么数据源。
技巧在于要知道绑定到Drop-Down List上的值。典型情况下,这个值已经提供给你,要么是在当前的item中,要么是在它的DataItem 属性中,item返回一个包含当前记录的DataRowView 对象。一旦有了这个值,可以通过Drop-Down List的FindByText 或者FindByValue 方法来定位当前项,然后使用item的IndexOf属性来返回索引。
private void DataGrid1_ItemDataBound(object sender,
System.Web.UI.WebControls.DataGridItemEventArgs e)
{
if(e.Item.ItemType == ListItemType.EditItem){
DataRowView drv = (DataRowView) e.Item.DataItem;
String currentgenre = drv["genre"].ToString();
DropDownList ddl =
(DropDownList) e.Item.FindControl("DropDownList1");
ddl.SelectedIndex =
ddl.Items.IndexOf(ddl.Items.FindByText(currentgenre));
}
}