跨两页面的主/明细筛选34

简介

在前面的教程中,我们了解了如何在一个单独网页中显示主/ 明细报表,如何通过 DropDownLists 显示 “主要” 记录,以及如何通过 DataList 显示“ 详细信息” 。另外一种主/ 明细报表通常使用的模式是将主要记录置于一个网页上,而详细情况置于另外一个网页上。在前面提到的跨两页面的主/详细筛选教程中,我们讨论了此模式,讨论了如何使用 GridView 在系统中显示所有的供应商。该 GridView 包含一个 HyperLinkField , HyperLinkField 作为第二个页面的链接呈现,在查询字符串中传递 SupplierID 。第二个页面使用 GridView 列出选定供应商提供的产品。

这样的两页面式主/ 明细报表还可以通过 DataList 和 Repeater 控件来完成。唯一的区别在于 DataList 和 Repeater 都不支持 HyperLinkField 控件。因此,我们必须在控件的 ItemTemplate 中添加一个 HyperLink Web 控件或者锚定 HTML 元素 (<a>) 。然后, HyperLink 的 NavigateUrl 属性或者锚定的 href 属性可以使用声明性方法或者通过编程进行定制。

在本教程中,我们将探讨在一个页面上使用 Repeater 控件以项目符号列表列出类别的实例。每个列表项将包含类别的名称和说明,并将类别名称链接到第二个页面的超链接形式显示。单击链接将自动带用户到第二个页面,此页面中 DataList 将显示所选取类别的产品。

步骤1 :以项目符号列表显示类别

创建任何主/ 明细报表的第一步是显示“主” 记录。因此,我们第一个任务是在 “主” 页中显示类别。在 DataListRepeaterFiltering 文件夹中打开 CategoryListMaster.aspx 页,添加一个 Repeater 控件,并从智能标记选项中添加一个新的 ObjectDataSource 。配置新的 ObjectDataSource ,使其可以从 CategoriesBLL 类的 GetCategories 方法访问数据。

图1 :配置新的 ObjectDataSource 以 使用 CategoriesBLL 类的 GetCategories 方法

接下来,定义 Repeater 的模板,使每个类别名称和说明在项目符号列表中作为一项进行显示。我们不必担心将每个类别链接到详细情况页面。下面显示了 Repeater 和 ObjectDataSource 的声明式标记:

<asp:Repeater ID="Repeater1" runat="server" DataSourceID="ObjectDataSource1" 
    EnableViewState="False"> 
    <HeaderTemplate> 
        <ul> 
    </HeaderTemplate> 
 
    <ItemTemplate> 
        <li><%# Eval("CategoryName") %> - <%# Eval("Description") %></li> 
    </ItemTemplate> 
 
    <FooterTemplate> 
        </ul> 
    </FooterTemplate> 
</asp:Repeater> 
 
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
    OldValuesParameterFormatString="original_{0}" 
    SelectMethod="GetCategories" TypeName="CategoriesBLL"> 
</asp:ObjectDataSource>

完成此标记后,花点时间在浏览器中查看一下进度。如图 2 所示,Repeater 呈现为项目符号列表,显示了每个类别的名称和说明。

图2 :每个类别以项目符号列表项的形式显示

步骤2 :将类别名称转化为明细页面的链接

为了让用户可以显示给定类别的“详细” 信息,我们需要给每个项目符号列表项添加链接,单击链接时,用户将转到第二个页面 (ProductsForCategoryDetails.aspx) 。随后,第二个页面将通过 DataList 显示选定类别的产品。若要确定被单击链接的类别,我们需要通过某种机制将被单击类别的 CategoryID 传递给第二个页面。从一个页面向另外一个页面传输标量数据的最便捷、最直接的方法是使用查询字符串,这也是我们将在此教程中使用的选项。具体来说,ProductsForCategoryDetails.aspx 页面希望通过名为CategoryID 的查询字符串字段传递选定的categoryID 值。例如,要查看饮料类别的产品(该类别产品的 CategoryID 为 1),用户可以访问页面 ProductsForCategoryDetails.aspx?CategoryID=1 。

若要在 Repeater 中为每个项目符号列表项创建超级链接,我们需要为 ItemTemplate 添加一个 Web 超级链接控件或者 HTML 锚定元素 (<a>) 。在每行的超级链接显示相同的情况下,可采用任一方法。至于 Repeater ,我更喜欢使用锚定元素。要使用锚定元素,请更新 Repeater 的 ItemTemplate :

<li> 
    <a href='ProductsForCategoryDetails.aspx?CategoryID=<%# Eval("CategoryID") %>'> 
        <%# Eval("CategoryName") %> 
    </a> - <%# Eval("Description") %> 
</li>

请注意,CategoryID 可直接注入到锚定元素的 href 属性;但是,由于 href 属性中的求值方法使用引号分隔其字符串("CategoryID") ,为此我们必须用撇号 (和引号)将 href 属性值隔开。也可以使用 Web 超链接控件。

<li> 
    <asp:HyperLink runat="server" Text='<%# Eval("CategoryName") %>' 
        NavigateUrl='<%# "ProductsForCategoryDetails.aspx?CategoryID=" & 
            Eval("CategoryID") %>'> 
    </asp:HyperLink> 
    - <%# Eval("Description") %> 
</li>

请注意URL — ProductsForCategoryDetails.aspx?CategoryID — 的静态部分在数据绑定语法中使用字符串连接被直接追加到求值结果("CategoryID") 。

使用超链接控件的一个好处是,如果需要,它可以从Repeater 的 ItemDataBound event handler 通过编程访问。例如,您可能希望以文本形式而不是链接形式显示没有相关产品的类别的类别名称。这样的检查可以在ItemDataBound event handler 中通过编程来完成;对于没有相关产品的类别来说,超链接NavigateUrl 属性可设置为空字符串,从而使特定类别名称以纯文本(而不是链接)形式呈现。有关更多通过 ItemDataBound event handler 以 编程方式格式化 DataList 和 Repeater 内容的信息,请参阅前面的教程 根据数据格式化 DataList 和 Repeater

如果您继续完成这些功能,可以按自己的喜好在页面中使用锚定元素或者超链接控件方法。不管是那种方法,在使用浏览器查看页面时,类别名称都应以链接到 ProductsForCategoryDetails.aspx 的链接形式呈现,传递可用的 CategoryID 值(见图 3 )。

图3 :类别名称链接到 ProductsForCategoryDetails.aspx

步骤3:列出选定类别的产品

CategoryListMaster.aspx 页面完成后,我们可以将注意力转到实施“明细” 页面ProductsForCategoryDetails.aspx 上了。打开此页面,将 DataList 从工具箱拖放到设计器中,将其 ID 属性设置为 ProductsInCategory 。然后,从 DataList 的智能标记选择为页面添加新的 ObjectDataSource ,将其命名为 ProductsInCategoryDataSource 。对其进行配置,使其可以调用 ProductsBLL 类的 GetProductsByCategoryID(categoryID) 方法;将下拉列表中的插入、更新和删除选项卡设置为无 (None) 。

图4 :配置 ObjectDataSource ,以 使用ProductsBLL 类的GetProductsByCategoryID(categoryID) 方法

由于GetProductsByCategoryID(categoryID) 方法接受输入参数 (categoryID) ,Choose Data Source 向导为我们提供了一个指定参数源的机会。使用QueryStringField CategoryID 将参数源设置为 查询字符串 。

图5 :将 Querystring Field CategoryID 作为参数源

正如我们在前面的教程中见到的一样,在完成 Choose Data Source 向导后,Visual Studio 自动为 DataList 创建一个 ItemTemplate ,列出了每个数据字段名称和值。将此模板替换为只列出品名、供应商和价格的模板。同时,将DataList 的 RepeatColumns 属性设置为 2 。完成这些更改之后,DataList 和 ObjectDataSource 的声明式标记应与下面的类似:

<asp:DataList ID="ProductsInCategory" runat="server" DataKeyField="ProductID" 
    RepeatColumns="2" DataSourceID="ProductsInCategoryDataSource" 
    EnableViewState="False"> 
    <ItemTemplate> 
        <h5><%# Eval("ProductName") %></h5> 
        <p> 
            Supplied by <%# Eval("SupplierName") %><br /> 
            <%# Eval("UnitPrice", "{0:C}") %> 
        </p> 
    </ItemTemplate> 
</asp:DataList> 
 
<asp:ObjectDataSource ID="ProductsInCategoryDataSource" 
    OldValuesParameterFormatString="original_{0}" runat="server" 
    SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL"> 
    <SelectParameters> 
        <asp:QueryStringParameter Name="categoryID" QueryStringField="CategoryID" 
            Type="Int32" /> 
    </SelectParameters> 
</asp:ObjectDataSource>

要查看实际页面,则进入CategoryListMaster.aspx 页面,然后,在类别项目符号列表项中单击链接。之后,您将进入 ProductsForCategoryDetails.aspx,通过查询字符串传递 CategoryID 。这样,ProductsForCategoryDetails.aspx 中的  ProductsInCategoryDataSource ObjectDataSource 将获得指定类别的产品,并且在 DataList 中显示这些产品,显示形式为每行显示两个产品。图 6 显示了在查看饮料类时 ProductsForCategoryDetails.aspx 的一个屏幕截图。

图6 :以每行两种产品的形式显示饮料类

步骤4 :在ProductsForCategoryDetails.aspx 页显示类别信息

用户在CategoryListMaster.aspx 页单击类别时,将转到ProductsForCategoryDetails.aspx 页,显示选定类别的产品。但是,在 ProductsForCategoryDetails.aspx 中,并没有用可见的提示来提示用户选定了哪个类别。如果用户本来希望单击饮料,但是错误的单击了佐料,除非他们已经进入 ProductsForCategoryDetails.aspx ,否则他们并不会意识到自己的错误。为了解决此潜在问题,我们可以在 ProductsForCategoryDetails.aspx 页面的顶部显示选定类别的信息 —— 其名称和说明。

要完成此操作,可在ProductsForCategoryDetails.aspx 页面的Repeater 控件上方添加一个 FormView 控件,从名为CategoryDataSource 的 FormView 智能标记向页面添加一个新 ObjectDataSource ,并且将其配置为使用 CategoriesBLL 类的 GetCategoryByCategoryID(categoryID) 方法。

图7 :通过 CategoriesBLL 类的 GetCategoryByCategoryID(categoryID) 方法访问类别信息

与步骤3 中添加的 ProductsInCategoryDataSource ObjectDataSource 一样,CategoryDataSource 的配置数据源向导将提示我们GetCategoryByCategoryID(categoryID) 方法的输入参数源。按照以前的方式使用完全相同的设置,设置查询字符串的参数源和 CategoryID 的 QueryStringField 值(请参阅图 5 )。

完成向导后,Visual Studio 自动创建 FormView 的 ItemTemplate 、EditItemTemplate 和 InsertItemTemplate 。由于我们提供了一个只读界面,您可以按照自己的想法删除 EditItemTemplate 和 InsertItemTemplate 。同样,您也定制 FormView 的 ItemTemplate 。在删除多余的模板并且定制  ItemTemplate 之后, FormView 和 ObjectDataSource 的声明式标记应与下面类似:

<asp:FormView ID="FormView1" runat="server" DataKeyNames="CategoryID" 
    DataSourceID="CategoryDataSource" EnableViewState="False" Width="100%"> 
    <ItemTemplate> 
        <h3> 
            <asp:Label ID="CategoryNameLabel" runat="server" 
                Text='<%# Bind("CategoryName") %>' /> 
        </h3> 
        <p> 
            <asp:Label ID="DescriptionLabel" runat="server" 
                Text='<%# Bind("Description") %>' /> 
        </p> 
    </ItemTemplate> 
</asp:FormView> 
 
<asp:ObjectDataSource ID="CategoryDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}" 
    SelectMethod="GetCategoryByCategoryID" TypeName="CategoriesBLL"> 
    <SelectParameters> 
        <asp:QueryStringParameter Name="categoryID" Type="Int32" 
            QueryStringField="CategoryID" /> 
    </SelectParameters> 
</asp:ObjectDataSource>

图8 显示了通过浏览器查看此页面的屏幕截图。

注意:除了 FormView 之外,我还在 FormView 上添加了一个超链接控件,该控件可以使用户返回到类别列表。您可以按照自己的想法在其它位置安排该链接或者忽略该链接。

图8 :现在页面的顶部显示类别信息

步骤5 :如果选定类别不包含产品,则显示一条消息

无论是否有相关产品,CategoryListMaster.aspx 页均列出了系统中所有的类别。如果用户单击了无相关产品的类别,由于其数据源不包含任何项,因此ProductsForCategoryDetails.aspx 中的DataList 将不显示。正如前面的教程所介绍的, GridView 提供了一个 EmptyData 文本属性,如果其数据源中无记录,此属性可用于指定显示的文本消息。遗憾的是,DataList 和 Repeater 均没有这样的属性。

要显示消息告知用户选定的类别中不含匹配产品,我们需要给页面添加一个 标签 控件,在不存在匹配产品的情况下,为控件的文本属性赋值消息以便显示。然后,我们需要根据 DataList 是否包含任何项来通过编程设置其 Visible 属性。

要实现此目标,我们需要首先在 DataList 的下面添加一个标签。 把其 ID 属性设置为 NoProductsMessage ,再将其文本属性设置为“选定类别无产品…” ,接下来,我们需要根据是否有数据绑定到 ProductsInCategory DataList 来编程设置此 标签 的Visible 属性。必须在数据绑定到 DataList 之后完成赋值。对于 GridView 、DetailsView 和 FormView 来说 ,我们可以为控件的 DataBound 事件创建一个 event handler ,在数据绑定后激发该 event handler 。但是 ,DataList 和 Repeater 均未提供 DataBound 事件。

具体到本例,由于数据将在页面的 Load 事件之前分配给 DataList ,因此,我们可以在 Page_Load 的 event handler 中分配 标签 的 Visible 属性。但是,由于在页面生命周期内来自 ObjectDataSource 的数据可能随后绑定到 DataList ,所以此方法不适用于一般情况。例如,如果显示的数据基于其它控件中的值(例如在使用 DropDownList 来保留 “ 主 ” 记录显示主 / 明细报表时),数据可能不会在页面生命周期的 PreRender 阶段绑定到 Web 数据控件。

一个适用于所有情况的解决方案是,在绑定项或 AlternatingItem 的项类型时给 DataList 的 ItemDataBound (或者ItemCreated)event handler 中的 Visible 属性赋值 False 。在这种情况下,表明数据源中至少有一个数据项,因此,可以隐藏 NoProductsMessage 标签。除了此event handler 之外,我们还需要一个用于处理 DataList 的DataBinding 事件的 event handler ,我们可以在此程序中初始化 标签 的Visible 属性为 True 。由于 DataBinding 事件在 ItemDataBound 事件之前激发,标签的 Visible 属性将初始化设置为 True ;如果没有数据项,则设置为 False 。下列代码可实现此逻辑:

protected void ProductsInCategory_DataBinding(object sender, EventArgs e) 

    // Show the Label 
    NoProductsMessage.Visible = true; 

 
protected void ProductsInCategory_ItemDataBound(object sender, DataListItemEventArgs e) 

    // If we have a data item, hide the Label 
    if (e.Item.ItemType == ListItemType.Item || 
        e.Item.ItemType == ListItemType.AlternatingItem) 
        NoProductsMessage.Visible = false; 
}

Northwind 数据库中的所有类别均与一个或者更多个产品相关联。要测试此功能,我已经手动调整了此教程的 Northwind 数据库,重新将所有与 Produce 类别 (CategoryID = 7) 相关联的产品分配给了 Seafood 类别 (CategoryID = 8) 。可以从 Server Explorer 通过选择 New Query (新查询)和使用下列 UPDATE 语句实现:

UPDATE Products SET CategoryID = 8 WHERE CategoryID = 7

在相应地更新了数据库之后,返回CategoryListMaster.aspx 页面,单击 Produce 链接。由于所有产品不再属于Produce 类别,您会看到“选定类别无产品…” 的消息,如图 9 所示。

图9 :如果选定类别无产品,将显示一条消息

小结

主/ 明细报表可以将主要记录和详细记录显示在单个页面中,而在很多网站中他们是跨两个页面单独显示的。本教程中,我们了解了怎样在“主”网页的 Repeater 以项目符号列表形式列出分类,或在“明细”页面列出相关产品来列出分类,以实现主 / 明细报表。主网页的每个列表项包含有到明细页面的链接,此链接可传递行的 CategoryID 值。

在明细页面中,通过ProductsBLL 类的GetProductsByCategoryID(categoryID) 方法检索特定供应商提供的产品。将 CategoryID 查询字符串值作为参数源赋值给categoryID 参数。我们还探讨了如何在明细页面中使用 FormView 显示类别的详细信息,以及如何在选定类别不包含任何产品时显示一条消息。

快乐编程!

转载于:https://www.cnblogs.com/uddgm/articles/5451478.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值