技术开发 频道

ASP.NET 2.0中的数据操作:定制数据修改界面

三、在编辑界面中使用DropDownList显示Category和Supplier

我们注意到ProductsRow对象包含产品的CategoryID,CategoryName,SupplierID和SupplierName属性,但是Products数据库只保存了外键,而对应的Name保存在Categories和Suppliers表中。ProductsRow对象中的CategoryID和SupplierID可以读取和写入,而CategoryName和SupplierName属性则标记为只读。

由于CategoryName和SupplierName的只读状态,相应绑定列的ReadOnly属性也被置为true,防止编辑某行时它们的值被修改。尽管也可以通过设置ReadOnly属性为false,使其在编辑状态将这些绑定列转为TextBox,但是这样以来当用户尝试更新产品信息时系统就会抛出异常,因为UpateProduct重载中并不接受CategoryName和SupplierName参数。事实上,我们也不想编写这种重载方法,原因如下:

  • 1. Products表没有SupplierName和CategoryName字段,而是对应的外键SupplierID和CategoryID。因此,我们希望在更新方法中传递外键ID,而不是查找外键表中的值。
  • 2. 要求用户键入supplier或者category的名字也很不合理,因为这要求用户必须知道合法的category和supplier,并且拼写正确无误。

我们打算在只读模式Supplier和category列分别显示了分类和提供商的名字,而在编辑时,通过下拉列表显示可用选项。这样以来,用户可以快速查看有效的category和supplier并且可以很便捷直观的进行选择。

要实现这一点,需要将SupplierName和CategoryName对应的绑定列转换为模板列,在ItemTemplate模板中显示SupplierName和CategoryName,而EidtItemTemplate模板则使用DropDownList控件列出有效的cagegory和supplier。

添加Categories和Suppliers 的DropDownList控件

我们要先将SupplierName和CategoryName绑定列转换为模板列:点击GridView智能标记中的‘编辑列’链接;选择左下的BoundField;点击“将此字段转换为TemplateField”链接,转换过程将创建一个模板列,包括ItemTemplate和EditItemTemplate,最终的元素标记大致如下:

<asp:TemplateField HeaderText="Category" SortExpression="CategoryName"> <EditItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Eval("CategoryName") %>'></asp:Label> </EditItemTemplate> <ItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Bind("CategoryName") %>'></asp:Label> </ItemTemplate> </asp:TemplateField>

由于绑定列标记为只读,ItemTemplate和EditItemTemplate都将用Label控件的Text属性绑定显示相关数据
(如上面的CategoryName)。因此需要修改EditItemTemplate模板,用DropDownList控件来替换原来的Label控件。

上节教程讲的,即可在设计器中编辑模板也可直接修改模板的元素标记。要在设计器中修改,可以通过GridView的智能标记点击“编辑模板”链接并选择Category字段的EditItemTemplate模板。删除Label控件用DropDownList控件代替,并设置DropDownList的ID属性为Categories。



图5:删除EditItemTemplate模板中的TextBox并增加一个DropDownList

下一步我们需要为DropDownList绑定category。从智能标记中点击“选择数据源”链接并选择创建一个新的ObjectDataSource,命名为CategoriesDataSource。



图6:创建一个新的ObjectDataSource控件CategoriesDataSource

为了使ObjectDataSource显示所有的category,我们将它与CategoriesBLL类的GetCategories()方法进行绑定。


图7:将ObjectDataSource控件用GategoriesBLL的GetCategories()方法进行绑定

最后,配置DropDownList,用CategoryName字段作为显示字段而CategoryID作为Value字段。



图8:用CategoryName作为显示字段并用CategoryID作为Value字段

改动后CategoryName的模板项将拥有一个DropDownList控件和一个ObjectDataSource,元素标记大致如下:

<asp:TemplateField HeaderText="Category" SortExpression="CategoryName"> <EditItemTemplate> <asp:DropDownList ID="Categories" runat="server" DataSourceID="CategoriesDataSource"
DataTextField
="CategoryName" DataValueField="CategoryID"> </asp:DropDownList><asp:ObjectDataSource ID="CategoriesDataSource" runat="server" OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories"
TypeName
="CategoriesBLL"> </asp:ObjectDataSource> </EditItemTemplate> <ItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Bind("CategoryName") %>'>
</
asp:Label> </ItemTemplate> </asp:TemplateField>

注意:EditItemTemplate模板中的DropDownList必须启用视图状态(view state)。下面我们将会在DropDownList的元素标记中增加数据绑定语法和数据绑定命令例如Eval()和Bind(),它们要求启用视图状态,否则将无法显示。

重复以上步骤为SupplierName的模板列中EditItemTemplate模板添加DropDownList控件,并命名为Suppliers。包括增加DropDownList控件和创建另一个ObjectDataSource,注意新的ObjectDataSource调用的是SuppliersBLL 类的 GetSuppliers()方法。另外,配置Suppliers下拉框的显示字段为CompanyName,value字段为SupplierID。

两个下拉框都增加完成后,在浏览器中查看页面并点击“Chef Anton’s Cajun Seasoning”产品的编辑按钮。如图9所示,产品的category和supplier列都变成了下拉框并包含了对应的category和supplier选项集。但是,你会发现下拉框中默认选择的是下拉框的第一项(category是Beverages,supplier是Exotic Liquids),事实上它们分别应该是Condiment和New Orleans Cajun Delights。


图9:下拉列表默认选中的是第一项

此外,如果点击更新,你会发现该产品的CategoryID 和 SupplierID都变成了NULL。这些都是由于EditItemTemplate模板中的下拉框没有根据数据库中的实际数据进行绑定。

为DropDownList绑定CategoryID 和 SupplierID 数据

为了使product编辑状态下的category和supplier下拉列表选中实际数据,并使其可以根据用户选择调用BLL的UpdateProduct方法对数据库进行更新,我们需要对两个下拉框的SelectedValue分别绑定到CategoryID 和 SupplierID。例如对于Categories下拉框,我们直接在元素标记中增加SelectedValue='<%# Bind("CategoryID") %>'。

另一种做法是在设计器中,通过下拉框的智能标记,点击“编辑DataBinding”链接,设置编辑模板中的下拉框的数据绑定。接下来,用双重模式指定SelectedValue绑定到CategoryID字段(见图10)。重复上面的方法之一,为Suppliers下拉框绑定SupplierID数据。



图10:给DropDownList的SelectedValue属性绑定CategoryID值

一旦完成两个下拉框SelectedValue属性的数据绑定,产品的category和supplier就会默认选中实际选项了。在点击Update按钮时,下拉框中的选择也会准确传递给UpdateProduct方法。图11显示了增加数据绑定后的代码;注意如何选中下拉列表中的项:Chef Anton’s Cajun Seasoning产品的分类和提供商分别选中了正确的Condiment和New Orleans Cajun Delights选项。


图11:修改后Categroy和Supplier正确选中了Product的实际数据

处理NULL值

Product表中的CategoryID 和 SupplierID列允许为NULL,而编辑模板中的下拉列表却没有NULL这一项。所以目前存在下面两种问题:

  • 1. 用户无法则现在的界面中将某个product非空的category或supplier设置为NULL
  • 2. 如果产品的CategoryID 或 SupplierID为NULL,在点击Edit按钮时程序会抛出异常。这是因为Bind()表达式中CategoryID(或SupplierID)返回NULL值时,SelectedValue无法找到NULL这一列表项因而抛出异常。  

为了支持CategoryID 和 SupplierID的NULL值,需要为两个DropDownList增加一个NULL值选项。在《Master/Detail Filtering With a DropDownList》教程中,我们演示了为绑定的DropDownList增加列表项,方法是将DropDownList的AppendDataBoundItems属性设置为true并手动增加一个值为-1的列表项。在ASP.NET的数据绑定逻辑中,空字符串将自动转换为NULL,NULL值也可以转为空字符串。因此,本节教程我们将增加一个值为空字符串的列表项。

先将这两个DropDownList的AppendDataBoundItems属性设置为true。接着,用<asp:ListItem>元素来增加一个NULL列表项,元素标记大致如下:

<asp:DropDownList ID="Categories" runat="server" DataSourceID="CategoriesDataSource"
DataTextField
="CategoryName" DataValueField="CategoryID"
SelectedValue
='<%# Bind("CategoryID") %>' AppendDataBoundItems="True"> <asp:ListItem Value="">(None)</asp:ListItem> </asp:DropDownList>

我们选择了使用“(None)”作为列表项的文本显示(Text),你也可以空字符串或别的字符。

注意:《Master/Detail Filtering With a DropDownList》教程演示过DropDownList列表项的增加方法――在设计器中点击DropDownList的属性窗口(F4)中的Item属性(将显示ListItem集合编辑器)。这次我们采用直接在元素标记中增加NULL列表项。如果你使用集合编辑器,创建出的元素标记将忽略空字符的Value,如:<asp:ListItem>(None)</asp:ListItem>。看起来并无大碍,可是DropDownList对没有Value的项则使用Text来代替,这样以来选择“None”时,“None”则被赋予CategoryID,系统将产生异常。通过显式设置Value="",选择此项,CategoryID 就被更新为NULL值了。

重复以上步骤设置Supplier的下拉框控件。

通过这一附加的列表项,编辑界面就可以为Product的CategoryID 和 SupplierID设定NULL值了,见图12


图12:通过选择(None)为产品的Category或Supplier指定NULL值。

0
相关文章