ASP.NET ListView 控件实现高效分页






4.95/5 (35投票s)
为了开发可扩展的应用程序,高效的分页是必不可少的。没有智能高效的分页和排序来处理海量数据会消耗额外的时间和系统资源。
引言
如果我们想开发一个可扩展的应用程序,分页对于处理海量数据来说是一件重要的事情。有时,这可能需要自定义用户界面以及分页功能。ASP.NET 的 ListView
是一个可以用来提供支持分页的用户界面或布局的控件。
背景
我将开发一个 ASP.NET Web 应用程序,使用 ListView 控件来展示如何通过分页和排序有效地构建可扩展的应用程序。
开始吧
在我们开始之前,您可以阅读我的第一篇关于分页的文章 ASP.NET GridView 控件实现高效分页。
打开 Microsoft SQL Server Management Studio 2005。按照以下结构设计一个表,或者您可以采用不同的结构。
Profile 表中的一些记录。
ListView 控件实现高效分页
为了实现有效的分页和排序,第一步是在 SQL 中创建存储过程。
- 打开 SQL Server Management Studio
- 新建查询
在您的数据库中创建一个带有某种技术的存储过程,用于从 Profile 表中检索记录。例如下面的 SQL
CREATE PROCEDURE [dbo].[Profile_GET]
@PageSize int = null,
@CurrentPage int = null,
@SortExpression nvarchar(max) = null
AS
BEGIN
SET NOCOUNT ON
DECLARE @SqlString nvarchar(max)
Declare @UpperBand int
Declare @LowerBand int
SET @LowerBand = (@CurrentPage - 1) * @PageSize
SET @UpperBand = (@CurrentPage * @PageSize) + 1
BEGIN
WITH tempProfile AS
(
SELECT
[ProfileId],
[Name],
[Address],
[Email],
[Mobile],
[IsActive] = CASE [IsActive] WHEN 1 THEN 'Active' _
WHEN 0 THEN 'DeActive' END,
ROW_NUMBER() OVER (ORDER BY ProfileId ASC ) AS RowNumber
FROM [dbo].[Profile]
)
SELECT
[ProfileId],
[Name],
[Address],
[Email],
[Mobile],
[IsActive]
FROM
tempProfile
WHERE
RowNumber > @LowerBand AND RowNumber < @UpperBand
ORDER BY
CASE WHEN @SortExpression ='ProfileId' _
THEN [ProfileId] END,
CASE WHEN @SortExpression ='ProfileId DESC' _
THEN [ProfileId] END DESC,
CASE WHEN @SortExpression ='Name' THEN [Name] END,
CASE WHEN @SortExpression ='Name DESC' _
THEN [Name] END DESC,
CASE WHEN @SortExpression ='Address' _
THEN [Address] END,
CASE WHEN @SortExpression ='Address DESC' _
THEN [Address] END DESC,
CASE WHEN @SortExpression ='Email' THEN [Email] END,
CASE WHEN @SortExpression ='Email DESC' _
THEN [Email] END DESC,
CASE WHEN @SortExpression ='Mobile' THEN [Mobile] END,
CASE WHEN @SortExpression ='Mobile DESC' _
THEN [Mobile] END DESC,
CASE WHEN @SortExpression ='Status' _
THEN [IsActive] END,
CASE WHEN @SortExpression ='Status DESC' _
THEN [IsActive] END DESC
END
END
Profile_GET
存储过程接受 PageSize
、CurrentPage
和 SortExpression
作为输入参数。PageSize
- 是 ListView
每页显示的记录数。CurrentPage
– 是您当前在 ListView
中的页码。
SortExpression
– 按哪个字段对页内记录进行排序。以上所有参数将在应用程序运行时由 ListView
控件和 Web 页面的 DataPage
传递。
SET @LowerBand = (@CurrentPage - 1) * @PageSize
SET @UpperBand = (@CurrentPage * @PageSize) + 1
以上两个表达式将计算每页的上限和下限。下限表示每页的起始行位置,上限表示每页的顶部行位置。假设您当前是第 5 页,每页大小为 5。那么以上两个表达式的结果是
LowerBand = (5 -1) * 5 = 20
UpperBand = (5 * 5) + 1 = 26
因此,持有位置编号 21-25 的记录(因为我在该存储过程后面的 where
条件中使用了大于和小于)将由这些表达式返回。
WITH tempProfile AS
(
SELECT
[ProfileId],
[Name],
[Address],
[Email],
[Mobile],
[IsActive] = CASE [IsActive] WHEN 1 THEN 'Active' _
WHEN 0 THEN 'DeActive' END,
ROW_NUMBER() OVER (ORDER BY
CASE @SortExpression WHEN 'ProfileId' _
THEN [ProfileId] END,
CASE @SortExpression WHEN 'Name' THEN [Name] END,
CASE @SortExpression WHEN 'Address' _
THEN [Address] END,
CASE @SortExpression WHEN 'Email' THEN [Email] END,
CASE @SortExpression WHEN 'Mobile' THEN [Mobile] END,
CASE @SortExpression WHEN 'Status' _
THEN [IsActive] END
) AS RowNumber
FROM [dbo].[Profile]
)
紧跟在表名之后的上述 SQL 语句将从其主体中的 SELECT
SQL 语句生成一个临时表。
ROW_NUMBER() OVER (ORDER BY
CASE @SortExpression WHEN 'ProfileId' THEN [ProfileId] END,
CASE @SortExpression WHEN 'Name' THEN [Name] END,
CASE @SortExpression WHEN 'Address' THEN [Address] END,
CASE @SortExpression WHEN 'Email' THEN [Email] END,
CASE @SortExpression WHEN 'Mobile' THEN [Mobile] END,
CASE @SortExpression WHEN 'Status' THEN [IsActive] END
) AS RowNumber
上述 SQL 语句将向名为 tempProfile
的临时表中添加一个名为 RowNumber
的附加列,并在按排序表达式参数升序排序后为临时表中的每条记录分配一个连续的编号。这个 RowNumber
列将在稍后用于分页。
临时 tempProfile
表中的一些记录,其中记录已按 Profile Id 排序。现在,根据 PageSize
、CurrentPage
和 SortExpresssion
参数的请求过滤记录。
SELECT
[ProfileId],
[Name],
[Address],
[Email],
[Mobile],
[IsActive]
FROM
tempProfile
WHERE
RowNumber > @LowerBand AND RowNumber < @UpperBand
ORDER BY
CASE WHEN @SortExpression ='ProfileId' THEN [ProfileId] END,
CASE WHEN @SortExpression ='ProfileId DESC' _
THEN [ProfileId] END DESC,
CASE WHEN @SortExpression ='Name' THEN [Name] END,
CASE WHEN @SortExpression ='Name DESC' THEN [Name] END DESC,
CASE WHEN @SortExpression ='Address' THEN [Address] END,
CASE WHEN @SortExpression ='Address DESC' _
THEN [Address] END DESC,
CASE WHEN @SortExpression ='Email' THEN [Email] END,
CASE WHEN @SortExpression ='Email DESC' THEN [Email] END DESC,
CASE WHEN @SortExpression ='Mobile' THEN [Mobile] END,
CASE WHEN @SortExpression ='Mobile DESC' _
THEN [Mobile] END DESC,
CASE WHEN @SortExpression ='Status' THEN [IsActive] END,
CASE WHEN @SortExpression ='Status DESC' _
THEN [IsActive] END DESC
现在,您需要创建另一个存储过程。
CREATE PROCEDURE [dbo].[Profile_Total]
AS
BEGIN
SET NOCOUNT ON
SELECT COUNT(*) FROM Profile
END
上面的 Profile_Total
将返回总记录数。
在 Visual Studio 2010 中创建 ASP.NET 网站
- 创建一个网站项目,并将其命名为 PagingWithListView
- 添加一个 Web 窗体,并将其命名为 PagingWithListView.aspx
在 Web 窗体上添加 ListView
。将其重命名为 lstProfileView。定义布局模板。
<LayoutTemplate>
<table cellpadding="0" cellspacing="0" border="0" width="70%">
<tr>
<td>
<h3 class="title">Effective Paging With List View Control in ASP.NET</h3>
</td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td colspan="6" style="background-color: #9BAAC1;
font-family: Arial; font-weight: bold;text-align: removed;
padding: 4px 2px">PROFILES
</td>
</tr>
<tr>
<td colspan="6" style="background-color: #384B69">
<table id="tlbProfile" runat="server"
cellspacing="0"
cellpadding="0" border="0" width="100%">
<tr>
<th align="removed"
style="width: 10%" class="column_head">
<asp:LinkButton ID="lnkProfileId"
runat="server"
Text="ProfileId" Style="color: #FFFFFF"
CommandName="Sort" CommandArgument="ProfileId" />
<asp:Image runat="server" ID="SortImage1"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 15%;"
class="column_head">
<asp:LinkButton ID="lnkName" runat="server"
Text="Name" Style="color: #FFFFFF"
CommandName="Sort" CommandArgument="Name" />
<asp:Image runat="server" ID="SortImage2"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 20%"
class="column_head">
<asp:LinkButton ID="lnkAddress" runat="server"
Text="Address" Style="color: #FFFFFF"
CommandName="Sort" CommandArgument="Address" />
<asp:Image runat="server" ID="SortImage3"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 15%"
class="column_head">
<asp:LinkButton ID="lnkEmail" runat="server"
Text="Email" Style="color: #FFFFFF"
CommandName="Sort" CommandArgument="Email" />
<asp:Image runat="server" ID="SortImage4"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
<th align="removed" style="width:12%"
class="column_head">
<asp:LinkButton ID="lnkMobile" runat="server"
Text="Mobile" Style="color: #FFFFFF"
CommandName="Sort" CommandArgument="Mobile" />
<asp:Image runat="server" ID="SortImage5"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 15%;
padding-left: 2px;">
<asp:LinkButton ID="lnkStatus"
runat="server" Text="Status"
Style="color: #FFFFFF" CommandName="Sort"
CommandArgument="Status" />
<asp:Image runat="server" ID="SortImage6"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
</tr>
<tr id="itmPlaceholder" runat="server">
</tr>
</table>
</td>
</tr>
<tr style="height: 10px;">
<td colspan="6">
</td>
</tr>
<tr>
<td>
<asp:DataPager ID="dataPagerNumeric"
runat="server" PageSize="5">
<Fields>
<asp:NumericPagerField ButtonCount="5"
NumericButtonCssClass="numeric_button"
CurrentPageLabelCssClass="current_page"
NextPreviousButtonCssClass="next_button" />
</Fields>
</asp:DataPager>
<td colspan="4" class="number_of_record">
<asp:DataPager ID="dataPageDisplayNumberOfPages"
runat="server" PageSize="5">
<Fields>
<asp:TemplatePagerField>
<PagerTemplate>
<span style="color: Black;">Records:
<%# Container.StartRowIndex >= 0 ?
(Container.StartRowIndex + 1) : 0 %> -
<%# (Container.StartRowIndex +
Container.PageSize)
> Container.TotalRowCount ?
Container.TotalRowCount :
(Container.StartRowIndex +
Container.PageSize)%> of
<%# Container.TotalRowCount %>
</span>
</PagerTemplate>
</asp:TemplatePagerField>
</Fields>
</asp:DataPager>
</td>
</td>
</tr>
</table>
</LayoutTemplate>
我使用了 HTML Table 来提供布局模板。
<tr>
<td>
<h3 class="title">
Effective Paging With List View Control in ASP.NET</h3>
</td>
</tr>
上面的标记是用于标题的。
<tr>
<td colspan="6" style="background-color: #9BAAC1; font-family: Arial;
font-weight: bold; text-align: removed; padding: 4px 2px">
PROFILES
</td>
</tr>
上面的标记是用于列表标题的。
<tr>
<td colspan="6" style="background-color: #384B69">
<table id="tlbProfile" runat="server"
cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<th align="removed" style="width: 10%"
class="column_head">
<asp:LinkButton ID="lnkProfileId"
runat="server" Text="ProfileId"
Style="color: #FFFFFF" CommandName="Sort"
CommandArgument="ProfileId" />
<asp:Image runat="server" ID="SortImage1"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 15%;"
class="column_head">
<asp:LinkButton ID="lnkName" runat="server"
Text="Name" Style="color: #FFFFFF"
CommandName="Sort" CommandArgument="Name" />
<asp:Image runat="server" ID="SortImage2"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 20%"
class="column_head">
<asp:LinkButton ID="lnkAddress" runat="server"
Text="Address" Style="color: #FFFFFF"
CommandName="Sort" CommandArgument="Address" />
<asp:Image runat="server" ID="SortImage3"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 15%" class="column_head">
<asp:LinkButton ID="lnkEmail" runat="server"
Text="Email" Style="color: #FFFFFF"
CommandName="Sort" CommandArgument="Email" />
<asp:Image runat="server" ID="SortImage4"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
<th align="removed" style="width:12%"
class="column_head">
<asp:LinkButton ID="lnkMobile" runat="server"
Text="Mobile" Style="color: #FFFFFF"
CommandName="Sort" CommandArgument="Mobile" />
<asp:Image runat="server" ID="SortImage5"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 15%; padding-left: 2px;">
<asp:LinkButton ID="lnkStatus" runat="server"
Text="Status" Style="color: #FFFFFF"
CommandName="Sort" CommandArgument="Status" />
<asp:Image runat="server" ID="SortImage6"
ImageUrl="~/Images/asc.png" Visible="false"
Width="15" Height="15" class="sort_image"/>
</th>
</tr>
<tr id="itmPlaceholder" runat="server">
</tr>
</table>
</td>
</tr>
上面的标记是用于列头的。您必须定义占位符 - ListView 需要它。
<tr id="itmPlaceholder" runat="server">
</tr>
在 ASPX 页面中添加两个数据分页器。
<tr>
<td>
<asp:DataPager ID="dataPagerNumeric"
runat="server" PageSize="5">
<Fields>
<asp:NumericPagerField ButtonCount="5"
NumericButtonCssClass="numeric_button"
CurrentPageLabelCssClass="current_page"
NextPreviousButtonCssClass="next_button" />
</Fields>
</asp:DataPager>
<td colspan="4" class="number_of_record">
<asp:DataPager ID="dataPageDisplayNumberOfPages"
runat="server" PageSize="5">
<Fields>
<asp:TemplatePagerField>
<PagerTemplate>
<span style="color: Black;">Records:
<%# Container.StartRowIndex >= 0 ?
(Container.StartRowIndex + 1) : 0 %> -
<%# (Container.StartRowIndex + Container.PageSize) >
Container.TotalRowCount ? Container.TotalRowCount :
(Container.StartRowIndex + Container.PageSize)%> of
<%# Container.TotalRowCount %>
</span>
</PagerTemplate>
</asp:TemplatePagerField>
</Fields>
</asp:DataPager>
</td>
</td>
</tr>
<asp:DataPager ID="dataPagerNumeric"
runat="server" PageSize="5">
<Fields>
<asp:NumericPagerField ButtonCount="5"
NumericButtonCssClass="numeric_button"
CurrentPageLabelCssClass="current_page"
NextPreviousButtonCssClass="next_button" />
</Fields>
</asp:DataPager>
上面的标记是用于数字按钮的。

我添加了一些 CSS 类来设计它。
.numeric_button
{
background-color:#384B69;
color:#FFFFFF;
font-family:Arial;
font-weight:bold;
padding:2px;
border:none;
}
.current_page
{
background-color:#09151F;
color:#FFFFFF;
font-family:Arial;
font-weight:bold;
padding:2px;
}
.next_button
{
background-color:#1F3548;
color:#FFFFFF;
font-family:Arial;
font-weight:bold;
padding:2px;
}
<td colspan="4" class="number_of_record">
<asp:DataPager ID="dataPageDisplayNumberOfPages" runat="server" PageSize="5">
<Fields>
<asp:TemplatePagerField>
<PagerTemplate>
<span style="color: Black;">Records:
<%# Container.StartRowIndex >= 0 ? (Container.StartRowIndex + 1) : 0 %> -
<%# (Container.StartRowIndex + Container.PageSize) >
Container.TotalRowCount ? Container.TotalRowCount :
(Container.StartRowIndex + Container.PageSize)%> of
<%# Container.TotalRowCount %>
</span>
</PagerTemplate>
</asp:TemplatePagerField>
</Fields>
</asp:DataPager>
</td>
上面的标记是用于记录数的。
现在添加 EmptyDataTemplate
。如果数据不可用,将显示它。
<EmptyDataTemplate>
<table class="empty_data" runat="server">
<tr>
<td>No data found.</td>
</tr>
</table>
</EmptyDataTemplate>
添加 ItemTemplate
<ItemTemplate>
<tr>
<td align="removed" style="width: 7%;"
class='<%# Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblProfileId"
runat="server" Width="65" />
</td>
<td align="removed" style="width: 10%;"
class='<%# Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblName" runat="server" />
</td>
<td align="removed" style="
width: 25%;" class='<%# Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblAddress" runat="server" />
</td>
<td align="removed" style="width: 25%;"
class='<%# Container.DataItemIndex % 2 == 0 ? "
alternate_row" : "row" %>'>
<asp:Label ID="lblEmail" runat="server" />
</td>
<td align="removed" style="width: 15%;"
class='<%# Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblMobile" runat="server" />
</td>
<td align="removed" style="width: 8%;
" class='<%# Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblStatus" runat="server" />
</td>
</tr>
</ItemTemplate>
上面的标记实际上显示了记录。
class='<%# Container.DataItemIndex % 2 == 0 ? "alternate_row" : "row" %>'
上面的代码是用于通过 CSS 类为每个交替行设置颜色的。如果行号除以 2,则它是交替行,并分配 alternate_row
CSS 类,否则它是常规行,并分配 row
类。
.alternate_row
{
background-color:#D9DEE7;
border-right:1px solid #FFFFFF;
padding-left:2px;
}
.row
{
background-color:#FFFFFF;
border-right:1px solid #FFFFFF;
padding-left:2px;
}
行和交替行。
全部集合
<asp:ListView ID="lstProfileView" runat="server"
DataSourceID="odsPforile" DataKeyNames="ProfileId"
ItemPlaceholderID="itmPlaceholder"
OnItemDataBound="Profile_ItemDataBound"
OnSorting="Profile_Sorting">
<LayoutTemplate>
<table cellpadding="0" cellspacing="0"
border="0" width="70%">
<tr>
<td>
<h3 class="title">
Effective Paging With List View Control in ASP.NET</h3>
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td colspan="6" style="
background-color: #9BAAC1; font-family: Arial; font-weight: bold;
text-align: left; padding: 4px 2px">
PROFILES
</td>
</tr>
<tr>
<td colspan="6" style="background-color: #384B69">
<table id="tlbProfile"
runat="server" cellspacing="0"
cellpadding="0" border="0"
width="100%">
<tr>
<th align="removed"
style="width: 10%" class="column_head">
<asp:LinkButton ID="lnkProfileId"
runat="server" Text="ProfileId"
Style="color: #FFFFFF"
CommandName="Sort"
CommandArgument="ProfileId" />
<asp:Image runat="server"
ID="SortImage1"
ImageUrl="~/Images/asc.png"
Visible="false" Width="15"
Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 15%;"
class="column_head">
<asp:LinkButton ID="lnkName"
runat="server" Text="Name"
Style="color: #FFFFFF" CommandName="Sort"
CommandArgument="Name" />
<asp:Image runat="server"
ID="SortImage2" ImageUrl="~/Images/asc.png"
Visible="false" Width="15"
Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 20%"
class="column_head">
<asp:LinkButton ID="lnkAddress"
runat="server" Text="Address"
Style="color: #FFFFFF"
CommandName="Sort"
CommandArgument="Address" />
<asp:Image runat="server"
ID="SortImage3" ImageUrl="~/Images/asc.png"
Visible="false" Width="15"
Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 15%"
class="column_head">
<asp:LinkButton ID="lnkEmail"
runat="server" Text="Email"
Style="color: #FFFFFF"
CommandName="Sort"
CommandArgument="Email" />
<asp:Image runat="server"
ID="SortImage4"
ImageUrl="~/Images/asc.png"
Visible="false" Width="15"
Height="15" class="sort_image"/>
</th>
<th align="removed" style="width:12%"
class="column_head">
<asp:LinkButton ID="lnkMobile"
runat="server" Text="Mobile"
Style="color: #FFFFFF"
CommandName="Sort"
CommandArgument="Mobile" />
<asp:Image runat="server"
ID="SortImage5"
ImageUrl="~/Images/asc.png"
Visible="false" Width="15"
Height="15" class="sort_image"/>
</th>
<th align="removed" style="width: 15%;
padding-left: 2px;">
<asp:LinkButton ID="lnkStatus"
runat="server" Text="Status"
Style="color: #FFFFFF"
CommandName="Sort"
CommandArgument="Status" />
<asp:Image runat="server"
ID="SortImage6"
ImageUrl="~/Images/asc.png"
Visible="false" Width="15"
Height="15" class="sort_image"/>
</th>
</tr>
<tr id="itmPlaceholder" runat="server">
</tr>
</table>
</td>
</tr>
<tr style="height: 10px;">
<td colspan="6">
</td>
</tr>
<tr>
<td>
<asp:DataPager ID="dataPagerNumeric"
runat="server" PageSize="5">
<Fields>
<asp:NumericPagerField ButtonCount="5"
NumericButtonCssClass="numeric_button"
CurrentPageLabelCssClass="current_page"
NextPreviousButtonCssClass="next_button" />
</Fields>
</asp:DataPager>
<td colspan="4" class="number_of_record">
<asp:DataPager ID="dataPageDisplayNumberOfPages"
runat="server" PageSize="5">
<Fields>
<asp:TemplatePagerField>
<PagerTemplate>
<span style="color: Black;">Records:
<%# Container.StartRowIndex >= 0 ?
(Container.StartRowIndex + 1) : 0 %>
-
<%# (Container.StartRowIndex +
Container.PageSize) > Container.TotalRowCount ?
Container.TotalRowCount : (Container.StartRowIndex +
Container.PageSize)%>
of
<%# Container.TotalRowCount %>
</span>
</PagerTemplate>
</asp:TemplatePagerField>
</Fields>
</asp:DataPager>
</td>
</td>
</tr>
</table>
</LayoutTemplate>
<EmptyDataTemplate>
<table class="empty_data" runat="server">
<tr>
<td>
No data found.
</td>
</tr>
</table>
</EmptyDataTemplate>
<ItemTemplate>
<tr>
<td align="removed" style="width: 7%;"
class='<%# Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblProfileId"
runat="server" Width="65" />
</td>
<td align="removed"
style="width: 10%;" class='<%#
Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblName" runat="server" />
</td>
<td align="removed" style="
width: 25%;" class='<%# Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblAddress" runat="server" />
</td>
<td align="removed" style="width: 25%;"
class='<%# Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblEmail" runat="server" />
</td>
<td align="removed" style="
width: 15%;" class='<%# Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblMobile" runat="server" />
</td>
<td align="removed" style="width: 8%;"
class='<%# Container.DataItemIndex % 2 == 0 ?
"alternate_row" : "row" %>'>
<asp:Label ID="lblStatus" runat="server" />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
现在回到 Visual Studio。添加我创建的类 ProfileDataSource.cs。此类型将由对象数据源使用。因此,我们需要将其制作为对象数据源的数据源。
[DataObject(true)]
public class ProfileDataSource
{
public ProfileDataSource()
{
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public Int32 TotalRowCount(Int32 startRowIndex,
Int32 pageSize, String sortExpression)
{
Int32 intTotalProfile = 0;
using (SqlConnection conn = new SqlConnection
(ConfigurationManager.ConnectionStrings["ApplicationServices"].ToString()))
{
SqlCommand cmdSelect = new SqlCommand();
conn.Open();
cmdSelect.CommandText = "Profile_Total";
cmdSelect.CommandType = CommandType.StoredProcedure;
cmdSelect.Connection = conn;
SqlDataReader dataReader = cmdSelect.ExecuteReader();
dataReader.Read();
intTotalProfile = Convert.ToInt32(dataReader[0]);
}
return intTotalProfile;
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public static DataTable GetProfileData
(Int32 startRowIndex, Int32 pageSize, String sortExpression)
{
DataTable profileDataTable = new DataTable();
using (SqlConnection conn = new SqlConnection
(ConfigurationManager.ConnectionStrings["ApplicationServices"].ToString()))
{
SqlCommand cmdSelect = new SqlCommand();
conn.Open();
cmdSelect.CommandText = "Profile_GET";
cmdSelect.CommandType = CommandType.StoredProcedure;
cmdSelect.Connection = conn;
startRowIndex = Convert.ToInt32(startRowIndex / pageSize) + 1;
if (String.IsNullOrEmpty(sortExpression))
sortExpression = "ProfileId";
cmdSelect.Parameters.AddWithValue("@CurrentPage", startRowIndex);
cmdSelect.Parameters.AddWithValue("@PageSize", pageSize);
cmdSelect.Parameters.AddWithValue("@SortExpression", sortExpression);
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = cmdSelect;
dataAdapter.Fill(profileDataTable);
}
return profileDataTable;
}
}
添加以下命名空间
using System.Configuration;
using System.Data.SqlClient;
using System.ComponentModel;
现在通过添加 DataObject
属性将 ProfileDataSource
类型标记为数据对象。
[DataObject(true)]
public class ProfileDataSource
{
}
在此类型中添加两个方法。TotalRowCount
用于获取底层表的总记录数。GetProfileData
用于获取底层表的带分页记录。
现在为数据对象 Select
方法编写方法。
[DataObjectMethod(DataObjectMethodType.Select, false)]
public Int32 TotalRowCount(Int32 startRowIndex, Int32 pageSize, String sortExpression)
{
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public static DataTable GetProfileData(Int32 startRowIndex,
Int32 pageSize, String sortExpression)
{
}
为 TotalRowCount
方法编写主体。此方法的参数将稍后由对象数据源控件传递。这将执行我们已创建的 Ptofile_Total
存储过程,并将总记录数返回给对象数据源控件。
[DataObjectMethod(DataObjectMethodType.Select, false)]
public Int32 TotalRowCount(Int32 startRowIndex,
Int32 pageSize, String sortExpression)
{
Int32 intTotalProfile = 0;
using (SqlConnection conn = new SqlConnection
(ConfigurationManager.ConnectionStrings
["ApplicationServices"].ToString()))
{
SqlCommand cmdSelect = new SqlCommand();
conn.Open();
cmdSelect.CommandText = "Profile_Total";
cmdSelect.CommandType = CommandType.StoredProcedure;
cmdSelect.Connection = conn;
SqlDataReader dataReader = cmdSelect.ExecuteReader();
dataReader.Read();
intTotalProfile = Convert.ToInt32(dataReader[0]);
}
return intTotalProfile;
}
为 GetProfileData
方法编写主体。此方法的参数将由对象数据源控件传递。这将执行我们已创建的 Profile_GET
存储过程,并带参数来获取每次请求的带分页记录。最后,此方法将返回一个数据表给对象数据源控件。
[DataObjectMethod(DataObjectMethodType.Select, true)]
public static DataTable GetProfileData(Int32 startRowIndex,
Int32 pageSize, String sortExpression)
{
DataTable profileDataTable = new DataTable();
using (SqlConnection conn = new SqlConnection
(ConfigurationManager.ConnectionStrings
["ApplicationServices"].ToString()))
{
SqlCommand cmdSelect = new SqlCommand();
conn.Open();
cmdSelect.CommandText = "Profile_GET";
cmdSelect.CommandType = CommandType.StoredProcedure;
cmdSelect.Connection = conn;
startRowIndex = Convert.ToInt32(startRowIndex / pageSize) + 1;
if (String.IsNullOrEmpty(sortExpression))
sortExpression = "ProfileId";
cmdSelect.Parameters.AddWithValue("@CurrentPage", startRowIndex);
cmdSelect.Parameters.AddWithValue("@PageSize", pageSize);
cmdSelect.Parameters.AddWithValue("@SortExpression", sortExpression);
SqlDataAdapter dataAdapter = new SqlDataAdapter();
dataAdapter.SelectCommand = cmdSelect;
dataAdapter.Fill(profileDataTable);
}
return profileDataTable;
}
startRowIndex = Convert.ToInt32(startRowIndex / pageSize) + 1;
这行代码根据 startRowIndex
和 pageSize
参数计算起始行索引。
当页面首次加载时,对象数据源控件会将 sortExpression
参数传递为 null
。在这种情况下,sort
表达式将是 ProfileId
,它是底层表的主键。
if (String.IsNullOrEmpty(sortExpression))
sortExpression = "ProfileId";
现在在 ASPX 页面中添加 Object Data Source。
<asp:ObjectDataSource ID="odsPforile"
runat="server" SelectMethod="GetProfileData"
SelectCountMethod="TotalRowCount" EnablePaging="true"
MaximumRowsParameterName="pageSize"
StartRowIndexParameterName="startRowIndex"
TypeName="VTS.Web.UI.ProfileDataSource"
SortParameterName="sortExpression">
<SelectParameters>
<asp:Parameter Name="startRowIndex" Type="Int32" />
<asp:Parameter Name="pageSize" Type="Int32" />
<asp:Parameter Name="sortExpression" Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
设置一些属性:EnablePaging
设置为 true
以实现分页,MaximumRowsParameterName
设置为 pageSize
以指定当前页大小,StartRowIndexParameterName
设置为 startRowIndex
以指定起始行号位置,TypeName
设置为 VTS.Web.UI.ProfileDataSource
以指定带命名空间的 Data object,SelectMethod
设置为 GetProfileData
以获取带分页的记录,SelectCountMethod
设置为 TotalRowCount
以获取底层表的总记录数,这将用于分页,SortParameterName
设置为 sortExpression
以进行排序。
对象数据源的 Select
参数
<SelectParameters>
<asp:Parameter Name="startRowIndex" Type="Int32" />
<asp:Parameter Name="pageSize" Type="Int32"/>
<asp:Parameter Name="sortExpression" Type="String" />
</SelectParameters>
现在像下面一样配置 listProfileView
<asp:ListView ID="lstProfileView" runat="server"
DataSourceID="odsPforile" DataKeyNames="ProfileId"
ItemPlaceholderID="itmPlaceholder" OnItemDataBound="Profile_ItemDataBound"
OnSorting="Profile_Sorting">
现在您需要编写两个事件来处理数据绑定和排序。
protected void Profile_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
System.Data.DataRowView rowView =
e.Item.DataItem as System.Data.DataRowView;
Label lblProfileId = (Label)e.Item.FindControl("lblProfileId");
Label lblName = (Label)e.Item.FindControl("lblName");
Label lblAddress = (Label)e.Item.FindControl("lblAddress");
Label lblEmail = (Label)e.Item.FindControl("lblEmail");
Label lblMobile = (Label)e.Item.FindControl("lblMobile");
Label lblStatus = (Label)e.Item.FindControl("lblStatus");
lblProfileId.Text = rowView["ProfileId"].ToString();
lblName.Text = rowView["Name"].ToString();
lblAddress.Text = rowView["Address"].ToString();
lblEmail.Text = rowView["Email"].ToString();
lblMobile.Text = rowView["Mobile"].ToString();
lblStatus.Text = rowView["IsActive"].ToString();
}
}
上面的事件将为项模板控件设置文本。
protected void Profile_Sorting(object sender, ListViewSortEventArgs e)
{
String imgUrl;
if (e.SortDirection == SortDirection.Ascending)
imgUrl = "~/images/asc.png";
else
imgUrl = "~/images/desc.png";
Image sortImage1 = (Image)lstProfileView.FindControl("SortImage1");
Image sortImage2 = (Image)lstProfileView.FindControl("SortImage2");
Image sortImage3 = (Image)lstProfileView.FindControl("SortImage3");
Image sortImage4 = (Image)lstProfileView.FindControl("SortImage4");
Image sortImage5 = (Image)lstProfileView.FindControl("SortImage5");
Image sortImage6 = (Image)lstProfileView.FindControl("SortImage6");
sortImage1.Visible = false;
sortImage2.Visible = false;
sortImage3.Visible = false;
sortImage4.Visible = false;
sortImage5.Visible = false;
sortImage6.Visible = false;
switch (e.SortExpression)
{
case "ProfileId":
sortImage1.Visible = true;
sortImage1.ImageUrl = imgUrl;
break;
case "Name":
sortImage2.Visible = true;
sortImage2.ImageUrl = imgUrl;
break;
case "Address":
sortImage3.Visible = true;
sortImage3.ImageUrl = imgUrl;
break;
case "Email":
sortImage4.Visible = true;
sortImage4.ImageUrl = imgUrl;
break;
case "Mobile":
sortImage5.Visible = true;
sortImage5.ImageUrl = imgUrl;
break;
case "Status":
sortImage6.Visible = true;
sortImage6.ImageUrl = imgUrl;
break;
}
}
上面的事件将在排序时设置升序和降序图像。

现在运行应用程序。您将看到如下输出
工作原理
在 SQL Management Studio 的 Tools 菜单下打开 SQL Profile,以诊断高效分页背后的工作原理。
- 在 File 菜单下打开 New Trace
- 使用您的凭据登录
- 选择 Run
- 在 Edit 菜单下点击 Clear Trace Window 以清除现有跟踪
- 最小化 SQL Server Profiler
- 从 Visual Studio 运行应用程序以浏览 PagingWithListView.aspx 页面
第一次运行应用程序后,您将看到如下跟踪

通过点击下一个数字按钮
在 Profiler 中
通过点击列头进行排序
在 profiler 中
继续对 ProfileView
底部的所有可用页面执行这些步骤,也可以通过点击每个列的标题进行排序。每次请求将获得 5 条记录。因此,加载底层表的所有记录没有任何变化。只加载您在 Listview
中 pageSize
属性设置的记录数。记录加载速度比以前的普通分页更快。它将占用更少的系统资源。对于海量数据来说,这是非常有效的。
结论
高效分页对于处理大量记录以构建可扩展应用程序的应用程序非常重要。此演示将帮助您创建可扩展的应用程序。