在ASP.NET应用程序中,用户控件(User Control)是一种强大的组件,它允许开发者将一组常用的控件抽象成一个可重用的单元。用户控件可以附加到数据控件上,例如GridView、ListView、DataList或Repeater,从而实现分页功能。DataPager控件本身会显示“第一页”、“下一页”、“上一页”和“最后一页”按钮,或者显示数字分页或自定义组合。用户点击这些按钮后,数据控件将自动通过SQL分页来遍历数据。
实现用户控件与包含它的ASP.NET网页之间的数据传递是很常见的需求。例如,可能有一个地址控件,当页面加载时,它会设置地址控件的街道、城市和州属性。然而,虽然对于ASPX页面来说,触发用户控件的方法是很简单的,但对于用户控件来说,要反过来触发其包含页面的方法就不那么简单了。
SQL分页是一种高效的数据分页方式,它使用SQL 2005中引入的ROW_NUMBER()函数(这个函数在免费的SQL Express版本及以上版本中都支持),以及ASP.NET 2.0中的GridView/ ObjectDataSource控件。
下面是一个SQL Server分页查询的示例:
SELECT * FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [OrderByField]) as Row, [OtherColumns]
FROM [TableName]
) as RecordEntries
WHERE Row between @startRowIndex and @endRowIndex
当在.aspx页面中放置控件时,可以设置DataPager控件的以下属性。然后在.aspx.cs文件中添加以下代码行:
public delegate void delPopulateData(int myInt);
delPopulateData delPopulate = new delPopulateData(this.BindGrid);
pagerApps.UpdatePageIndex = delPopulate;
委托(Delegate)是一种数据结构,它引用一个静态方法或一个类实例及其实例方法。换句话说,可以将一个方法引用分配给委托,然后像传递其他类型一样传递它。将通过一个示例解决方案来解决在引言中提到的记录导航器问题。在这个示例中,有一个WebForm包含一个用户控件。用户控件包含两个属性,一个用于委托,另一个用于业务数据——在这种情况下是一个整数索引。WebForm有一个BindGrid()方法来填充数据,然后适当地填充页面控件。WebForm创建一个引用BindGrid()方法的委托,并将该委托传递给用户控件的委托类型属性。每当用户控件的上一个或下一个按钮被点击时,它就会调用它被赋予的委托,传递从用户控件中选择的数据值(在这种情况下只是索引)。最后,委托反过来触发父页面的BindGrid()方法。
在技术实现方面,首先想要创建用户控件。创建一个名为DataPager.ascx的用户控件,并添加以下两个属性(代码非常自解释):
public partial class DataPager : System.Web.UI.UserControl
{
public delPopulateData UpdatePageIndex { get; set; }
public int CurrentPageIndex { get; set; }
// 更多代码...
}
aspx.cs页面包含以下代码:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGrid(1);
}
delPopulateData delPopulate = new delPopulateData(this.BindGrid);
pagerApps.UpdatePageIndex = delPopulate;
}
程序流程如下:在WebForm的初始加载时,相关的控件流程从WebForm的Page_Load开始,并设置用户控件的属性。它只需要在第一次设置业务数据(如页面索引),因为该数据是序列化的,并在页面的ViewState中持久保存。它在每次回发时设置委托属性,因为委托默认不会被序列化并保存到ViewState中。在WebForm Page_Load之后,调用用户控件的Page_Load。这会设置默认的业务值(存储在用户控件的属性中),然后调用UpdatePageIndex()方法。
当用户点击RecordIndex上一个或下一个按钮时,它们会适当地更新内部业务数据,然后调用UpdatePageIndex()方法,该方法如前所述更新父页面。回发的控件流程几乎相同——只是默认的业务数据不会被重置。
以下存储过程将只返回通过参数传递的那些记录:
ALTER PROCEDURE [dbo].[GetAppsDetails]
@PageIndex INT,
@RecordsPerPage INT
AS
BEGIN
SET NOCOUNT ON
DECLARE @startRowIndex INT;
DECLARE @endRowIndex INT;
SET @endRowIndex = (@PageIndex * @RecordsPerPage);
SET @startRowIndex = (@endRowIndex - @RecordsPerPage) + 1;
WITH RecordEntries AS (
SELECT ROW_NUMBER() OVER (ORDER BY A.APP_TYPE_ID ASC) as Row,
A.APP_TYPE_ID, A.APP_TYPE_NAME,A.APP_STORE_ID,R.REVIEW_TITLE,R.AUTHOR_NAME,
R.REVIEW_DATE, R.REVIEW_RATING, R.REVIEW_TEXT
FROM [dbo].[APP_TYPES] A
INNER JOIN [CUSTOMER_APP_REVIEWS] R ON A.APP_TYPE_ID=R.APP_TYPE_ID
)
SELECT APP_TYPE_ID, APP_TYPE_NAME, APP_STORE_ID, REVIEW_TITLE, AUTHOR_NAME,
REVIEW_DATE, REVIEW_RATING, REVIEW_TEXT
FROM RecordEntries
WHERE Row between @startRowIndex and @endRowIndex
SELECT COUNT(*)
FROM [dbo].[APP_TYPES] A
INNER JOIN [CUSTOMER_APP_REVIEWS] R ON A.APP_TYPE_ID=R.APP_TYPE_ID
END
用户控件为Web应用程序提供了许多好处。利用这些好处的一部分是,在WebForm和用户控件之间双向传递数据。虽然将数据传递给用户控件是微不足道的,但从用户控件将数据传回页面则不是。然而,仍然可以通过让页面实例化一个委托并将其传递给用户控件来解决这个问题,从而让用户控件能够按需触发父页面的方法。