使用Gridview和ObjectDataSource轻松实现自定义分页

 一.什么是自定义分页

        自定义分页是与默认分页相对应的。默认分页指一次检索出所有数据并将其绑定到数据绑定控件中,虽然该控件只能一页一页显示这些数据,但是所有数据其实都已经被绑定到控件上了。自定义分页的含义是显示到哪一页就检索并绑定哪一页的数据。显然在大数据量的情况下,自定义分页的效率会高很多。  
        在Asp.net 1.x中自定义分页又称数据库分页,DataGrid中的AllowCustomerPaging属性和VirtualItemCount属性就是专门为自定义分页准备的。在Asp.net 2.0中因为引入了数据源的概念,因此自定义分页也可以叫做数据源分页。

二.为什么使用ObjectDataSource

        ASP.NET2.0提供了SqlDataSource数据源控件,提供了ConnectionString、SelectCommand、SelectCommandType、SelectParameters等属性,分别用于指定连接字符串、SQL查询语句、SQL查询语句的类型和查询所使用的参数。SqlDataSource数据源控件根据这些属性的设定从关系数据库中获取数据。但是,SqlDataSource 控件存在一个问题:该控件的缺点在于它迫使您将用户界面层与数据访问层混合在一起,忽略了业务逻辑层。然而随着应用程序规模的扩大,具有清晰的用户界面层、业务逻辑层、数据访问层以及数据实体层是极为必要的。仅仅通过 SqlDataSource 控件的属性,在用户界面层引用 SQL 语句或存储过程是不可取的,或说是缺乏架构意识的,不利于代码的重用和维护。另外,SqlDataSource也不支持数据源分页,也就不能实现自定义分页。
        ObjectDataSource 控件对象模型类似于 SqlDataSource 控件。但ObjectDataSource 提供一个 TypeName 属性(而不是 ConnectionString属性),该属性指定用于执行数据操作的业务逻辑类的类名,ObjectDataSource可以通过TypeName 属性直接调用业务层的类。类似于 SqlDataSource 的命令属性SelectCommand、InsertCommand、UpdateCommand、DeleteCommand,ObjectDataSource 控件支持诸如 SelectMethod、UpdateMethod、InsertMethod 和 DeleteMethod属性,用于指定执行这些操作的方法名。显然ObjectDataSource是依托于一个业务逻辑类的,这样我们就可以拥有完善的架构,业务逻辑类可以为复杂的业务逻辑提供好的支持,也有利于代码的重用和维护。特别是ObjectDataSource 控件提供了EnablePaging属性、SelectCountMethod属性、StartRowIndexParameterName属性和MaximumRowsParameterName属性专门支持数据源分页。 SelectCountMethod属性指定的是获取数据项总数的方法。StartRowIndexParameterName属性用于指定一个参数的名称,如程序中不特别设定,其默认参数名为startRowIndex,该参数代表该页数据项的开始行索引;MaximumRowsParameterName属性也用于指定一个参数名称,其默认参数名为maximumRows,该参数代表一页中容纳的数据项总数。

三.示例

        本例是以SQL Server自带的Northwind数据库的Orders表为主,Employees表和Customers表为辅,显示OrderDate在1997年之前的Order列表。

(1). 实体层
        在实体层中创建Order、Employee、Customer三个类,其中Order引用了Employee类和Customer类。

(2).  数据访问层
        数据访问层使用了微软提供的SqlHelper类。

public  class  OrderDataAccess
    {
        
private  string   ConnectionString  =  Convert.ToString(ConfigurationManager.ConnectionStrings[ " NorthWindConnectionString " ]);

        
public  OrderDataAccess()
        {
            
//
            
//  TODO: Add constructor logic here
            
//
        }

        
public  int  CountTotalNumber()
        {
            
return  Convert.ToInt32(SqlHelper.ExecuteScalar(ConnectionString, CommandType.StoredProcedure,  " Order_Select_TotalNumber " )); 
        }

        
public  IEnumerable FindOrders( int  startRowIndex,  int  maximumRows, bool  isDataSet)
        {
            SqlParameter[] parms 
=  {
                
new  SqlParameter( " @StartRowIndex " ,SqlDbType.Int, 4 ),
                
new  SqlParameter( " @MaximumRows " ,SqlDbType.Int, 4 )
            };
            parms[
0 ].Value  =  startRowIndex;
            parms[
1 ].Value  =  maximumRows;

            
if ( ! isDataSet)
            {
                ArrayList OrderList 
=  new  ArrayList();
                
using  (SqlDataReader reader  =  SqlHelper.ExecuteReader(ConnectionString, CommandType.StoredProcedure,  " Order_Select_Pagination " , parms))
                {
                    
while  (reader.Read())
                    {
                        OrderList.Add(LoadOrder(reader));
                    }
                }
                
return  OrderList;
            }
            
else
            {
                DataSet ds 
=  SqlHelper.ExecuteDataset(ConnectionString, CommandType.StoredProcedure,  " Order_Select_Pagination " , parms);
                
return  ds.Tables[ 0 ].DefaultView;
            }
        }

        
public  int  DeleteOrder( int  orderId)
        {
            SqlParameter parm 
=  new  SqlParameter( " @OrderID " ,SqlDbType.Int, 4 );
            parm.Value 
=  orderId;

            
return  SqlHelper.ExecuteNonQuery(ConnectionString,CommandType.StoredProcedure, " Order_Delete " ,parm);
        }

        
private  Order LoadOrder(SqlDataReader reader)
        {
            Order order 
=  new  Order();

            order.OrderId 
=  Convert.ToInt32(reader[ " OrderID " ]);
            order.Customer 
=  new  Customer(Convert.ToString(reader[ " CustomerID " ]), Convert.ToString(reader[ " CompanyName " ]));
            order.Employee 
=  new  Employee(Convert.ToInt32(reader[ " EmployeeID " ]), Convert.ToString(reader[ " LastName " ]), Convert.ToString(reader[ " FirstName " ]));
            order.OrderDate 
=  Convert.ToDateTime(reader[ " OrderDate " ]);
            order.RequiredDate 
=  Convert.ToDateTime(reader[ " RequiredDate " ]);
            order.ShippedDate 
=  Convert.ToDateTime(reader[ " ShippedDate " ]);
            order.ShipVia 
=  Convert.ToInt32(reader[ " ShipVia " ]);
            order.Freight 
=  Convert.ToDecimal(reader[ " Freight " ]);
            order.ShipName 
=  Convert.ToString(reader[ " ShipName " ]);
            order.ShipAddress 
=  Convert.ToString(reader[ " ShipAddress " ]);
            order.ShipCity 
=  Convert.ToString(reader[ " ShipCity " ]);
            order.ShipRegion 
=  Convert.ToString(reader[ " ShipRegion " ]);
            order.ShipPostalCode 
=  Convert.ToString(reader[ " ShipPostalCode " ]);
            order.ShipCountry 
=  Convert.ToString(reader[ " ShipCountry " ]);

            
return  order;
        }
    }

        注意FindOrders方法,它带有三个参数,startRowIndex代表起始行的索引,maxmiumRows代表本次查询所要获得的数据项总数,isDataSet是为标示是使用DataSet还是SqlDataReader,如果表示层的GridView设置了属性AllowSorting为true,也就是要求具有排序功能,那么数据访问层就必须使用DataSet来容纳数据,否则使用SqlDataReader就可以了。

(3). 存储过程

获取符合要求的总订单数存储过程:

ALTER PROCEDURE  Order_Select_TotalNumber 

AS


SET NOCOUNT ON

Select Count (OrderID)

From
 Orders 

Where OrderDate < '1997'


RETURN  

分页获取数据的存储过程:

ALTER PROCEDURE  Order_Select_Pagination 
(
    
@StartRowIndex int = null
,
    
@MaximumRows int = null

)
AS
SET NOCOUNT ON
DECLARE @PageLowerBound int
DECLARE @PageUpperBound int

-- Set the page bounds
SET @PageLowerBound = @StartRowIndex
SET @PageUpperBound = @PageLowerBound + @MaximumRows + 1

-- Create a temp table to store the select results
CREATE TABLE  #tmp
(
     RecNo 
int IDENTITY (11NOT NULL
,
     OrderID 
int

)

INSERT INTO  #tmp
        
SELECT [OrderID]

        
FROM [Orders]
        
Where OrderDate < '1997'
        
ORDER BY OrderID ASC

SELECT o.* ,e.LastName,e.FirstName,c.CompanyName
FROM Orders o inner join Employees e on o.EmployeeID = e.EmployeeID inner join Customers c on o.CustomerID =
 c.CustomerID, #tmp t
WHERE o.OrderID = t.OrderID AND

     t.RecNo 
> @PageLowerBound AND
     t.RecNo 
< @PageUpperBound
ORDER BY  t.RecNo

    
RETURN

(4). 业务逻辑层
        本例的业务逻辑很简单,只是作为表示层和数据访问层之间的桥梁,并没有掺杂其它的运算逻辑。
业务逻辑类中的方法可以设置给ObjectDataSource控件的SelectCountMethod属性和SelectMethod属性,这样ObjectDataSource就可以自动通过业务逻辑类获得数据了。

public  class  OrderBusinessLogic
    {
        
private  static  OrderDataAccess orderAccess  =  new  OrderDataAccess();
        
        
public  OrderBusinessLogic()
        {
            
//
            
//  TODO: Add constructor logic here
            
//
        }

        
public  static  int  GetRowsTotalNumber()
        {
            
return  orderAccess.CountTotalNumber();
        }

        
public  static  IEnumerable GetOrdersForPagingAndSorting( int  startRowIndex,  int  maximumRows)
        {
           
return  orderAccess.FindOrders(startRowIndex, maximumRows, true );          
        }

        
public  static  IEnumerable GetOrdersForPaging( int  startRowIndex,  int  maximumRows)
        {
            
return  orderAccess.FindOrders(startRowIndex, maximumRows,  false );
        }

        
public  static  void  DeleteOrder( int  orderId)
        {
            orderAccess.DeleteOrder(orderId);
        }       
    }

       值得注意的两点是:第一,这里的方法都是用了静态方法,其实也可以不使用静态方法。不使用静态方法时Asp.net会先实例化ObjectDataSource的TypeName中设定的类,然后调用它的方法。第二,GetOrdersForPagingAndSorting和GetOrdersForPaging两个方法,前者是为了应对GridView的排序要求,因为为了能够实现排序,必须使用DataView、DataTable或DataSet;而后者则不用于排序,只需返回一个SqlDataReader。

(5).页面程序
        如果想只使用下图所示GridView的默认分页样式,则按照下面的页面代码,不必再写任何后台代码就可实现。

   

  < asp:GridView  ID ="OrdersGridView"  DataSourceID ="OrdersObjectDataSource"  AutoGenerateColumns ="false"
            AllowPaging
="true"  runat ="server"  AllowSorting ="true"  Width ="720px"  PageSize ="20" >
            
< PagerStyle  ForeColor ="Blue"  BackColor ="LightBlue"  />             
            
< Columns >
                
< asp:BoundField  HeaderText ="Order Id"  DataField ="OrderId"    />
                
< asp:TemplateField  HeaderText ="Customer" >
                    
< ItemTemplate >
                        
<% Eval ( " Customer.CompanyName " ) %>
                    
</ ItemTemplate >
                
</ asp:TemplateField >
                
< asp:TemplateField  HeaderText ="Employee" >
                    
< ItemTemplate >
                        
<% Eval ( " Employee.EmployeeName " ) %>
                    
</ ItemTemplate >
                
</ asp:TemplateField >
                
< asp:BoundField  HeaderText ="Order date"  DataField ="OrderDate"  DataFormatString ="{0:g}"  />
                
< asp:BoundField  HeaderText ="Required date"  DataField ="RequiredDate"  DataFormatString ="{0:d}"  />
                
< asp:BoundField  HeaderText ="Shipped date"  DataField ="ShippedDate"  DataFormatString ="{0:d}"  />
                
< asp:BoundField  HeaderText ="Ship address"  DataField ="ShipAddress"  />
                
< asp:BoundField  HeaderText ="Ship country"  DataField ="ShipCountry"  />                 
            
</ Columns >
        
</ asp:GridView >
        
< asp:ObjectDataSource  ID ="OrdersObjectDataSource"  runat ="server"  SelectCountMethod ="GetRowsTotalNumber"
          SelectMethod
="GetOrdersForPaging"  TypeName ="MyTest.BusinessLogic.OrderBusinessLogic"  OldValuesParameterFormatString ="Original_{0}"  EnablePaging ="true" >           
        
</ asp:ObjectDataSource >

        如果想实现如下图所示的自定义的分页样式,则参考下列代码:

< asp:GridView  ID ="OrdersGridView"  DataSourceID ="OrdersObjectDataSource"  AutoGenerateColumns ="false"
            AllowPaging
="true"  AllowSorting ="true"  OnDataBound ="OrdersGridView_DataBound"  runat ="server"  
            Width
="720px"  PageSize ="25"  OnRowDeleted ="OrdersGridView_RowDeleted"  DataKeyNames ="OrderID" >
            
< Columns >
                
< asp:BoundField  HeaderText ="Order Id"  DataField ="OrderID"  SortExpression ="OrderID" />
                
< asp:BoundField  HeaderText ="Customer company"  DataField ="CompanyName"  SortExpression ="CompanyName" />
                
< asp:TemplateField  HeaderText ="Employee"  SortExpression ="EmployeeName" >
                  
< ItemTemplate >
                      
<% Eval ( " LastName " ) + "  " + Eval ( " FirstName " %>   
                  
</ ItemTemplate >
                
</ asp:TemplateField >                                                 
                
< asp:BoundField  HeaderText ="Order date"  DataField ="OrderDate"  DataFormatString ="{0:g}"  SortExpression ="OrderDate" />
                
< asp:BoundField  HeaderText ="Required date"  DataField ="RequiredDate"  DataFormatString ="{0:d}"  SortExpression ="RequiredDate" />
                
< asp:BoundField  HeaderText ="Shipped date"  DataField ="ShippedDate"  DataFormatString ="{0:d}"  SortExpression ="ShippedDate" />
                
< asp:BoundField  HeaderText ="Ship address"  DataField ="ShipAddress"  />
                
< asp:BoundField  HeaderText ="Ship country"  DataField ="ShipCountry"  />                 
                
< asp:CommandField  ButtonType ="Button"  DeleteText ="删除"  ShowDeleteButton ="true"  HeaderText ="Operation"    />
            
</ Columns >
            
< PagerStyle  ForeColor ="Blue"  BackColor ="LightBlue"  />             
            
< PagerTemplate >
                
< table  width ="100%" >
                    
< tr >
                        
< td  width ="70%" >
                            
< asp:Label  ID ="MessageLabel"  ForeColor ="Blue"  Text ="页码:"  runat ="server"  />
                            
< asp:DropDownList  ID ="PageDropDownList"  AutoPostBack ="true"  OnSelectedIndexChanged ="PageDropDownList_SelectedIndexChanged"
                                runat
="server"  />
                            
< asp:LinkButton  CommandName ="Page"  CommandArgument ="First"  ID ="linkBtnFirst"  runat ="server" > 首页 </ asp:LinkButton >
                            
< asp:LinkButton  CommandName ="Page"  CommandArgument ="Prev"  ID ="linkBtnPrev"  runat ="server" > 上一页 </ asp:LinkButton >
                            
< asp:LinkButton  CommandName ="Page"  CommandArgument ="Next"  ID ="linkBtnNext"  runat ="server" > 下一页 </ asp:LinkButton >
                            
< asp:LinkButton  CommandName ="Page"  CommandArgument ="Last"  ID ="linkBtnLast"  runat ="server" > 末页 </ asp:LinkButton >
                        
</ td >
                        
< td  align ="right" >
                            
< asp:Label  ID ="CurrentPageLabel"  ForeColor ="Blue"  runat ="server"  />
                        
</ td >
                    
</ tr >
                
</ table >
            
</ PagerTemplate >
        
</ asp:GridView >
        
< asp:ObjectDataSource  ID ="OrdersObjectDataSource"  runat ="server"  SelectCountMethod ="GetRowsTotalNumber"
          SelectMethod
="GetOrdersForPagingAndSorting"  DeleteMethod ="DeleteOrder"
          TypeName
="MyTest.BusinessLogic.OrderBusinessLogic"  EnablePaging ="true"  EnableViewState ="true" >           
        
< DeleteParameters >
            
< asp:Parameter  Name ="OrderId"  Type ="Int32"  Direction ="Input"  />
        
</ DeleteParameters >
        
</ asp:ObjectDataSource >

        注意页导航模板PagerTemplate属性的使用。通常将按钮控件(如上面代码中的LinkButton)添加到页导航模板以执行分页操作。单击 CommandName 属性设置为“Page”的按钮控件时,GridView 控件会执行分页操作。按钮的 CommandArgument 属性确定要执行的分页操作的类型。下表列出了 GridView 控件支持的命令参数值。 

CommandArgument 值

说明

“Next”

导航至下一页。

“Prev”

导航至上一页。

“First”

导航至第一页。

“Last”

导航至最后一页。

整数值

导航至指定页码。

        页面程序的后台代码:

public  partial  class  TestGridview2 : System.Web.UI.Page
{
    
protected  void  Page_Load( object  sender, EventArgs e)
    {

    }

    
protected  void  PageDropDownList_SelectedIndexChanged(Object sender, EventArgs e)
    {
        GridViewRow pagerRow 
=  OrdersGridView.BottomPagerRow;
        DropDownList pageList 
=  (DropDownList)pagerRow.Cells[ 0 ].FindControl( " PageDropDownList " );
        OrdersGridView.PageIndex 
=  pageList.SelectedIndex;
    }

    
protected  void  OrdersGridView_DataBound(Object sender, EventArgs e)
    {
        GridViewRow pagerRow 
=  OrdersGridView.BottomPagerRow;
        LinkButton linkBtnFirst 
=  (LinkButton)pagerRow.Cells[ 0 ].FindControl( " linkBtnFirst " );
        LinkButton linkBtnPrev 
=  (LinkButton)pagerRow.Cells[ 0 ].FindControl( " linkBtnPrev " );
        LinkButton linkBtnNext 
=  (LinkButton)pagerRow.Cells[ 0 ].FindControl( " linkBtnNext " );
        LinkButton linkBtnLast 
=  (LinkButton)pagerRow.Cells[ 0 ].FindControl( " linkBtnLast " );
        
if  (OrdersGridView.PageIndex  ==  0 )
        {
            linkBtnFirst.Enabled 
=  false ;
            linkBtnPrev.Enabled 
=  false ;
        }
        
else  if  (OrdersGridView.PageIndex  ==  OrdersGridView.PageCount  -  1 )
        {
            linkBtnLast.Enabled 
=  false ;
            linkBtnNext.Enabled 
=  false ;
        }
        
else  if  (OrdersGridView.PageCount  <=  0 )
        {
            linkBtnFirst.Enabled 
=  false ;
            linkBtnPrev.Enabled 
=  false ;
            linkBtnNext.Enabled 
=  false ;
            linkBtnLast.Enabled 
=  false ;
        }
        DropDownList pageList 
=  (DropDownList)pagerRow.Cells[ 0 ].FindControl( " PageDropDownList " );
        Label pageLabel 
=  (Label)pagerRow.Cells[ 0 ].FindControl( " CurrentPageLabel " );
        
if  (pageList  !=  null )
        {
            
for  ( int  i  =  0 ; i  <  OrdersGridView.PageCount; i ++ )
            {
                
int  pageNumber  =  i  +  1 ;
                ListItem item 
=  new  ListItem(pageNumber.ToString()  +  " / "  +  OrdersGridView.PageCount.ToString(), pageNumber.ToString());
                
if  (i  ==  OrdersGridView.PageIndex)
                {
                    item.Selected 
=  true ;
                }
                pageList.Items.Add(item);
            }
        }
        
if  (pageLabel  !=  null )
        {
            
int  currentPage  =  OrdersGridView.PageIndex  +  1 ;
            pageLabel.Text 
=  " 当前页:  "  +  currentPage.ToString()  +
              
"  /  "  +  OrdersGridView.PageCount.ToString();
        }
    }

    
protected  void  OrdersGridView_RowDeleted( object  sender,GridViewDeletedEventArgs e)
    {
        
if  (e.Exception  ==  null  &&  OrdersGridView.Rows.Count  ==  1 )
        {
            
//  we just deleted the last row
            OrdersGridView.PageIndex  =  Math.Max( 0 , OrdersGridView.PageIndex  -  1 );
         }
    }
}

    
    由以上示例可以看出GridView关联ObjectDataSource时,省去了DataBind方法的使用。也就是说只要给GridView关联上数据源控件,那么绑定的事程序员就不用操心了。当GridView发生翻页事件时整个的运行过程是这样的,GridView的PageIndex变成新值,ObjectDataSource根据GridView的PageIndex属性换算出startRowIndex和MaxmiumRows的值,然后传递这两个参数给SelectMethod指定的方法从而获得数据,然后再调用SelectCountMethod指定的方法获得总数据项数,以计算出总页数,然后执行OrderGridView_DataBound事件处理方法最终完成绑定工作。
    注意OrdersGridView_RowDeleted事件处理方法的写法,它是为了应对将最后一页的最后一条数据删除之后,GridView将能够识别出最后一页已经被删空了,因此原来的倒数第二页就变成了现在的末页了,并让GridView的当前页指向末页。
    下载完整源程序/Files/taewind/TestDataBindControlls.rar

转载于:https://www.cnblogs.com/xiaozhuoyun/archive/2007/10/29/941879.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值