使用DataList 和Bulleted List创建主/明细报表 35

简介

在 前一篇教程 中,我们了解了如何跨两页面分离主/ 明细报表。在“主”页面中,我们使用一个 Repeater 控件来显示类别的项目符号列表。每个类别名称都为一个超级链接,单击链接时,用户将转到“明细”页面,在此页面中以两栏 DataList 显示选定类别的产品。

在本教程中,我们将把两页面主/ 明细报表压缩为单个页面,在屏幕的左侧显示类别名称的项目符号列表,每个类别名称以 LinkButton 呈现。单击一个类别名称, LinkButton 将产生回传,并在屏幕的右侧将选定类别的产品绑定到一个两栏 DataList 。除了显示每个类别名称之外,左侧的 Repeater 还显示了指定类别的产品数目(见图 1 )。

图1 :类别名称和产品总数在左侧显示

步骤1 :在屏幕的左半部分显示Repeater

本教程中,我们需要将类别的项目符号列表在选定类别产品的左侧出现。 Web 页面上的内容可使用标准 HTML 元素 —— 段落标签、不间断空格、 <table> 或者级联样式表 (CSS) 技术进行定位。现在为止,我们所有的教程都使用 CSS 技术进行定位。在 母版页与网站导航 教程中,在母版页中创建导航用户界面时,我们使用 绝对定位为导航列表和主要内容指示精确像素偏移量。也可使用 CSS 来定位元素,通过浮动调整左右位置。我们可以通过将 Repeater 浮动在 DataList 的左部,使类别的项目符号列表出现在选定类别产品的左部。

从DataListRepeaterFiltering 文件夹打开CategoriesAndProducts.aspx 页面,并为页面添加一个Repeater 和 DataList 。将Repeater 的ID 设置为Categories ,将DataList 的 ID 设置为 CategoryProducts 。 转到源视图 ,Repeater 和 DataList 控件输入它们自己的 <div> 元素。也就是说,首先在 <div> 元素包含在 Repeater 中,然后将 DataList 自身的 <div> 元素直接包含在 Repeater 后面。此时,标记应与下面类似:

<div> 
    <asp:Repeater ID="Categories" runat="server"> 
    </asp:Repeater> 
</div> 
<div> 
    <asp:DataList ID="CategoryProducts" runat="server"> 
    </asp:DataList> 
</div>

要将Repeater 浮动在DataList 的左部,我们需要使用浮动 CSS style 属性,如下所示:

<div style="float: left; width: 33%; padding-right: 10px;"> 
    Repeater 
</div> 
<div> 
    DataList 
</div>

浮动:左部;将第一个<div>元素浮动在第二个<div>元素的左部。宽度和右侧填充设置表示第一个<div>的宽度,以及在<div>元素的内容和其右边缘有多少填充。有关CCS 中浮动元素的更多信息,请参阅 Floatutorial 。

在名为 FloatLeft 的 Styles.css 中创建一个新的 CSS 类,而不是直接通过第一个<p>元素的 style 属性指定 style 设置。

.FloatLeft 

    float: left; 
    width: 33%; 
    padding-right: 10px; 
}

然后,我们就可以用<div class="FloatLeft">替换<div style="float:left;"> 。

在添加CSS 类并在 CategoriesAndProducts.aspx 页面配置标记之后,请转到设计器。您会看到 Repeater 浮动在 DataList 的左半部分(由于我们尚未配置其数据源或模板,此时它们两个都以灰色框出现)。

图2 :Repeater 浮动在 DataList 的左部

步骤2 :确定每个类别的产品数量

Repeater 和 DataList 的标记完成后,我们可以将类别数据绑定到 Repeater 控件。如图 1 中所示类别的项目符号列表,除了每个类别名称之外,我们还需要显示与类别相关联的产品数量。要访问该信息,我们可以采用下列两种方式中的一种:

  • 从ASP.NET页面的代码文件类确定该信息。给出特定的 categoryID,我们可以通过调用 ProductsBLL 类的GetProductsByCategoryID(categoryID) 方法来确定相关产品的数目。该方法返回一个 ProductsDataTable 对象,此对象的 Count 属性表示存在多少个 ProductsRows ,其中 ProductsRows 表示特定 categoryID 的产品数量。我们可以为 Repeater 创建一个ItemDataBound Event Handler ,每个绑定到 Repeater 的类别均调用 ProductsBLL 类的 GetProductsByCategoryID(categoryID) 方法,并在输出中包含其数量。
  • 在强类型DataSet中更新CategoriesDataTable,使之包含一个NumberOfProducts列。然后,我们可以在 CategoriesDataTable 中更新 GetCategories () 方法,使之包含此信息,或者保持 GetCategories () 不变,并创建一个名为 GetCategoriesAndNumberOfProducts () 的新 CategoriesDataTable 方法。

下面,我们探讨一下这两种技术。由于无需更新数据访问层,因此第一种方法相比之下更简单,但是,此方法需要与数据库之间进行更多的通信。在ItemDataBound Event Handler 中调用ProductsBLL 类的GetProductsByCategoryID(categoryID) 方法为 Repeater 中显示的每个类型增加了额外的数据库调用。使用此技术,共有 N + 1 次数据库调用,此处的 N 为 Repeater 中显示的类型数。采用第二种方式,产品数量从CategoriesBLL 类的GetCategories () ( 或者GetCategoriesAndNumberOfProducts () )方法随每个类型的相关信息返回。

在ItemDataBound Event Handler 中确定产品数量

在Repeater 的 ItemDataBound Event Handler 中确定每种类别的产品数据时无需对现有的数据访问层进行修改。所有的修改可以在CategoriesAndProducts.aspx 页面上直接完成。首先,通过Repeater 的智能标记添加一个新的名为 CategoriesDataSourc 的 ObjectDataSource 。接下来,配置 CategoriesDataSource ObjectDataSource ,保证其可以从 CategoriesBLL 类的 GetCategories () 方法检索数据。

图3 :配置 ObjectDataSource 以 使用 CategoriesBLL 类的GetCategories () 方法

类别Repeater 中的每一项均要可单击,单击时,CategoryProducts DataList 将显示选定类别的产品。这可以通过为每个类别添加超链接链接到相同页面,但通过查询字符串传递 CategoryID 来完成,和我们在前面教程中见到的非常象。此方法的好处是显示特定类别产品的页面可以被搜索引擎设置标签和索引。

或者,我们可以为每个类别创建 LinkButton ,这也是我们将在此教程中使用的方法。LinkButton 在用户浏览器中以超链接显示,单击时,将产生回传;而回传时,需要刷新DataList 的ObjectDataSource 来显示属于选定类别的产品。对于本教程来说,似乎使用超链接要比使用 LinkButton 合理的多,但是,可能使用LinkButton 对其它方案更有利。尽管使用超级链接对此例非常理想,我们还是要探讨一下使用 LinkButton 。正如我们将看到的一样,使用 LinkButton 将产生一些我们使用超链接所不会产生的难题。因此,本教程将重点列出使用 LinkButton 所带来的难题,并对那些用户希望使用LinkButton 而非超链接提供解决方案。

注意:我们鼓励您在 LinkButton 中使用 HyperLink 控件或 <a> 元素。

下列标记显示了 Repeater 和 ObjectDataSource 的声明式语法。请注意,Repeater 的模板以 LinkButton 显示项目符号列表的每一项。

<asp:Repeater ID="Categories" runat="server" DataSourceID="CategoriesDataSource"> 
    <HeaderTemplate> 
        <ul> 
    </HeaderTemplate> 
 
    <ItemTemplate> 
        <li><asp:LinkButton runat="server" ID="ViewCategory"></asp:LinkButton></li> 
    </ItemTemplate> 
 
    <FooterTemplate> 
        </ul> 
    </FooterTemplate> 
</asp:Repeater> 
 
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}" 
    SelectMethod="GetCategories" TypeName="CategoriesBLL"> 
</asp:ObjectDataSource>

注意:对于本教程,Repeater 必须启用其视图状态(请注意从Repeater 声明式语法删除 EnableViewState="False" )。在步骤 3 中,我们将为Repeater 的 ItemCommand 事件创建一个 Event Handler ,在此Event Handler 中,我们将更新DataList 的 ObjectDataSource 的  SelectParameters 集合。如果未启用视图状态,将不触发 Repeater 的 ItemCommand 。有关为什么必须启用视图状态才能触发 ItemCommand 的更多信息,请参见 ASP.NET 问题 及其 解决方案 。

ID 属性值为ViewCategory 的 LinkButton 并未设置其文本属性。如果仅希望显示类别名称,我们需要通过数据绑定语法以声明的方式设置文本属性,如下面所示:

<asp:LinkButton runat="server" ID="ViewCategory" Text='<%# Eval("CategoryName") %>' />

但是,我们希望既显示类别的名称, 显示此类别产品的数目。您可以通过调用ProductBLL 类的GetCategoriesByProductID(categoryID) 方法和确定由其产生的ProductsDataTable 所返回的记录数的方式,从 Repeater 的 ItemDataBound Event Handler 检索此信息,如下列代码所示:

protected void Categories_ItemDataBound(object sender, RepeaterItemEventArgs e) 

    // Make sure we're working with a data item... 
    if (e.Item.ItemType == ListItemType.Item || 
        e.Item.ItemType == ListItemType.AlternatingItem) 
    { 
        // Reference the CategoriesRow instance bound to this RepeaterItem 
        Northwind.CategoriesRow category = 
            (Northwind.CategoriesRow) ((System.Data.DataRowView) e.Item.DataItem).Row; 
 
        // Determine how many products are in this category 
        NorthwindTableAdapters.ProductsTableAdapter productsAPI = 
            new NorthwindTableAdapters.ProductsTableAdapter(); 
        int productCount = 
            productsAPI.GetProductsByCategoryID(category.CategoryID).Count; 
 
        // Reference the ViewCategory LinkButton and set its Text property 
        LinkButton ViewCategory = (LinkButton)e.Item.FindControl("ViewCategory"); 
        ViewCategory.Text = 
            string.Format("{0} ({1:N0})", category.CategoryName, productCount); 
    } 
}

首先,确保我们使用数据项(其ItemType 为 Item 或 AlternatingItem),然后引用绑定到当前 RepeaterItem 的 CategoriesRow 实例。接下来,我们需要通过创建 ProductsBLL 类的实例,调用其GetCategoriesByProductID(categoryID) 方法以及确定使用 Count 属性确定返回的记录数来确定此类别的产品数量。最后,引用 ItemTemplate 中的ViewCategory LinkButton ,将其文本属性设置为 “CategoryName (NumberOfProductsInCategory)” ,其中 CategoryName (NumberOfProductsInCategory) 为整数形式的数值。

注意:还有一种办法,我们可以为ASP.NET 页面的 代码文件 类添加格式化功能,此功能可接受类别的 CategoryName 和 CategoryID 值,在类别中返回CategoryName 级联的产品数量(通过调用 GetCategoriesByProductID(categoryID) 方法确定)。可以将此类格式化功能的结果声明式的赋值给LinkButton 的文本属性,从而代替  ItemDataBound Event Handler 的需求。有关使用格式化功能的更多信息,请参阅 在 GridView 控件中使用 TemplateField 或 根据数据格式化 DataList 控件和 Repeater 控件 。

添加完此Event Handler 之后,花点时间在浏览器中测试一下页面。请注意每个类别是如何列在项目符号列表中的,显示类别名称以及相关的产品数量(见图 4 ) 。

图4 :显示每个类别名称和产品数量

更新CategoriesDataTable 和 CategoriesTableAdapter ,使之包括每个类别的产品数量

由于产品数量绑定到 Repeater 中,我们可以通过在 数据访问层 中调整 CategoriesDataTable 和 CategoriesTableAdapter 来包含此信息,而不是确定每个类别的产品数量。为此,我们必须给CategoriesDataTable 添加新列来保留相关产品的数量。要想给DataTable 添加新列,您可以打开强类型 DataSet (App_Code\DAL\Northwind.xsd) ,右键单击 DataTable 进行修改,并选择添加/ 列。为 CategoriesDataTable 添加新列(见图 5 )。

图5 :为 CategoriesDataSource 添加新列

这将添加名为Column1 的新列,您可以将此列改为其他名称。将新列命名为NumberOfProducts 。接下来,我们需要配置此列的属性。单击新列,转到Properties 窗口。将列的 DataType 属性从System.String 更改为 System.Int32 ,并将 ReadOnly 属性设置为 True ,如图 6 所示。

图6 :设置新列的 DataType 和 ReadOnly 属性

尽管CategoriesDataTable 已经有了一个 NumberOfProducts 列,但是相应的TableAdapter 查询并没有设置它的值。如果希望每次检索类别信息均可返回这样的信息,我们可以更新GetCategories () 方法,从而返回此信息。但是,如果我们只需要获取稀有实例(例如本教程)类别的相关产品数量,那么我们可以保留 GetCategories() ,并创建返回此信息的新方法。下面,我们使用后面一种方法来创建一个名为GetCategoriesAndNumberOfProducts () 的新方法。

要添加这个新的 GetCategoriesAndNumberOfProducts () 方法,右键单击CategoriesTableAdapter 并选择 New Query 。这将显示前面教程中多次用到的 TableAdapter Query Configuration Wizard 。对此方法来说,您可以指示查询使用了一个返回行的ad-hoc SQL 语句,通过此方法来开始向导。

图7 :使用 Ad-Hoc SQL 语句创建方法

图8 :SQL 语句返回行

下一个向导屏幕将提示我们使用的查询。要返回每个类别的CategoryID 、CategoryName 、说明字段及与类别相关的产品数量,请使用下面的SELECT 语句:

SELECT CategoryID, CategoryName, Description, 
       (SELECT COUNT(*) FROM Products p WHERE p.CategoryID = c.CategoryID) 
            as NumberOfProducts 
FROM Categories c

图9 :指定要使用的查询

请注意,计算与类别相关的产品数量的子查询的别名为NumberOfProducts 。名称匹配将使此子查询的返回值与 CategoriesDataTable 的 NumberOfProducts 列相关联。

输入此查询后,最后一步是选择新方法的名称。分别为 Fill a DataTable 和 Return a DataTable 使用 FillWithNumberOfProducts 和 GetCategoriesAndNumberOfProducts 名称。

图10 :将新 TableAdapter 方法命名为FillWithNumberOfProducts 和GetCategoriesAndNumberOfProducts

此时,数据访问层已经扩展为包含每个类别的产品数量。由于我们所有的表示层均通过独立的业务逻辑层来传送对 DAL 的调用,我们需要给CategoriesBLL 类添加相应的GetCategoriesAndNumberOfProducts 方法 :

[System.ComponentModel.DataObjectMethodAttribute 
    (System.ComponentModel.DataObjectMethodType.Select, false)] 
public Northwind.CategoriesDataTable GetCategoriesAndNumberOfProducts() 

    return Adapter.GetCategoriesAndNumberOfProducts(); 
}

完成DAL 和 BLL 后,我们可以在 CategoriesAndProducts.aspx 中向 Categories Repeater 绑定此数据。如果您已经从“在ItemDataBound Event Handler 中确定产品数量” 为 Repeater 创建了一个 ObjectDataSource ,请删除此ObjectDataSource ,并删除Repeater 的 DataSourceID 属性设置;也可以通过在 ASP.NET 代码文件类中删除 “Handles Categories.OnItemDataBound ” 语法来解除 Repeater 的ItemDataBound 事件连接。

Repeater 返回到其初始状态,使用Repeater 的智能标记添加一个名为 CategoriesDataSource 的新 ObjectDataSource 。将 ObjectDataSource 配置为使用CategoriesBLL 类,使之使用 GetCategoriesAndNumberOfProducts () 而不是使用GetCategories () 方法(见图 11 )。

图11 :将 ObjectDataSource 配置为 使用 GetCategoriesAndNumberOfProducts 方法

下面,更新 ItemTemplate ,这样LinkButton 的文本属性可以使用数据绑定语法进行声明式赋值,并包括CategoryName 和 NumberOfProducts 数据字段。Repeater 和 CategoriesDataSource ObjectDataSource 的完整声明式标记如下:

<asp:Repeater ID="Categories" runat="server" DataSourceID="CategoriesDataSource"> 
    <HeaderTemplate> 
        <ul> 
    </HeaderTemplate> 
 
    <ItemTemplate> 
        <li><asp:LinkButton runat="server" ID="ViewCategory" 
                Text='<%# String.Format("{0} ({1:N0})", _ 
                    Eval("CategoryName"), Eval("NumberOfProducts")) %>' /> 
        </li> 
    </ItemTemplate> 
 
    <FooterTemplate> 
        </ul> 
    </FooterTemplate> 
</asp:Repeater> 
 
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}" 
    SelectMethod="GetCategoriesAndNumberOfProducts" TypeName="CategoriesBLL"> 
</asp:ObjectDataSource>

为了包括NumberOfProducts 列而更新 DAL 所得到的显示输出与使用 ItemDataBound Event Handler 方式所得到的完全一样(有关显示类别名称和产品数量的屏幕截图,请参照图4 )。

步骤3 :显示选定类别的产品

此时,我们已经在每个类别中使用 Categories Repeater 显示类别列表和产品数量。Repeater 对每个类别使用一个 LinkButton ,单击 LinkButton 将产生回传,我们需要在CategoryProducts DataList 中显示选定类别的产品。

我们面临的一个难题是如何保证 DataList 只显示选定类别的产品。在 使用具有 Details DetailView 功能的可选主GridView 的主/明细报表 教程中,我们探讨了如何创建可选择行的 GridView ,并将选定行的详细情况显示在同一页面上的DetailsView 中。GridView 的ObjectDataSource 使用 ProductsBLL 的 GetProducts () 方法返回所有产品的信息,而 DetailsView 的 ObjectDataSource 使用 GetProductsByProductID(productID) 方法检索所选产品的信息。productID 参数值是通过关联 GridView 的 SelectedValue 属性值提供的。但不幸的是 ,Repeater 没有 SelectedValue 属性,无法充当参数源。

注意:这是在 Repeater 中使用 LinkButton 出现的难题之一。如果我们在 CategoryID 中通过查询字符串使用一个超链接来传递的话,我们可以将 QueryString 作为参数值源。

为了解决Repeater 缺少 SelectedValue 属性的问题,我们首先给ObjectDataSource 绑定 DataList ,并指定其ItemTemplate 。

从DataList 的智能标记选择添加名为 CategoryProductsDataSource 的新ObjectDataSource ,并将其配置为使用 ProductsBLL 类的GetProductsByCategoryID(categoryID) 方法。由于此教程中的 DataList 提供一个只读界面,请将下拉列表的 INSERT 、UPDATE 和 DELETE 选项卡设置为 (None) 。

图12 :将 ObjectDataSource 配置为使用 ProductsBLL 类的GetProductsByCategoryID(categoryID) 方法

由于GetProductsByCategoryID(categoryID) 方法 需要 输入参数(categoryID) ,因此 Configure Data Source 向导允许我们指定参数源。如果类别已经在GridView 或者 DataList 中列出,我们应将参数源下拉列表设置为 Control ,将ControlID 设置为 Web 数据控件的 ID 。但是,由于Repeater 缺少 SelectedValue 属性,它不能被用作参数源。如果检查的话您会发现 ,ControlID 下拉列表只包含一个控件 ID——CategoryProducts ,此 ID 为 DataList 的 ID 。

现在,将参数源下拉列表设置为 None 。在 Repeater 中单击类别 LinkButton 时,我们也就完成了通过编程对参数赋值的过程。

图13 :不要为 categoryID 参数指定参数源

在完成 Configure Data Source 向导之后,Visual Studio 将自动产生 DataList 的 ItemTemplate 。将默认的ItemTemplate 替换为我们在前面的教程中使用的模板,将 DataList’s RepeatColumns 属性设置为 2 。完成更改后,您的 DataList and 声明式标记及其相关的 ObjectDataSource 应如下面所示:

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

现在,我们还没有设置 CategoryProductsDataSource ObjectDataSource 的categoryID 参数,因此查看页面时不显示产品。我们需要做的是在Repeater 中根据所单击类别的 CategoryID 设置此参数值。这将产生两个难题:首先,我们如何确定什么时间单击了 Repeater 的 ItemTemplate 中的LinkButton ,其次,我们如何确定被单击 LinkButton 的相应类别的 CategoryID ?

LinkButton (譬如Button 和 ImageButton 控件)有一个Click 事件和一个 Command 事件。Click 事件仅用于提示 LinkButton 已经被单击。但有些时候,尽管没有任何单击,我们仍然需要给 Event Handler 传递额外的信息。如果发生这种情况,LinkButton 的 CommandName 和 CommandArgument 属性可分配额外信息。这样,单击 LinkButton 时将触发其 Command 事件 ( 而不是其 Click 事件 ),Event Handler 将传递 CommandName 和 CommandArgument 属性值。

当Repeater 中的模板出现 Command 时,将触发 Repeater 的 ItemCommand event 并传递被单击LinkButton (或者 Button 或 ImageButton )的CommandName 和 CommandArgument 值。因此,要确定什么时候单击了 Repeater 中的类别 LinkButton ,我们需要采取下列操作:

  1. 将 Repeater 的 ItemTemplate 中的 LinkButton 的 CommandName 属性设置为某值(我使用了 “ListProducts” )。通过设置 CommandName 值,单击 LinkButton 时,将触发 LinkButton 的 Command 事件。
  2. 将 LinkButton 的 CommandArgument 属性设置为当前项目的 CategoryID 值。
  3. 为  Repeater 的 ItemCommand 事件创建一个 Event Handler 。在 Event Handler 中,将 CategoryProductsDataSource ObjectDataSource 的 CategoryID 设置为传入的 CommandArgument 的值。

下列 Categories Repeater 的ItemTemplate 标记实现步骤 1 和步骤 2 。请注意 CommandArgument 值是如何通过数据绑定语法分配数据项CategoryID 的:

<ItemTemplate> 
    <li> 
        <asp:LinkButton CommandName="ListProducts"  runat="server" 
            CommandArgument='<%# Eval("CategoryID") %>' ID="ViewCategory" 
            Text='<%# string.Format("{0} ({1:N0})", _ 
                Eval("CategoryName"), Eval("NumberOfProducts")) %>'> 
        </asp:LinkButton> 
    </li> 
</ItemTemplate>

创建ItemCommand Event Handler 时要始终保持谨慎,请首先检查接收到的 CommandName 值,因为Repeater 中任何Button 、 LinkButton 或ImageButton的任何Command 事件均会触发 ItemCommand 事件。尽管我们现在只有一个这样的 LinkButton ,但是在不久的将来,我们(或者我们团队中的其他开发人员 )可能向Repeater 添加其他的 Web 按钮 控件,单击这些控件时会出现相同的 ItemCommand Event Handler 。 因此,最好的方式是确保检查 CommandName 属性,并只在其值与期望值匹配时才处理编程逻辑。

在确定传入的CommandName 值与 “ListProducts” 值相等之后,Event Handler 将为CategoryProductsDataSource ObjectDataSource 的CategoryID 参数赋值为传入的CommandArgument 。对 ObjectDataSource 的 SelectParameters 所做的修改自动将 DataList 自身绑定到数据源,显示新选择类别的产品。

protected void Categories_ItemCommand(object source, RepeaterCommandEventArgs e) 

    // If it's the "ListProducts" command that has been issued... 
    if (string.Compare(e.CommandName, "ListProducts", true) == 0) 
    { 
        // Set the CategoryProductsDataSource ObjectDataSource's CategoryID parameter 
        // to the CategoryID of the category that was just clicked (e.CommandArgument)... 
        CategoryProductsDataSource.SelectParameters["CategoryID"].DefaultValue = 
            e.CommandArgument.ToString(); 
    } 
}

添加完毕之后,我们的教程也将结束了。请花几分钟时间在浏览器中测试一下。图 14 显示了首次访问页面时的屏幕。由于还未选择类别,因此屏幕上并不显示产品。单击一个类别(例如 Produce),在双栏视图的 Product 类别中显示这些产品(见图 15 )。

图14 :首次访问页面时,屏幕上不显示任何产品

图15 :单击 Produce 类别,在右侧显示匹配的产品

小结

在本教程和前一篇教程中我们看到,主/ 明细报表可以跨两个页面进行扩展或者在一个页面上级联。但是,在单个页面上显示主 / 明细报表将对如何在页面上布局主要和详细记录产生一些难题。在 使用具有 Details DetailView 功能的可选主 GridView 的主 / 明细报表 教程中,我们将详细记录显示在主要记录的上方;在此教程中,我们使用了 CSS 技术将主要记录浮动在详细记录的左部。

除了显示主/ 明细报表,我们还探讨了如何检索与每个类别相关的产品数量,以及在Repeater 中单击 LinkButton (或者 Button 或 ImageButton )时如何执行服务器端逻辑。

本教程中我们探究了使用 DataList 和 Repeater 显示主/ 明细报表。下一系列教程将演示如何给DataList 控件添加编辑和删除功能。

快乐编程!

posted @ 2016-05-01 23:14  迅捷之风  阅读(149)  评论(0编辑  收藏  举报