分页 DataList 或 Repeater 控件中的报表数据 (VB)
虽然 DataList 和 Repeater 都不提供自动分页或排序支持,但本教程演示如何向 DataList 或 Repeater 添加分页支持,从而允许更灵活的分页和数据显示接口。
简介
分页和排序是联机应用程序中显示数据的两个非常常见的功能。 例如,在联机书店搜索 ASP.NET 书籍时,可能有数百种此类书籍,但列出搜索结果的报告每页仅列出十个匹配项。 此外,结果可以按标题、价格、页计数、作者姓名等进行排序。 正如我们在 分页和排序报表数据 教程中所述,GridView、DetailsView 和 FormView 控件都提供内置分页支持,可在勾选复选框时启用。 GridView 还包括排序支持。
遗憾的是,DataList 和 Repeater 都不提供自动分页或排序支持。 本教程介绍如何向 DataList 或 Repeater 添加分页支持。 我们必须手动创建分页界面,显示相应的记录页,并记住跨回发访问的页面。 虽然这确实比使用 GridView、DetailsView 或 FormView 花费更多的时间和代码,但 DataList 和 Repeater 允许更灵活的分页和数据显示接口。
注意
本教程专门重点介绍分页。 在下一教程中,我们将把注意力转向添加排序功能。
步骤 1:添加分页和排序教程网页
在开始本教程之前,让我们先花点时间添加本教程所需的 ASP.NET 页面和下一页。 首先,在名为 PagingSortingDataListRepeater
的项目中创建一个新文件夹。 接下来,将以下五个 ASP.NET 页添加到此文件夹,使其全部配置为使用母版页 Site.master
:
Default.aspx
Paging.aspx
Sorting.aspx
SortingWithDefaultPaging.aspx
SortingWithCustomPaging.aspx
图 1:创建 PagingSortingDataListRepeater
文件夹并添加教程 ASP.NET 页面
接下来,打开 Default.aspx
页面,将“用户控件” SectionLevelTutorialListing.ascx
从 UserControls
文件夹拖到“设计”图面上。 我们在 母版页和网站导航 教程中创建的此用户控件枚举网站地图,并在项目符号列表的当前部分中显示这些教程。
图 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>
图 3:更新站点地图以包含新 ASP.NET 页
分页回顾
在前面的教程中,我们了解了如何在 GridView、DetailsView 和 FormView 控件中分页浏览数据。 这三个控件提供了一种称为 默认分页的简单分页 形式,只需选中控件智能标记中的“启用分页”选项即可实现。 使用默认分页时,每次在访问第一页时请求数据页,或者当用户导航到其他数据页时,GridView、DetailsView 或 FormView 控件都会从 ObjectDataSource 重新请求 所有数据 。 然后,根据请求的页面索引和每页要显示的记录数,它会截取要显示的特定记录集。 我们在分 页和排序报表数据 教程中详细讨论了默认分页。
由于默认分页会重新请求每个页面的所有记录,因此在分页浏览足够大量的数据时是不切实际的。 例如,假设分页浏览 50,000 条页面大小为 10 的记录。 每次用户移动到新页面时,都必须从数据库中检索所有 50,000 条记录,即使其中仅显示 10 条记录。
自定义分页 通过仅获取要显示在所请求页面上的精确记录子集来解决默认分页的性能问题。 实现自定义分页时,必须编写 SQL 查询,以便有效地返回正确的记录集。 在高效分页大量数据教程中,我们了解了如何使用 SQL Server 2005 年的新ROW_NUMBER()
关键字 (keyword) 创建此类查询。
若要在 DataList 或 Repeater 控件中实现默认分页,可以使用 PagedDataSource
类 作为对内容进行分页的 包装器 ProductsDataTable
。 类 PagedDataSource
具有一个 DataSource
属性,该属性可以分配给任何可枚举对象和 PageSize
和 CurrentPageIndex
属性,这些属性指示每页要显示多少条记录和当前页索引。 设置这些属性后, PagedDataSource
即可将 用作任何数据 Web 控件的数据源。 PagedDataSource
枚举 时,将仅返回其内部DataSource
基于 PageSize
和 CurrentPageIndex
属性的相应记录子集。 图 4 描述了 类的功能 PagedDataSource
。
图 4:使用 PagedDataSource
可分页接口包装可枚举对象
PagedDataSource
可以直接从业务逻辑层创建和配置对象,并通过 ObjectDataSource 绑定到 DataList 或 Repeater,也可以直接在 ASP.NET 页代码隐藏类中创建和配置。 如果使用后一种方法,则必须放弃使用 ObjectDataSource,而是以编程方式将分页数据绑定到 DataList 或 Repeater。
对象 PagedDataSource
还具有支持自定义分页的属性。 但是,我们可以绕过使用 PagedDataSource
自定义分页的 ,因为我们在类中 ProductsBLL
已有 BLL 方法,这些方法专为返回要显示的精确记录的自定义分页而设计。
在本教程中,我们将通过向返回正确配置的 PagedDataSource
对象的类添加新方法,ProductsBLL
了解如何在 DataList 中实现默认分页。 在下一教程中,我们将了解如何使用自定义分页。
步骤 2:在业务逻辑层中添加默认分页方法
类 ProductsBLL
当前有一个方法用于返回所有产品信息 GetProducts()
,一个用于返回起始索引 GetProductsPaged(startRowIndex, maximumRows)
处的特定产品子集。 使用默认分页时,GridView、DetailsView 和 FormView 控件都使用 GetProducts()
方法检索所有产品,但在内部使用 PagedDataSource
仅显示正确的记录子集。 若要使用 DataList 和 Repeater 控件复制此功能,可以在 BLL 中创建一个模拟此行为的新方法。
将方法添加到名为 GetProductsAsPagedDataSource
的类,ProductsBLL
该方法采用两个整数输入参数:
pageIndex
要显示的页面的索引,索引为零,以及pageSize
每页要显示的记录数。
GetProductsAsPagedDataSource
首先从 GetProducts()
中检索所有记录。 然后,它会创建一个 PagedDataSource
对象,将其 CurrentPageIndex
和 PageSize
属性设置为传入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
,将“工具箱”中的 PagingSortingDataListRepeater
DataList 拖到Designer,并将 DataList 的 ID
属性设置为 ProductsDefaultPaging
。 在 DataList 的智能标记中,创建名为 ProductsDefaultPagingDataSource
的新 ObjectDataSource 并对其进行配置,以便它使用 GetProductsAsPagedDataSource
方法检索数据。
图 5:创建 ObjectDataSource 并将其配置为使用 GetProductsAsPagedDataSource
()
方法 (单击以查看全尺寸图像)
将“更新”、“插入”和“删除”选项卡中的下拉列表设置为 (“无”) 。
图 6:将“更新”、“插入”和“删除”选项卡中的 Drop-Down Lists 设置为“ (无”) (单击以查看全尺寸图像)
GetProductsAsPagedDataSource
由于 方法需要两个输入参数,因此向导会提示我们输入这些参数值的源。
必须跨回发记住页面索引和页面大小值。 它们可以以视图状态存储、持久保存到查询字符串、存储在会话变量中或使用某种其他技术进行记住。 在本教程中,我们将使用 querystring,它的优点是允许为特定数据页添加书签。
具体而言,请分别对 pageIndex
和 pageSize
参数使用查询字符串字段 pageIndex 和 pageSize, (请参阅图 7) 。 请花点时间设置这些参数的默认值,因为当用户首次访问此页面时,查询字符串值将不存在。 对于 pageIndex
,将默认值设置为 0 (这将显示数据) 的第一页, pageSize
默认值为 4。
图 7:使用 QueryString 作为 和 pageSize
参数的源 pageIndex
(单击 以查看全尺寸图像)
配置 ObjectDataSource 后,Visual Studio 会自动为 DataList 创建 ItemTemplate
。 自定义 , ItemTemplate
以便仅显示产品名称、类别和供应商。 此外,将 DataList 的 RepeatColumns
属性设置为 2,将其 Width
设置为 100%,其 ItemStyle
设置为 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.aspx
更改为 Paging.aspx?pageIndex=2
,然后按 Enter。 这会导致显示第二页数据 (见图 9) 。
图 9:显示第二页数据 (单击以查看全尺寸图像)
步骤 4:创建分页接口
可以实现各种不同的分页接口。 GridView、DetailsView 和 FormView 控件提供四种不同的接口供你选择:
- 接下来,上 一个用户可以一次将一个页面移动到下一页或上一页。
- 除了“下一页 ”和“上一页”按钮外,此界面还包括“第一页”和“最后一页”按钮,用于移动到第一页或最后一页。
- 数值 列出分页界面中的页码,使用户能够快速跳转到特定页面。
- 除数字页码外,“数字”、“第一页”、“最后一页”还包括用于移动到第一页或最后一页的按钮。
对于 DataList 和 Repeater,我们负责决定并实现分页接口。 这涉及到在页面中创建所需的 Web 控件,并在单击特定的分页界面按钮时显示请求的页面。 此外,可能需要禁用某些分页接口控件。 例如,使用“下一页”、“上一页”、“第一页”、“最后一页”界面查看数据时,将禁用“第一页”和“上一页”按钮。
在本教程中,我们将使用 Next、Previous、First、Last 接口。 将四个按钮 Web 控件添加到页面,并将其 ID
FirstPage
设置为 、 PrevPage
、 NextPage
和 LastPage
。 将 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
事件处理程序。 稍后,我们将添加显示所请求页面所需的代码。
记住正在分页的记录总数
无论选择哪种分页接口,都需要计算并记住正在分页的记录总数。 总行计数 (与页面大小) 确定要分页的数据的总页数,这决定了要添加或启用哪些分页接口控件。 在我们正在构建的 Next、Previous、First、Last 接口中,页面计数以两种方式使用:
- 确定我们是否正在查看最后一页,在这种情况下禁用“下一页”和“最后一页”按钮。
- 如果用户单击“最后一个”按钮,则需要将他们转到最后一页,其索引比页计数少一个。
页面计数按总行计数上限除以页面大小计算。 例如,如果我们分页 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 方法返回的对象Select()
包含所有产品记录,即使 DataList 中只显示其中的一部分。 PagedDataSource
属性Count
仅返回将在 DataList 中显示的项数;DataSourceCount
属性返回 中的PagedDataSource
项总数。 因此,我们需要为 ASP.NET 页属性TotalRowCount
分配 s DataSourceCount
属性的值PagedDataSource
。
为此,请为 ObjectDataSource 事件 Selected
创建事件处理程序。 在此 Selected
事件处理程序中,我们可以访问 ObjectDataSource 方法的 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
显示请求的数据页
当用户单击分页界面中的其中一个按钮时,我们需要显示请求的数据页。 由于分页参数是通过 querystring 指定的,若要显示请求的数据页,请使用 Response.Redirect(url)
让用户浏览器使用相应的分页参数重新请求 Paging.aspx
页面。 例如,为了显示第二页数据,我们将用户重定向到 Paging.aspx?pageIndex=1
。
为此,请创建一个 RedirectUser(sendUserToPageIndex)
将用户重定向到 Paging.aspx?pageIndex=sendUserToPageIndex
的方法。 然后,从四个 Button Click
事件处理程序调用此方法。 在事件处理程序中 FirstPage
Click
,调用 RedirectUser(0)
以将它们发送到第一页;在事件处理程序中 PrevPage
Click
,使用 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()
具有属性,IsLastPage
我们可以检查这些属性IsFirstPage
以确定我们查看的是数据的第一页还是最后一页。
将以下内容添加到 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 控件添加到页面,并将其 ID
属性设置为 CurrentPageNumber
。 在 ObjectDataSource 的 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:显示数据的第一页 (单击以查看全尺寸图像)
图 11:显示第二页数据 (单击以查看全尺寸图像)
注意
通过允许用户指定每页查看的页面数,可以进一步增强分页界面。 例如,可以添加 DropDownList,列出页面大小选项,如 5、10、25、50 和全部。 选择页面大小后,需要将用户重定向回 Paging.aspx?pageIndex=0&pageSize=selectedPageSize
。 我将实现此增强作为读者的练习。
使用自定义分页
DataList 使用低效的默认分页技术通过其数据进行分页。 在对足够大量的数据进行分页时,必须使用自定义分页。 尽管实现细节略有不同,但在 DataList 中实现自定义分页背后的概念与默认分页相同。 使用自定义分页时,使用 ProductBLL
类 s GetProductsPaged
方法 (而不是 GetProductsAsPagedDataSource
) 。 如 高效分页大量数据 教程中所述, GetProductsPaged
必须传递起始行索引和要返回的最大行数。 可以通过查询字符串维护这些参数,就像默认分页中使用的 和 pageSize
参数一样pageIndex
。
由于没有 PagedDataSource
自定义分页,因此必须使用替代技术来确定正在分页的记录总数,以及是要显示数据的第一页还是最后一页。 TotalNumberOfProducts()
类中的 ProductsBLL
方法返回正在分页的产品的总数。 若要确定是否正在查看第一页数据,请检查起始行索引(如果为零),然后查看第一页。 如果起始行索引加上要返回的最大行数大于或等于正在分页的记录总数,则查看最后一页。
我们将在下一教程中更详细地探讨如何实现自定义分页。
总结
虽然 DataList 和 Repeater 都不提供 GridView、DetailsView 和 FormView 控件中现成的分页支持,但只需最少的工作量即可添加此类功能。 实现默认分页的最简单方法是将整个产品集包装在 中, PagedDataSource
然后将 绑定到 PagedDataSource
DataList 或 Repeater。 在本教程中,我们已将 GetProductsAsPagedDataSource
方法添加到 类以 ProductsBLL
返回 PagedDataSource
。 类 ProductsBLL
已包含自定义分 GetProductsPaged
页和 TotalNumberOfProducts
所需的方法。
除了检索要为自定义分页显示的精确记录集或默认分页中 PagedDataSource
的所有记录之外,我们还需要手动添加分页接口。 在本教程中,我们创建了一个包含四个 Button Web 控件的 Next、Previous、First、Last 接口。 此外,还添加了显示当前页码和总页数的 Label 控件。
在下一教程中,我们将了解如何向 DataList 和 Repeater 添加排序支持。 我们还将介绍如何使用默认分页和自定义分页) 创建可分页和排序 (的 DataList。
编程愉快!
关于作者
Scott Mitchell 是七本 ASP/ASP.NET 书籍的作者, 4GuysFromRolla.com 的创始人,自 1998 年以来一直从事 Microsoft Web 技术工作。 Scott 担任独立顾问、培训师和作家。 他的最新书是 山姆斯在24小时内 ASP.NET 2.0自学。 可以在 上联系 mitchell@4GuysFromRolla.com他, 也可以通过他的博客联系到他,该博客可在 http://ScottOnWriting.NET中找到。
特别感谢
本教程系列由许多有用的审阅者查看。 本教程的主要审阅者是 Liz Shulok、Ken Pespisa 和 Bernadette Leigh。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处放置一行 mitchell@4GuysFromRolla.com。
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈