使用两个 DropDownList 实现母版/详细信息筛选 (VB)

作者 :Scott Mitchell

下载 PDF

本教程扩展母版/详细信息关系以添加第三层,使用两个 DropDownList 控件选择所需的父级和祖父级记录。

简介

上一教程中 ,我们介绍了如何使用填充了类别的单个 DropDownList 和显示属于所选类别的产品的 GridView 来显示简单的母版/详细信息报表。 当显示具有一对多关系的记录时,此报表模式非常有效,并且可以轻松地扩展为适用于包含多个一对多关系的场景。 例如,订单输入系统将具有对应于客户、订单和订单行项的表。 给定客户可能有多个订单,每个订单由多个项目组成。 此类数据可以通过两个 DropDownList 和一个 GridView 呈现给用户。 第一个 DropDownList 将具有数据库中每个客户的列表项,第二个列表项是所选客户下达的订单。 GridView 将列出所选订单中的行项。

虽然 Northwind 数据库在其 CustomersOrdersOrder Details 表中包括规范的客户/订单/订单详细信息,但这些表不会在我们的体系结构中捕获。 尽管如此,我们仍然可以说明如何使用两个依赖的 DropDownList。 第一个 DropDownList 将列出类别,第二个 DropDownList 将列出属于所选类别的产品。 然后,DetailsView 将列出所选产品的详细信息。

步骤 1:创建和填充类别下拉列表

我们的第一个目标是添加列出类别的 DropDownList。 上述教程中详细介绍了这些步骤,但为了完整性,此处汇总了这些步骤。

MasterDetailsDetails.aspx打开 文件夹中的页面Filtering,将 DropDownList 添加到页面,将其ID属性设置为 Categories,然后单击其智能标记中的“配置数据源”链接。 在“数据源配置向导”中,选择添加新数据源。

为 DropDownList 添加新数据源

图 1:为 DropDownList 添加新数据源 (单击以查看全尺寸图像)

新数据源自然应为 ObjectDataSource。 将此新 ObjectDataSource CategoriesDataSource 命名为 ,并让其调用 CategoriesBLL 对象的 GetCategories() 方法。

选择使用 CategoriesBLL 类

图 2:选择使用 CategoriesBLL 类 (单击以查看全尺寸图像)

将 ObjectDataSource 配置为使用 GetCategories () 方法

图 3:将 ObjectDataSource 配置为使用 GetCategories() 方法 (单击以查看全尺寸图像)

配置 ObjectDataSource 后,仍需要指定应在 DropDownList 中显示的 Categories 数据源字段,以及应将哪个数据源字段配置为列表项的值。 将 CategoryName 字段设置为每个列表项的显示和 CategoryID 值。

让 DropDownList 显示 CategoryName 字段,并使用 CategoryID 作为值

图 4:让 DropDownList 显示 CategoryName 字段并用作 CategoryID 值 (单击以查看全尺寸图像)

此时,我们有一个 DropDownList 控件 (Categories) ,该控件填充了表中的 Categories 记录。 当用户从 DropDownList 中选择新类别时,我们希望进行回发,以便刷新要在步骤 2 中创建的产品 DropDownList。 因此,检查 DropDownList 的智能标记中的categories“启用 AutoPostBack”选项。

为类别下拉列表启用 AutoPostBack

图 5:为 Categories DropDownList 启用 AutoPostBack (单击以查看全尺寸图像)

步骤 2:显示第二个下拉列表中所选类别的产品

Categories DropDownList 完成后,下一步是显示属于所选类别的产品的 DropDownList。 若要完成此操作,请将另一个 DropDownList 添加到名为 ProductsByCategory的页面。 与 Categories DropDownList 一样,为名为 ProductsByCategoryDataSourceProductsByCategory DropDownList 创建新的 ObjectDataSource。

为 ProductsByCategory DropDownList 添加新数据源

图 6:为 ProductsByCategory DropDownList 添加新数据源 (单击以查看全尺寸图像)

新建名为 Products 的 ObjectDataSourceByCategoryDataSource

图 7:新建名为 ProductsByCategoryDataSource 的对象数据源 (单击以查看全尺寸图像)

ProductsByCategory由于 DropDownList 需要仅显示属于所选类别的产品,请让 ObjectDataSource 从 ProductsBLL 对象调用 GetProductsByCategoryID(categoryID) 方法。

“配置数据源 - productsByCategoryDataSource”窗口的屏幕截图,其中显示了业务对象下拉菜单,其中选择了“ProductsBLL”并突出显示了“下一步”按钮。

图 8:选择使用 ProductsBLL 类 (单击以查看全尺寸图像)

配置 ObjectDataSource 以使用 GetProductsByCategoryID (categoryID) 方法

图 9:将 ObjectDataSource 配置为使用 GetProductsByCategoryID(categoryID) 方法 (单击以查看全尺寸图像)

在向导的最后一步中,需要指定 参数的值 categoryID 。 将此参数分配给 DropDownList 中的 Categories 选定项。

从类别下拉列表中拉取 categoryID 参数值

图 10:从 Categories DropDownList 拉取categoryID参数值 (单击以查看全尺寸图像)

配置 ObjectDataSource 后,剩下的就是指定用于 DropDownList 项的显示和值的数据源字段。 ProductName显示字段,并使用 字段ProductID作为值。

指定用于 DropDownList 的 ListItems 的文本和值属性的数据源字段

图 11:指定用于 DropDownList 的 ListItemTextValue 属性的数据源字段 (单击以查看全尺寸图像)

配置 ObjectDataSource 和 ProductsByCategory DropDownList 后,我们的页面将显示两个 DropDownList:第一个将列出所有类别,第二个将列出属于所选类别的产品。 当用户从第一个 DropDownList 中选择新类别时,将进行回发,第二个 DropDownList 将反弹,显示属于新选择类别的产品。 图 12 和 13 显示 MasterDetailsDetails.aspx 通过浏览器查看时的操作。

首次访问页面时,“饮料类别”处于选中状态

图 12:首次访问页面时,“饮料类别”处于选中状态 (单击以查看全尺寸图像)

选择其他类别会显示新类别的产品

图 13:选择其他类别显示新类别的产品 (单击以查看全尺寸图像)

目前, productsByCategory DropDownList 在更改时 会导致回发。 但是,在添加 DetailsView 以显示所选产品的详细信息后,我们希望在步骤 3) (进行回发。 因此,检查 DropDownList 的智能标记中的productsByCategory“启用 AutoPostBack”复选框。

为产品启用 AutoPostBack 功能ByCategory DropDownList

图 14:为 productsByCategory DropDownList 启用 AutoPostBack 功能 (单击以查看全尺寸图像)

步骤 3:使用 DetailsView 显示所选产品的详细信息

最后一步是在 DetailsView 中显示所选产品的详细信息。 为此,请将 DetailsView 添加到页面,将其 ID 属性设置为 ProductDetails,然后为其创建新的 ObjectDataSource。 配置此 ObjectDataSource 以使用 DropDownList 的ProductsByCategory选定值作为参数的值从ProductsBLLGetProductByProductID(productID)productID 方法拉取其数据。

“配置数据源 - productsByCategoryDataSource”窗口的屏幕截图,其中打开了业务对象下拉菜单。ProductsBLL 处于选中状态,并突出显示了“下一步”按钮。

图 15:选择使用 ProductsBLL 类 (单击以查看全尺寸图像)

配置 ObjectDataSource 以使用 GetProductByProductID (productID) 方法

图 16:将 ObjectDataSource 配置为使用 GetProductByProductID(productID) 方法 (单击以查看全尺寸图像)

从 ProductsByCategory DropDownList 中拉取 productID 参数值

图 17:从 ProductsByCategory DropDownList 中拉取productID参数值 (单击以查看全尺寸图像)

可以选择在 DetailsView 中 ProductDetails 显示任何可用字段。 我已选择删除 ProductIDSupplierIDCategoryID 字段,并重新排序和格式化其余字段。 此外,我清除了 DetailsView 的 HeightWidth 属性,使 DetailsView 能够扩展到最佳显示其数据所需的宽度,而不是将其限制为指定大小。 完整标记如下所示:

<asp:DetailsView ID="ProductDetails" runat="server"
    AutoGenerateRows="False" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" EnableViewState="False">
    <Fields>
        <asp:BoundField DataField="ProductName"
          HeaderText="Product" SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName"
          HeaderText="Category" ReadOnly="True"
          SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName"
          HeaderText="Supplier" ReadOnly="True"
          SortExpression="SupplierName" />
        <asp:BoundField DataField="QuantityPerUnit"
           HeaderText="Qty/Unit" SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice"
           DataFormatString="{0:c}" HeaderText="Price"
            HtmlEncode="False" SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock"
            HeaderText="UnitsInStock"
            SortExpression="Units In Stock" />
        <asp:BoundField DataField="UnitsOnOrder"
            HeaderText="UnitsOnOrder"
            SortExpression="Units On Order" />
        <asp:BoundField DataField="ReorderLevel"
            HeaderText="ReorderLevel" SortExpression="Reorder Level" />
        <asp:CheckBoxField DataField="Discontinued"
            HeaderText="Discontinued" SortExpression="Discontinued" />
    </Fields>
</asp:DetailsView>

花点时间在浏览器中试用 MasterDetailsDetails.aspx 页面。 乍一看,似乎一切都按预期工作,但存在一个微妙的问题。 选择新类别时, ProductsByCategory DropDownList 将更新为包含所选类别的这些产品,但 ProductDetails DetailsView 继续显示以前的产品信息。 为所选类别选择其他产品时,将更新 DetailsView。 此外,如果测试得足够全面,你会发现,如果你不断选择新类别 (例如从 Categories DropDownList 中选择饮料,然后是调味品,然后糖果) 所有其他类别选择都会 ProductDetails 刷新 DetailsView。

为了帮助具体化此问题,让我们看一个特定示例。 当你第一次访问页面时,“饮料”类别处于选中状态,相关产品将加载到 ProductsByCategory DropDownList 中。 Chai 是所选产品,其详细信息显示在 DetailsView 中 ProductDetails ,如图 18 所示。

所选产品的详细信息显示在 DetailsView 中

图 18:所选产品的详细信息显示在详细信息视图 (单击以查看全尺寸图像)

如果将类别选择从“饮料”更改为“调味品”,则会发生回发并 ProductsByCategory 相应地更新 DropDownList,但 DetailsView 仍显示 Chai 的详细信息。

仍显示以前选择的产品的详细信息

图 19:仍显示以前选择的产品的详细信息 (单击以查看全尺寸图像)

从列表中选择新产品会按预期刷新 DetailsView。 如果在更改产品后选择新类别,则 DetailsView 不会再次刷新。 但是,如果未选择新产品,而是选择了新类别,则 DetailsView 将刷新。 这里到底怎么回事?

问题是页面生命周期中的计时问题。 每当请求页面时,它都将继续执行许多步骤作为呈现。 在其中一个步骤中,ObjectDataSource 控件检查以查看其SelectParameters任何值是否已更改。 如果是这样,绑定到 ObjectDataSource 的数据 Web 控件知道它需要刷新其显示。 例如,选择新类别时, ProductsByCategoryDataSource ObjectDataSource 会检测到其参数值已更改,DropDownList ProductsByCategory 会重新绑定自身,获取所选类别的产品。

在这种情况下出现的问题是,在页面生命周期中,ObjectDataSources 检查更改参数的点发生在重新绑定关联的数据 Web 控件之前。 因此,在选择新类别时, ProductsByCategoryDataSource ObjectDataSource 会检测其参数值的更改。 但是,DetailsView 使用的 ProductDetails ObjectDataSource 不会记录任何此类更改, ProductsByCategory 因为 DropDownList 尚未重新绑定。 在生命周期的后期, ProductsByCategory DropDownList 将重新绑定到其 ObjectDataSource,获取新选择类别的产品。 ProductsByCategory虽然 DropDownList 的值已更改,但 ProductDetails DetailsView 的 ObjectDataSource 已检查完成其参数值;因此,DetailsView 将显示其以前的结果。 图 20 中描述了这种交互。

ProductDetails DetailsView 的 ObjectDataSource 检查更改之后的 ProductsByCategory DropDownList 值更改

图 20ProductsByCategory 在 DetailsView 的 ObjectDataSource 检查更改后 ProductDetails ,DropDownList 值发生更改 (单击以查看全尺寸图像)

若要解决此问题,我们需要在绑定 DropDownList 后ProductsByCategory显式重新绑定 ProductDetails DetailsView。 当 DropDownList 的事件DataBind()触发时ProductsByCategoryProductDetails可以通过调用 DetailsView 的 DataBound 方法来实现此目的。 将以下事件处理程序代码添加到 MasterDetailsDetails.aspx 页面的代码隐藏类 (请参阅“以编程方式设置 ObjectDataSource 的参数值”,了解如何) 添加事件处理程序:

Protected Sub ProductsByCategory_DataBound(sender As Object, e As EventArgs) _
    Handles ProductsByCategory.DataBound
        ProductDetails.DataBind()
End Sub

添加对 DetailsView 的 方法的DataBind()此显式调用ProductDetails后,本教程将按预期工作。 图 21 突出显示了此更改如何修复我们之前的问题。

ProductDetails DetailsView 在 ProductsByCategory DropDownList 的 DataBound 事件触发时显式刷新

图 21ProductDetails当 DropDownList 的事件DataBound触发时ProductsByCategory,将显式刷新 DetailsView (单击以查看全尺寸图像)

总结

DropDownList 用作主/详细信息报表的理想用户界面元素,其中主记录和详细信息记录之间存在一对多关系。 在前面的教程中,我们了解了如何使用单个 DropDownList 筛选所选类别显示的产品。 在本教程中,我们将产品的 GridView 替换为 DropDownList,并使用 DetailsView 显示所选产品的详细信息。 本教程中讨论的概念可以轻松地扩展到涉及多个一对多关系(如客户、订单和订单项)的数据模型。 通常,始终可以为一对多关系中的每个“一”实体添加 DropDownList。

编程愉快!

关于作者

Scott Mitchell 是七本 ASP/ASP.NET 书籍的作者, 4GuysFromRolla.com 的创始人,自 1998 年以来一直从事 Microsoft Web 技术工作。 Scott 担任独立顾问、培训师和作家。 他的最新书是 山姆斯在24小时内 ASP.NET 2.0自学。 可以在 上联系 mitchell@4GuysFromRolla.com他, 也可以通过他的博客联系到他,该博客可在 http://ScottOnWriting.NET中找到。

特别感谢

本教程系列由许多有用的审阅者查看。 本教程的首席审阅者是希尔顿·吉森诺。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处放置一行 mitchell@4GuysFromRolla.com。