分页 DataList 或 Repeater 控件中的报表数据 (VB)

作者 :斯科特·米切尔

下载 PDF

虽然 DataList 和 Repeater 都不提供自动分页或排序支持,但本教程演示如何向 DataList 或 Repeater 添加分页支持,从而允许更灵活的分页和数据显示接口。

简介

在联机应用程序中显示数据时,分页和排序是两个非常常见的功能。 例如,在联机书店搜索 ASP.NET 书籍时,可能有数百本此类书籍,但列出搜索结果的报告仅列出每页 10 个匹配项。 此外,结果可以按标题、价格、页面计数、作者姓名等进行排序。 正如我们在 分页和排序报表数据 教程中所述,GridView、DetailsView 和 FormView 控件都提供内置分页支持,可在复选框的滴答声中启用。 GridView 还包括排序支持。

遗憾的是,DataList 和 Repeater 都不提供自动分页或排序支持。 本教程介绍如何向 DataList 或 Repeater 添加分页支持。 我们必须手动创建分页界面,显示相应的记录页,并记住在回发期间访问的页面。 虽然与使用 GridView、DetailsView 或 FormView 相比,这确实需要花费更多的时间和代码,但 DataList 和 Repeater 允许更灵活的分页和数据显示接口。

注意

本教程专门介绍分页。 在下一教程中,我们将把注意力转向添加排序功能。

步骤 1:添加分页和排序教程网页

在开始本教程之前,让我们先花点时间添加本教程和下一个教程所需的 ASP.NET 页面。 首先在名为 <a0/a0> 的项目中创建一个新文件夹。 接下来,将以下五个 ASP.NET 页添加到此文件夹中,其中所有页面都配置为使用母版页 Site.master

  • Default.aspx
  • Paging.aspx
  • Sorting.aspx
  • SortingWithDefaultPaging.aspx
  • SortingWithCustomPaging.aspx

创建 PagingSortingDataListRepeater 文件夹并添加教程 ASP.NET 页

图 1:创建 PagingSortingDataListRepeater 文件夹并添加教程 ASP.NET 页面

接下来,打开Default.aspx页面,并将SectionLevelTutorialListing.ascx用户控件从文件夹拖动UserControls到设计图面上。 我们在母版页和网站导航教程中创建的此用户控件枚举网站地图,并在项目符号列表中的当前部分中显示这些教程。

将 SectionLevelTutorialListing.ascx 用户控件添加到 Default.aspx

图 2:将用户控件SectionLevelTutorialListing.ascx添加到 Default.aspx单击以查看全尺寸图像

为了使项目符号列表显示要创建的分页和排序教程,我们需要将它们添加到网站地图。 Web.sitemap打开该文件,并使用 DataList 站点映射节点标记在编辑和删除后添加以下标记:

<siteMapNode
    url="~/PagingSortingDataListRepeater/Default.aspx"
    title="Paging and Sorting with the DataList and Repeater"
    description="Paging and Sorting the Data in the DataList and Repeater Controls">
    <siteMapNode
        url="~/PagingSortingDataListRepeater/Paging.aspx"
        title="Paging"
        description="Learn how to page through the data shown
                     in the DataList and Repeater controls." />
    <siteMapNode
        url="~/PagingSortingDataListRepeater/Sorting.aspx"
        title="Sorting"
        description="Sort the data displayed in a DataList or
                     Repeater control." />
    <siteMapNode
        url="~/PagingSortingDataListRepeater/SortingWithDefaultPaging.aspx"
        title="Sorting with Default Paging"
        description="Create a DataList or Repeater control that is paged using
                     default paging and can be sorted." />
    <siteMapNode
        url="~/PagingSortingDataListRepeater/SortingWithCustomPaging.aspx"
        title="Sorting with Custom Paging"
        description="Learn how to sort the data displayed in a DataList or
                     Repeater control that uses custom paging." />
</siteMapNode>

更新网站地图以包括新的 ASP.NET 页面

图 3:更新网站地图以包括新的 ASP.NET 页

分页评审

在前面的教程中,我们了解了如何在 GridView、DetailsView 和 FormView 控件中分页浏览数据。 这三个控件提供了一种称为 默认分页的简单分页形式,只需检查控件智能标记中的“启用分页 ”选项即可实现。 使用默认分页时,每次在第一页上请求数据页访问或用户导航到 GridView、DetailsView 或 FormView 控件的其他数据页时,都会重新请求 ObjectDataSource 中的所有数据。 然后,它会根据请求的页面索引和每页显示的记录数来截取要显示的特定记录集。 我们在分页和排序报表数据教程中详细介绍了默认分页。

由于默认分页会重新请求每个页面的所有记录,因此分页时,分页的数据量足够大时并不可行。 例如,假设分页到 50,000 条页面大小为 10 的记录。 每次用户移动到新页面时,都必须从数据库中检索所有 50,000 条记录,即使只显示其中 10 条记录。

自定义分页 通过仅获取要显示在请求页面上的精确记录子集来解决默认分页的性能问题。 实现自定义分页时,必须编写能够有效地返回正确记录集的 SQL 查询。 我们已了解如何使用 SQL Server 2005 的新 ROW_NUMBER() 关键字 创建此类查询, 并在“高效分页浏览大量数据 ”教程中重新创建此类查询。

若要在 DataList 或 Repeater 控件中实现默认分页,我们可以将 PagedDataSource 用作分页内容的包装 ProductsDataTable 器。 该PagedDataSource类具有DataSource可分配给任何可枚举对象的属性以及PageSize指示每个页面和CurrentPageIndex当前页索引显示多少条记录的属性。 设置这些属性后, PagedDataSource 可以将这些属性用作任何数据 Web 控件的数据源。 枚举PagedDataSource时,将仅基于DataSource属性PageSize返回其内部CurrentPageIndex记录的相应子集。 图 4 描述了类的功能 PagedDataSource

PagedDataSource 使用 Pageable 接口包装可枚举对象

图 4:使用 PagedDataSource 可分页接口包装可枚举对象

PagedDataSource可以直接从业务逻辑层创建和配置对象,并通过 ObjectDataSource 绑定到 DataList 或 Repeater,也可以直接在 ASP.NET 页的代码隐藏类中创建和配置对象。 如果使用后一种方法,则必须使用 ObjectDataSource 放弃,而是以编程方式将分页数据绑定到 DataList 或 Repeater。

PagedDataSource 对象还具有支持自定义分页的属性。 但是,我们可以绕过使用自定义分页, PagedDataSource 因为我们在类中 ProductsBLL 已有 BLL 方法,这些方法专为返回要显示的精确记录的自定义分页而设计。

在本教程中,我们将介绍如何在 DataList 中实现默认分页,方法是向返回适当配置的ProductsBLL对象的类添加新方法PagedDataSource。 在下一教程中,我们将了解如何使用自定义分页。

步骤 2:在业务逻辑层中添加默认分页方法

ProductsBLL 类当前有一个返回所有产品信息 GetProducts() 的方法,一个用于在起始索引 GetProductsPaged(startRowIndex, maximumRows)处返回特定子集的产品。 使用默认分页时,GridView、DetailsView 和 FormView 控件都使用 GetProducts() 该方法检索所有产品,但随后在内部使用仅 PagedDataSource 显示正确的记录子集。 若要使用 DataList 和 Repeater 控件复制此功能,我们可以在 BLL 中创建一个新方法来模拟此行为。

将方法添加到 ProductsBLL 采用两个整数输入参数的类 GetProductsAsPagedDataSource

  • pageIndex 要显示的页的索引、索引为零和
  • pageSize 每页要显示的记录数。

GetProductsAsPagedDataSource 首先从中检索 所有 记录 GetProducts()。 然后,它会创建一个 PagedDataSource 对象,将其 CurrentPageIndexPageSize 属性设置为传入 pageIndex 的值和 pageSize 参数。 该方法最后返回此配置的 PagedDataSource

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetProductsAsPagedDataSource(ByVal pageIndex As Integer, _
    ByVal pageSize As Integer) As PagedDataSource
    ' Get ALL of the products
    Dim products As Northwind.ProductsDataTable = GetProducts()
    ' Limit the results through a PagedDataSource
    Dim pagedData As New PagedDataSource()
    pagedData.DataSource = products.Rows
    pagedData.AllowPaging = True
    pagedData.CurrentPageIndex = pageIndex
    pagedData.PageSize = pageSize
    Return pagedData
End Function

步骤 3:使用默认分页在 DataList 中显示产品信息

GetProductsAsPagedDataSource将方法添加到ProductsBLL类后,现在可以创建一个提供默认分页的 DataList 或 Repeater。 首先打开文件夹中的页面,Paging.aspx并将 DataList 从工具箱拖动到设计器上,将 DataList s PagingSortingDataListRepeater 属性设置为 IDProductsDefaultPaging 从 DataList 的智能标记中,创建一 ProductsDefaultPagingDataSource 个名为和配置的新 ObjectDataSource,以便它使用 GetProductsAsPagedDataSource 该方法检索数据。

创建 ObjectDataSource 并将其配置为使用 GetProductsAsPagedDataSource () 方法

图 5:创建 ObjectDataSource 并将其配置为使用GetProductsAsPagedDataSource()方法(单击以查看全尺寸图像

将 UPDATE、INSERT 和 DELETE 选项卡中的下拉列表设置为“无”。

将 UPDATE、INSERT 和 DELETE 选项卡中的下拉列表设置为 (无)

图 6:将 UPDATE、INSERT 和 DELETE 选项卡中的下拉列表设置为(无)(单击可查看全尺寸图像

GetProductsAsPagedDataSource由于该方法需要两个输入参数,向导会提示我们输入这些参数值的源。

必须在回发时记住页面索引和页面大小值。 它们可以存储在视图状态、保存到查询字符串、存储在会话变量中,或使用一些其他技术进行记住。 在本教程中,我们将使用 querystring,它的优点是允许为特定数据页添加书签。

具体而言,请分别对pageIndexpageSize参数使用 querystring 字段 pageIndex 和 pageSize(请参阅图 7)。 请花点时间设置这些参数的默认值,因为当用户首次访问此页面时不会显示查询字符串值。 对于 pageIndex,将默认值设置为 0(这将显示数据的第一页), pageSize 并将默认值设置为 4。

使用 QueryString 作为 pageIndex 和 pageSize 参数的源

图 7:使用 QueryString 作为“源 pageIndex ”和 pageSize “参数”(单击可查看全尺寸图像

配置 ObjectDataSource 后,Visual Studio 会自动为 DataList 创建一个 ItemTemplateItemTemplate自定义,以便仅显示产品名称、类别和供应商。 此外,将 DataList 的属性 RepeatColumns 设置为 2,将其 Width 设置为 100%,其 ItemStyle s Width 设置为 50%。 这些宽度设置将为两列提供相等间距。

进行这些更改后,DataList 和 ObjectDataSource 的标记应如下所示:

<asp:DataList ID="ProductsDefaultPaging" runat="server" Width="100%"
    DataKeyField="ProductID" DataSourceID="ProductsDefaultPagingDataSource"
    RepeatColumns="2" EnableViewState="False">
    <ItemTemplate>
        <h4><asp:Label ID="ProductNameLabel" runat="server"
            Text='<%# Eval("ProductName") %>'></asp:Label></h4>
        Category:
        <asp:Label ID="CategoryNameLabel" runat="server"
            Text='<%# Eval("CategoryName") %>'></asp:Label><br />
        Supplier:
        <asp:Label ID="SupplierNameLabel" runat="server"
            Text='<%# Eval("SupplierName") %>'></asp:Label><br />
        <br />
        <br />
    </ItemTemplate>
    <ItemStyle Width="50%" />
</asp:DataList>
<asp:ObjectDataSource ID="ProductsDefaultPagingDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}" TypeName="ProductsBLL"
    SelectMethod="GetProductsAsPagedDataSource">
    <SelectParameters>
        <asp:QueryStringParameter DefaultValue="0" Name="pageIndex"
             QueryStringField="pageIndex" Type="Int32" />
        <asp:QueryStringParameter DefaultValue="4" Name="pageSize"
             QueryStringField="pageSize" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

注意

由于本教程中未执行任何更新或删除功能,因此可以禁用 DataList 视图状态以减少呈现的页面大小。

最初通过浏览器访问此页面时,既不提供查询pageIndex字符串参数,也不pageSize提供查询字符串参数。 因此,使用默认值 0 和 4。 如图 8 所示,这会导致 DataList 显示前四个产品。

前四个产品已列出

图 8:列出了前四个产品(单击以查看全尺寸图像

如果没有分页界面,用户当前没有直接的方法可以导航到第二页数据。 我们将在步骤 4 中创建分页接口。 不过,目前,只能通过直接在 querystring 中指定分页条件来完成分页。 例如,若要查看第二页,请将浏览器地址栏中的 URL 更改为 Paging.aspxPaging.aspx?pageIndex=2 Enter 并按 Enter。 这会导致显示第二页数据(请参阅图 9)。

DataList 窗口中分页数据的屏幕截图,其中显示了第二页数据。

图 9:显示第二页数据(单击以查看全尺寸图像

步骤 4:创建分页接口

可以实现各种不同的分页接口。 GridView、DetailsView 和 FormView 控件提供四个不同的接口可供选择:

  • 接下来,上 一个用户可以一次移动一个页面,移到下一个页面或上一个页面。
  • 接下来,除了“下一页”和“上一页”按钮外, 此界面还包括“第一个”和“最后一个”按钮,用于移动到第一页或最后一页。
  • 数字 列出了分页界面中的页码,允许用户快速跳转到特定页面。
  • 数字、第一页、最后 一页以及数字页码,包括用于移动到第一页或最后一页的按钮。

对于 DataList 和 Repeater,我们负责确定分页接口并实现它。 这涉及到在页面中创建所需的 Web 控件,并在单击特定分页界面按钮时显示请求的页面。 此外,可能需要禁用某些分页接口控件。 例如,使用 Next、Previous、First、Last 接口查看数据的第一页时,将禁用“第一个”和“上一”按钮。

在本教程中,让我们使用 Next、Previous、First、Last 接口。 向页面添加四个按钮 Web 控件,并将其ID设置为FirstPagePrevPageNextPageLastPage。 将 Text 属性设置为 << First、 < Prev、Next >和 Last >> 。

<asp:Button runat="server" ID="FirstPage" Text="<< First" />
<asp:Button runat="server" ID="PrevPage" Text="< Prev" />
<asp:Button runat="server" ID="NextPage" Text="Next >" />
<asp:Button runat="server" ID="LastPage" Text="Last >>" />

接下来,为每个按钮创建一个 Click 事件处理程序。 在片刻中,我们将添加显示请求的页面所需的代码。

记住正在分页的记录总数

无论选择何种分页接口,都需要计算并记住正在分页的记录总数。 总行计数(与页面大小结合使用)确定要分页的数据总页数,这决定了添加或启用哪些分页接口控件。 在要生成的下一个、上一个、最后一个接口中,页计数以两种方式使用:

  • 若要确定我们是否正在查看最后一页,在这种情况下,“下一步”和“最后一步”按钮处于禁用状态。
  • 如果用户单击“最后一个”按钮,则需要将它们移动到最后一页,其索引小于页计数。

页计数计算为总行计数的上限,除以页面大小。 例如,如果我们分页到每页有四条记录的 79 条记录,则页面计数为 20(上限为 79 / 4)。 如果使用数字分页接口,此信息将告知我们要显示的数值页按钮数;如果分页界面包含“下一个”或“最后一个”按钮,则页面计数用于确定何时禁用“下一个”或“最后一个”按钮。

如果分页界面包含“最后一个”按钮,则必须在回发中记住要翻页的记录总数,以便在单击“最后一个”按钮时,我们可以确定最后一页索引。 为此,请在 ASP.NET 页的代码隐藏类中创建一个 TotalRowCount 属性,该类保留其值以查看状态:

Private Property TotalRowCount() As Integer
    Get
        Dim o As Object = ViewState("TotalRowCount")
        If (o Is Nothing) Then
            Return -1
        Else
            Return Convert.ToInt32(o)
        End If
    End Get
    set(Value as Integer)
        ViewState("TotalRowCount") = value
    End Set
End Property

此外 TotalRowCount,请花一分钟时间创建只读页面级属性,以便轻松访问页面索引、页面大小和页计数:

Private ReadOnly Property PageIndex() As Integer
    Get
        If (Not String.IsNullOrEmpty(Request.QueryString("pageIndex"))) Then
            Return Convert.ToInt32(Request.QueryString("pageIndex"))
        Else
            Return 0
        End If
    End Get
End Property
Private ReadOnly Property PageSize() As Integer
    Get
        If (Not String.IsNullOrEmpty(Request.QueryString("pageSize"))) Then
            Return Convert.ToInt32(Request.QueryString("pageSize"))
        Else
            Return 4
        End If
    End Get
End Property
Private ReadOnly Property PageCount() As Integer
    Get
        If TotalRowCount <= 0 OrElse PageSize <= 0 Then
            Return 1
        Else
            Return ((TotalRowCount + PageSize) - 1) / PageSize
        End If
    End Get
End Property

确定正在分页的记录总数

PagedDataSource从 ObjectDataSource s Select() 方法返回的对象在所有产品记录中都有,即使只有其中一部分显示在 DataList 中。 该PagedDataSourceCount属性仅返回 DataList 中显示的项数;该DataSourceCount属性返回其中的PagedDataSource项总数。 因此,我们需要将 ASP.NET 页的属性TotalRowCount指定为 s PagedDataSource 属性的值DataSourceCount

为此,请为 ObjectDataSource 事件 Selected 创建事件处理程序。 在此事件处理程序中 Selected ,我们有权访问 ObjectDataSource s Select() 方法的返回值, PagedDataSource即 .

Protected Sub ProductsDefaultPagingDataSource_Selected(ByVal sender As Object, _
    ByVal e As System.Web.UI.WebControls.ObjectDataSourceStatusEventArgs) _
    Handles ProductsDefaultPagingDataSource.Selected
    ' Reference the PagedDataSource bound to the DataList
    Dim pagedData As PagedDataSource = CType(e.ReturnValue, PagedDataSource)
    ' Remember the total number of records being paged through across postbacks
    TotalRowCount = pagedData.DataSourceCount
End Sub

显示请求的数据页

当用户在分页界面中单击其中一个按钮时,我们需要显示请求的数据页。 由于分页参数是通过查询字符串指定的,为了显示请求的数据页,以便 Response.Redirect(url) 用户浏览器使用相应的分页参数重新请求 Paging.aspx 页面。 例如,若要显示第二页数据,我们将用户重定向到 Paging.aspx?pageIndex=1

为此,请创建一个 RedirectUser(sendUserToPageIndex) 将用户重定向到 Paging.aspx?pageIndex=sendUserToPageIndex的方法。 然后,从四个 Button Click 事件处理程序调用此方法。 在事件处理程序中FirstPageClick,调用RedirectUser(0),以将它们发送到第一页;在事件处理程序中PrevPageClick,用作PageIndex - 1页索引;依此等。

Protected Sub FirstPage_Click(ByVal sender As Object, ByVal e As EventArgs) _
    Handles FirstPage.Click
    ' Send the user to the first page
    RedirectUser(0)
End Sub
Protected Sub PrevPage_Click(ByVal sender As Object, ByVal e As EventArgs) _
    Handles PrevPage.Click
    ' Send the user to the previous page
    RedirectUser(PageIndex - 1)
End Sub
Protected Sub NextPage_Click(ByVal sender As Object, ByVal e As EventArgs) _
    Handles NextPage.Click
    ' Send the user to the next page
    RedirectUser(PageIndex + 1)
End Sub
Protected Sub LastPage_Click(ByVal sender As Object, ByVal e As EventArgs) _
    Handles LastPage.Click
    ' Send the user to the last page
    RedirectUser(PageCount - 1)
End Sub
Private Sub RedirectUser(ByVal sendUserToPageIndex As Integer)
    ' Send the user to the requested page
    Response.Redirect(String.Format("Paging.aspx?pageIndex={0}&pageSize={1}", _
        sendUserToPageIndex, PageSize))
End Sub

Click事件处理程序完成后,可以通过单击按钮来分页 DataList 的记录。 花点时间尝试一下!

禁用分页接口控件

目前,所有四个按钮都处于启用状态,而不考虑正在查看的页面。 但是,我们希望在显示第一页数据时禁用“第一页”和“上一页”按钮,在显示最后一页时禁用“下一页”和“最后一个”按钮。 PagedDataSource ObjectDataSource 方法Select()返回的对象具有属性IsFirstPageIsLastPage我们可以检查以确定我们是否正在查看数据的第一页或最后一页。

将以下内容添加到 ObjectDataSource 的 Selected 事件处理程序:

' Configure the paging interface based on the data in the PagedDataSource
FirstPage.Enabled = Not pagedData.IsFirstPage
PrevPage.Enabled = Not pagedData.IsFirstPage
NextPage.Enabled = Not pagedData.IsLastPage
LastPage.Enabled = Not pagedData.IsLastPage

添加后,查看第一页时将禁用“第一个”和“上一步”按钮,而查看最后一页时将禁用“下一步”和“最后一个”按钮。

让我们完成分页界面,方法是通知用户他们当前正在查看的页面以及总页数。 向页面添加标签 Web 控件并将其属性设置为 IDCurrentPageNumber。 在 ObjectDataSource s Selected 事件处理程序中设置其 Text 属性,使其包括正在查看的当前页(PageIndex + 1)和总页数(PageCount)。

' Display the current page being viewed...
CurrentPageNumber.Text = String.Format("You are viewing page {0} of {1}...", _
    PageIndex + 1, PageCount)

图 10 显示 Paging.aspx 首次访问时。 由于 querystring 为空,DataList 默认显示前四个产品:“第一个”和“上一个”按钮处于禁用状态。 单击“下一步”将显示接下来的四条记录(请参阅图 11):现在已启用“第一个”和“上一个”按钮。

显示第一页数据

图 10:显示数据的第一页(单击以查看全尺寸图像

显示 DataList 窗口中分页数据的页 2 的屏幕截图。

图 11:显示第二页数据(单击以查看全尺寸图像

注意

通过允许用户指定每页查看的页面数,可以进一步增强分页界面。 例如,可以添加 DropDownList 列表页面大小选项,例如 5、10、25、50 和 All。 选择页面大小后,需要将用户重定向回 Paging.aspx?pageIndex=0&pageSize=selectedPageSize。 我将实现此增强作为读者的练习。

使用自定义分页

DataList 使用低效的默认分页技术浏览其数据。 分页时,必须使用自定义分页。 尽管实现详细信息略有不同,但 DataList 中实现自定义分页背后的概念与默认分页相同。 使用自定义分页时,请使用 ProductBLL 类的方法 GetProductsPaged (而不是 GetProductsAsPagedDataSource)。 如“有效分页浏览大量数据”教程中所述GetProductsPaged必须传递起始行索引和要返回的最大行数。 可以通过查询字符串来维护这些参数, pageIndex 就像默认分页中使用的参数 pageSize 一样。

由于没有 PagedDataSource 自定义分页,因此必须使用替代方法来确定正在分页的记录总数以及我们是否显示数据的第一页或最后一页。 类 TotalNumberOfProducts() 中的 ProductsBLL 方法返回正在分页的产品总数。 若要确定正在查看数据的第一页,请检查起始行索引是否为零,然后查看第一页。 如果起始行索引加上要返回的最大行大于或等于正在分页的记录总数,则查看最后一页。

我们将在下一教程中更详细地探讨如何实现自定义分页。

总结

虽然 DataList 和 Repeater 都没有提供 GridView、DetailsView 和 FormView 控件中现成的分页支持,但可以尽量少地添加此类功能。 实现默认分页的最简单方法是包装整个产品集, PagedDataSource 然后将它绑定到 PagedDataSource DataList 或 Repeater。 在本教程中,我们将该方法添加到GetProductsAsPagedDataSourceProductsBLL类以返回 PagedDataSource. 该 ProductsBLL 类已包含自定义分页 GetProductsPagedTotalNumberOfProducts.

除了检索要为自定义分页显示的精确记录集或默认分页中的所有 PagedDataSource 记录之外,我们还需要手动添加分页接口。 在本教程中,我们创建了一个 Next、Previous、First、Last 接口,其中包含四个按钮 Web 控件。 此外,还添加了一个显示当前页码和总页数的标签控件。

在下一教程中,我们将了解如何向 DataList 和 Repeater 添加排序支持。 我们还将了解如何创建可分页和排序的 DataList(使用默认分页和自定义分页的示例)。

快乐编程!

关于作者

斯科特·米切尔,七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自1998年以来一直在与Microsoft Web 技术合作。 斯科特担任独立顾问、教练和作家。 他的最新书是 山姆斯在24小时内 ASP.NET 2.0。 可以通过 mitchell@4GuysFromRolla.com 联系到他。

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是 Liz Shulok、Ken Pespisa 和 Bernadette Leigh。 有兴趣查看即将发布的 MSDN 文章? 如果是这样,请给我写信。mitchell@4GuysFromRolla.com