Tip/Trick ASP.NET 2.0: DropDownList DataBind
问题
用DropDowList输入参照数据时,例如输入产品信息时,选择产品类别,通常情况下产品类别也应该是从数据库中绑定出来的。这时会用两个问题:
- 如何方便的在DropDownList里放入一个空值,即Value为空字符串的一个ListItem,因为数据源中是不存在空值的;
- 当编辑某个产品信息时,如果该条产品信息的类别信息已经删除,那么在编辑视图绑定数据时,DropDownList就会报错,因为此时DropDownList的Items集合中 并不存在值为SelectedValue的Item。其实这是个数据一致性的问题。
办法
解决问题1需要利用DropDownList的AppendDataBoundItems属性,这个属性在ASP.NET 1.x是好像是没有的,所以在2.0中一直也没注意到,直到一天才偶然发现。顾名思义,这个属性的作用就是把绑定产生的Items附加到原有Items的后面。那么,解决问题1,我们就可以先在页面里显性声明一个静态的ListItem,如:<asp:ListItem Value="">None</asp:ListItem>,然后将DropDownList的AppendDataBoundItems属性设为true(默认值为false),完整代码实例看下方。
解决问题2,需要对DropDownList做一些必要的扩展,因为在问题2所处的情况下,DropDownList的默认行为就是抛出一个异常,我们的目的是使其具有"容错"功能,在SelectedValue不存在的情况下,默认选择第一项,也就是空值项。通过对DropDownList源码的研究,我们发现这个异常是在执行PerformDataBinding 方法时抛出的,那么最简单的方法就是重写改方法,吃掉抛出的异常,代码片段见下方。
aspx代码片段:
<asp:FormView ID="FormViewProductDetail" runat="server" DataKeyNames="PurchaseOrderID"
DataSourceID="SqlDataSourceProduct" Width="100%">
<EditItemTemplate>
<table cellpadding="0" cellspacing="0" width="100%" border="0">
<tbody>
<tr class="alternating">
<td>
<asp:Label ID="Label1" runat="server" Text="Product Name"></asp:Label>
</td>
<td>
<asp:TextBox ID="ProductNameTextBox" runat="server" Text='<%# Bind("ProductName") %>'>
</asp:TextBox>
</td>
</tr>
<tr>
<td>
<asp:Label ID="Label8" runat="server" Text="Category"></asp:Label></td>
<td>
<ts:DropDownList ID="DropDownListCategory" runat="server" AppendDataBoundItems="True"
DataSourceID="SqlDataSource1" SelectedValue='<%# Bind("CategoryID") %>' DataTextField="CategoryName"
DataValueField="CategoryID">
<asp:ListItem Value="">None</asp:ListItem>
</ts:DropDownList>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:MyConnectionString %>"
SelectCommand="SELECT [CategoryID], [CategoryName] FROM [Category]"></asp:SqlDataSource>
</td>
</tr>
</tbody>
</table>
</EditItemTemplate>
......Other Template.........
</asp:FormView>
DropDownList扩展:
public class DropDownList : System.Web.UI.WebControls.DropDownList
{
/// /// kill the exception. the exception was raised because the selectedvalue does not exist in the list items, /// we do not hope the control throws a "selectedvalue not exist..." exception /// /// protected override void PerformDataBinding(System.Collections.IEnumerable dataSource) { try { base.PerformDataBinding(dataSource); } catch (ArgumentOutOfRangeException ex) { ArgumentOutOfRangeException o = ex; } } }