目的:
1. 展示 ListControl.AppendDataBoundItems 属性用法
2. 展示使用数据源控件绑定联动 ListControl
3.出发点:
a. 今天 csdn 还有网友问,DropDownList 绑定数据后能否插入额外项?答案当然是肯定的。
b. 昨天 forums.asp.net中有人使用数据源控件绑定两个联动DRP,设置第二个DRPAppendDataBoundItems=true,绑定数据后将出现重复数据。
c. 自己学习下数据源绑定控件——用ASP.NET 2.0 一年了,基本还没实践性的操练过数据源控件,总存有疑虑——如此,傻瓜式的东东能上得了台面?
提示:
1. ASP.NET 2.0 为列表型控件基类 ListControl 提供了AppendDataBoundItems 属性,该值指示是否在绑定数据之前清除已 存在的列表项。默认值为 false。然而,只要你设置 AppendDataBoundItems=true,无论何时执行数据绑定(首次加载或者回发页面),都不会清除原有数据,而是将绑定数据追加上去。因此,如果我们希望每次绑定数据,插入自己的静态项(如常见的“选择全部”),而且希望在任意位置插入,还是只有手动实现。如果使用数据源控件绑定数据,那么需要选择正确的插入静态项时机。下面我们将展示,数据源绑定控件和手动绑定如何加入自定义额外项。
关于这个问题,早期 scott 在他的blog上做了讨论:
ListControl.AppendDataBoundItems Property in ASP.NET 2.0
2. 继承自 ListControl 的控件包括 BulletedList, CheckBoxList, DropDownList, ListBox, RadioButtonList
所有这些控件用法基本一致,这里我们以 DropDownList (DRP)为例。
3.示例由两个DRP组成,第一个DRP数据来自Northwind的Categories表,第二个DRP展示当前选择的Category的Product。
4.数据源控件包括AccessDataSource, SqlDataSource,ObjectDataSource,XmlDataSource,提供访问不同类型的数据源,如数据库、XML 文件或中间层业务对象。这里我们选择使用SqlDataSource。常规用法,我们都很熟悉,使用配置数据源向导,一路鼠标+回车,数据库中数据就展示在我们面前。
然而,这里我们希望为Category下来框增加一项“Select All”,以便能列出所有的Product。该模型SQL是通常是这样实现的,即如果参数 @CategoryID IS NULL,我们就返回所有的Product
SELECT [ProductID], [ProductName] FROM [Products] WHERE (@CategoryID IS NULL OR [CategoryID] = @CategoryID)
因此,我们希望SqlDataSource的过滤参数(由Parameter 类的扩展类表示)能接受或者将某个预定值自动将转化为 DBNull,非常幸运,Parameter确实为我们提供了 ConvertEmptyStringToNull 属性以指示是否将空字符串转换为null。默认值为true。
然而,SqlDataSource还公开了一个开关项属性 CancelSelectOnNullParameter,该属性指示当 SqlDataSource的 SelectParameters 集合中包含任何一个参数为空引用时,是否取消数据检索操作。默认值为true。因此,为实现我们的示例,我们需要将其设置为false。
5.现在我们再来看下AppendDataBoundItems 的用法,首先设置 drpCategory.AppendDataBoundItems=True,然后手动添加了一个静态项,text="Select ALL" 而 value="",就像前面所述,SqlDataSource使用的过滤参数(这里是ControlParameter)会自动将其转换为null。
1: <asp:DropDownList ID="drpCategory" runat="server" AppendDataBoundItems="True"
2: AutoPostBack="True" DataSourceID="dsCategory" DataTextField="CategoryName"
3: DataValueField="CategoryID">
4: <asp:ListItem Value="">Select All</asp:ListItem>
5: </asp:DropDownList>
对于drpProduct 呢?如果我们依葫芦画瓢:
1: <asp:DropDownList ID="drpProduct" runat="server" DataSourceID="dsProduct" AppendDataBoundItems="true"
2: DataTextField="ProductName" DataValueField="ProductID">
3: <asp:ListItem Value="">Please select a product</asp:ListItem>
4: </asp:DropDownList>
选择第二次选择Category后我们将得到重复的Product列表:
因此,我们只有另择他法。回忆 ASP.NET 1.x 我们是如何处理的呢?
1: void drpCategory_SelectedIndexChagned(object sender, EventArgs e)
2: {
3: int selectedCategoryId = -1;
4: // ...
5: //
6: drpProduct.DataSource = BindProductByCategory(selectedCategoryId);
7: drpProduct.DataBind();
8:
9: ListItem item = new ListItem("Please select a product", "");
10: drpProduct.Items.Insert(0, item);
11: }
然而,由于我们将数据绑定完全委托给数据源控件处理,我们应该在哪里添加我们额外项呢?答案是 ListControl 的 DataBound 事件!该事件在执行数据绑定之后触发。
1: void drpProduct_DataBound(object sender, EventArgs e)
2: {
3: ListItem item = new ListItem("Please select a product", "");
4: //drpProduct.Items.Add(item);
5: // u can insert the All item to Items at the specified index location,
6: // such as zero
7: drpProduct.Items.Insert(0, item);
8: // u can set the All as the selected item.
9: //drpProduct.SelectedIndex = drpProduct.Items.Count - 1;
10: }
完整代码:
1: <%@ Page Language="C#" AutoEventWireup="true" %>
2:
3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4:
5: <script runat="server">
1:
2: void Page_Load(Object sender, EventArgs e)
3: {
4:
5: }
6:
7: void Page_PreRender(object sender, EventArgs e)
8: {
9:
10: }
11:
12: void drpProduct_DataBound(object sender, EventArgs e)
13: {
14: ListItem item = new ListItem("Please select a product", "");
15: //drpProduct.Items.Add(item);
16: // u can insert the All item to Items at the specified index location,
17: // such as zero
18: drpProduct.Items.Insert(0, item);
19: // u can set the All as the selected item.
20: //drpProduct.SelectedIndex = drpProduct.Items.Count - 1;
21: }
22:
23: protected void dsProduct_Selected(object sender, SqlDataSourceStatusEventArgs e)
24: {
25:
26: }
</
script
>
6:
7: <html xmlns="http://www.w3.org/1999/xhtml" >
8: <head runat="server">
9: <title>活用 ListControl.AppendDataBoundItems 属性</title>
10: </head>
11: <body>
12: <form id="form1" runat="server">
13: <h2 style="text-align:center;">活用 ListControl.AppendDataBoundItems 属性</h2>
14: <div>
15: Category:
16: <asp:DropDownList ID="drpCategory" runat="server" AppendDataBoundItems="True"
17: AutoPostBack="True" DataSourceID="dsCategory" DataTextField="CategoryName"
18: DataValueField="CategoryID">
19: <asp:ListItem Value="">Select All</asp:ListItem>
20: </asp:DropDownList>
21: <asp:SqlDataSource ID="dsCategory" runat="server" ConnectionString="Data Source=.;Initial Catalog=Northwind;Integrated Security=True"
22: ProviderName="System.Data.SqlClient" SelectCommand="SELECT [CategoryID], [CategoryName] FROM [Categories]">
23: </asp:SqlDataSource>
24: Product:
25: <asp:DropDownList ID="drpProduct" runat="server" DataSourceID="dsProduct" OnDataBound="drpProduct_DataBound"
26: DataTextField="ProductName" DataValueField="ProductID">
27: </asp:DropDownList>
28: <asp:SqlDataSource ID="dsProduct" runat="server" ConnectionString="Data Source=.;Initial Catalog=Northwind;Integrated Security=True"
29: ProviderName="System.Data.SqlClient" CancelSelectOnNullParameter="false" SelectCommand="SELECT [ProductID], [ProductName] FROM [Products] WHERE (@CategoryID IS NULL OR [CategoryID] = @CategoryID)" OnSelected="dsProduct_Selected">
30: <SelectParameters>
31: <asp:ControlParameter ControlID="drpCategory" Name="CategoryID" ConvertEmptyStringToNull="true"
32: PropertyName="SelectedValue" Type="Int32" />
33: </SelectParameters>
34: </asp:SqlDataSource>
35: <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="Please select a product" ControlToValidate="drpProduct" Display="Dynamic"></asp:RequiredFieldValidator>
36: <asp:Button ID="btnPostBackTest" Text="PostBack Test" runat="server" />
37: </div>
38: </form>
39: </body>
40: </html>