chiname

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

一套可嵌入或独立使用的翻页控件(DataGrid,DataList): WebPager(附源码)

  WebPager 控件的源码及其演示程序。点此下载压缩包。

  于ASP.NET里的翻页控件,大家应该都很熟悉,网上也有很多这样的例子。我也做过不少各种类型的此类控件,但设计思想都不太一样。从功能上看,一种是只呈现翻页所需的外观和操作,一种是同时包装了对数据的分页功能。从形式上看,有扩展DataGrid翻页功能的(嵌入式),也有能够独立实现翻页的。
  而我做这套 WebPager 的目的,就是希望能够兼顾以上各个方面,做出灵活而扩展性强的翻页控件。也就是说它既可以嵌入DataGrid,又可以单独使用。 同时最好能够让我可以方便地切换翻页样式或者外观,而不用改变类或接口。
独立内嵌外观


  实现这个目标其实不难,我们本来是要继承DataGrid类,然后重写其产生和控制翻页的部分。

public sealed class AdvDataGrid : DataGrid  {
    
public AdvDataGrid() {
        
this.ItemCreated += new DataGridItemEventHandler( AdvDataGrid_ItemCreated );
    }


    
private void AdvDataGrid_ItemCreated( object sender , System.Web.UI.WebControls.DataGridItemEventArgs e ) {
        
if ( e.Item.ItemType == ListItemType.Pager ) {
            Literal msg 
= new Literal();
            msg.Text 
= "把这三句代码替换成呈现实际翻页控件外观的代码。";
            ( ( TableCell ) e.Item.Controls[
0] ).Controls.Add( msg );
        }

    }

}

  要实现翻页子控件的重用,既能独立使用,又能内嵌,只要把这部分代码抽离出来,放在一个独立的类里面就可以。在这里,我们提取所有翻页子控件的公共接口:IDataPagerItemCreated 事件里的代码要改成:
IDataPager pager = DataPagerFactory.CreateDataPager("SimplePager");
( ( TableCell ) e.Item.Controls[
0] ).Controls.Add( pager );

  这里我们先打住,看看这样做的好处。首先,翻页代码放到独立的类中,有助于复用(为独立使用翻页控件做准备);其次,由于提炼出公共接口,凡是实现该接口的类都可以被加载到DataGrid中作为翻页子控件,实现了多样化;第三,使用工厂模式创建具体的翻页子控件,可以非常方便地切换外观。

  我们这里只实现了内嵌DataGrid。如果DataList怎么办?没关系,照葫芦画瓢。在 ItemCreated 事件中重写外观。DataList不支持翻页,没有 ItemType == ListItemType.Pager 的?也不要紧,我们可以在 DataList 的 Footer 部分加载翻页子控件。
  我们这里实现了两个翻页子控件的容器,DataGrid 和 DataList。看看他们有什么共同点没有。首先需要有分页信息吧,比如当前页,页大小,总记录等等。这个类我们已经封装到了 PagerInfo 里面。所有的容器都要有这样一个属性。其次,我们要能够通过修改 PagerClass 来随时改变这个容器具体使用的 Pager 的种类。这个也要做到属性里。还有翻页发生时所触发的事件,这个也是必不可少的。
  那么我们这里再为翻页子控件的容器类再提取一个接口: IDataPagerContainer。所有可以加载翻页控件的容器都要实现该接口。
  这样,我们的 WebPager 的类结构基本上就已经形成了。由 IDataPager 接口延伸出各种各样的翻页子控件。由 IDataPagerContainer 接口延伸出各种各样的包含容器。它们之间可以自由地挂接与组合。

  剩下最后一个问题没有解决。就是独立使用翻页控件。这个也是比较简单的。所有翻页控件都有 PagerInfo 属性,描述了当前分页信息。当页面改变时,它的 PagerInfo.PageIndex 也随着改变。然后根据这个来取得不同的数据,然后让数据显示控件进行绑定即可。
  这里我本来是打算做成翻页子控件能够完全独立地运行和显示。也就是说它们可以被拖拽到页面。但后来发现这样实现起来很不漂亮,而且抛弃了原先的结构。所以子控件的独立使用,其实还是借助了一个第三方的容器: DataPagerContainer。这是一个通用并且简单的 IDataPagerContainer 接口的实现。这样独立使用翻页控件的时候,仍然可以方便地改变外观。
  类结构:
  Hooyee.Utils.PagerInfo   封装数据分页信息。 如PageSize、PageIndex
  Hooyee.WebControls.IDataPagerContainer 翻页控件的容器对象的公共支持接口。
    Hooyee.WebControls.DataPagerContainer 通用的数据翻页控件的容器类。 可以作为默认容器。
    Hooyee.WebControls.AdvDataGrid 支持翻页控件的DataGrid
    Hooyee.WebControls.AdvDataList 支持翻页控件的DataList
  Hooyee.WebControls.IDataPager 实现数据翻页功能的用户控件的公共接口。
    Hooyee.WebControls.DataPagerBase 用于实现数据翻页功能的用户控件的公共抽象基类。
      Hooyee.WebControls.FirstPager 一个具体的翻页子控件实现。
      Hooyee.WebControls.SecondPager 一个具体的翻页子控件实现。
posted on 2005-01-25 01:04 逸天 阅读(2296) 评论(17)  编辑 收藏 收藏至365Key 所属分类: 技术

评论

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-01-25 10:17 飞天狐狸

  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-01-25 12:10 听棠.NET
楼主的思想是蛮好的,我觉得确实可以采用继承扩展的方式来提高分页功能,以前的分页控件确实不好用,太烦。
不过,楼主的分页外观是如何灵活配置的呢?
能自己指定显示的内容否?
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-01-25 12:56 逸天
to: 听棠.NET
我这里其实也只是想展示一下思路,想和大家一起交流。这套控件本身还并不是很强大。而且我也只是提供了一个 Pager 的具体实现。其余的大家可以根据自己的需要,扩展 DataPagerBase 类就可以了。我们把大部分共通的处理都提取到了实现 IDataPager 接口的抽象基类 DataPagerBase 里。力争将具体 Pager 类变得越简单越好,最好一个Pager类里只有呈现外观的代码。这样自己做一个Pager就变得容易和轻松。

我还是比较倾向于把不同外观做成不同的Pager。如果一个Pager过分强大,可以通过属性或配置灵活定义外观(就像AspNetPager,但这个类太庞大了。),那这一个Pager就够用了,还要其它的干嘛。这是两种思路。我只是做了一个框架,把单个Pager的复杂度降到最低。WebPager真正的威力还是在于你自己实现的各个Pager类(说实话Pager虽然简单,但不同项目总是会需要不同类型的Pager....)。

而且这里的Pager都是通过容器来呈现的。不管使用哪种Pager,在Web页面上的都是 DataPagerContainer,或者其它实现 IDataPagerContainer的容器。也就是说Pager会很多,容器相对会比较固定。
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-01-25 13:43 venjiang
不错.
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-01-25 17:28 boy119
请问楼主能否使用dataread读取数据源
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-01-26 10:31 听棠.NET
在NetAdvantage 2004 vol 3里,UltraWebGrid的分页功能就比较强了,他是使用了Patten的方式,可以在里面输入自己的HTML代码,他提供[PageSize],[CurrentPageIndex],[Pages]几个域值,所以在Patten里可以按自己的方式呈现出来,这向个域会自动被值替换掉,我觉得楼主或许也可以考虑这种思想!!!
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-01-26 15:35 逸天
to: 听棠.NET
是的,我也正有这样的想法。利用模板技术来灵活定制界面。这样比继承DataPagerBase实现自己的Pager,然后在Render()方法里用代码搭界面要更方便。这个应该不难,我会在下次release的时候把它做上去:)
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-01-26 17:14 boy119
请问如何使用dataread读取数据源,主要是在
private void ShowPage() {
string dataFile = MapPath( "Data/Movies.XML" );
MovieTDS movies = new MovieTDS();
movies.ReadXml( dataFile );
_pager.PagerInfo.ItemCount = movies.MovieInfo.Count;
string filter = string.Format( "Index >= {0} and Index <= {1}" , _pager.PagerInfo.ItemStart , _pager.PagerInfo.ItemEnd );
// 这是个简单的例子,实际的 DataSource 可能要从数据库取得,并要自己根据 PagerInfo 里的信息对数据进行分页。
_grid.DataSource = new DataView( movies.MovieInfo , filter , "" , DataViewRowState.CurrentRows );
_grid.DataBind();
}
不知道应该如何将DataView换为dataread,看了一些为datalist加入分页的文章,大部分使用了dataset,但是如果要使用dataread读取数据,为datalist加入分页功能,不知道具体如何写代码,谢谢!
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-03-18 17:06 地狱之火
下载并实用楼主的翻页控件,很不错,但是楼主用的是xml 而我这里用的数据是access的我一般通过如此的方法来邦定数据
myDs是DataSet

this.AdvDataGrid1.PagerInfo.ItemCount =myDs.Tables [0].Rows.Count ;
string filter = string.Format( "id >= {0} and id <= {1}" , AdvDataGrid1.PagerInfo.ItemStart , AdvDataGrid1.PagerInfo.ItemEnd );
this.AdvDataGrid1 .DataSource =new DataView (myDt,filter,"",DataViewRowState.CurrentRows ) ;
this.AdvDataGrid1.DataBind ();

但是显示的时候不页面上不显示任何数据库 ,但是显示整个数据的页数,数据的条数 请问如何解决 ~
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-03-18 22:35 逸天
to : 地狱之火
我怀疑是你所创建的DataView里没有任何数据。请确认表里面存在复合条件“id >= {0} and id <= {1}”的数据。实际上数据库里的id不一定和PagerInfo.ItemStart,ItemEnd相同,这点请注意。

我的翻页控件主要作用是外观呈现,具体对数据的分页并不涉及。这部分需要你自己去实现。不过你可以通过翻页控件的 PagerInfo 对象,来获得关于分页的一些信息,例如当前页码,每页大小,当前页记录的开始位置(ItemStart)和结束位置(ItemEnd)(相对于整个table而言)。

这里提供一种方法:
PagerInfo pagerInfo = this.AdvDataGrid1.PagerInfo; 
ArrayList pageRows 
= new ArrayList( pagerInfo.PageSize ); 
for(int i = pagerInfo.ItemStart; i<= pagerInfo.ItemEnd;i++

pageRows.Add( myDS.Tables[
0].Rows[i] ); 
}
 
this.AdvDataGrid1 .DataSource = pageRows; 
this.AdvDataGrid1.DataBind (); 


如果不行,可以尝试
this.AdvDataGrid1 .DataSource = (DataRow[])
pageRows.ToArray(typeof(DataRow));


不过我仍建议你改进数据分页的方法。
因为你现在这种方法其实还是“虚假”的数据分页。例如一页只有10条数据,但你显示没一页的时候还是把所有数据都读进DataTable里(例如300条),这样效率是比较低的。最好是 ItemCount,总记录数,通过一个查询获得(例如: select count(*) from myTable)。然后DataSource可以精确地、只是获得该页的必要数据。

这在SQL Server里比较好实现,例如:
SqlCommand cmdCNT = new SqlCommand 
(
"select count(*) from myTable", conn ); 
pagerInfo.ItemCount 
= (int) cmdCNT.ExecuteScalar(); 

SqlCommand cmdQuery 
= new SqlCommand 
(
"select * from myTable", conn ); 
SqlDataAdapter sda 
= new SqlDataAdapter(cmdQuery); 
DataTable myTable 
= new DataTable(); 
sda.Fill(myTable, pagerInfo.ItemStart, pagerInfo.ItemEnd 
"myTable");

  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-07-03 13:05 fsdfds
fsfsadfsdfsda
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-07-03 13:06 fdsf
fdsfsdfds
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-07-03 13:06 fsfdsf
fdsfsdafsd
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-07-03 13:07 fsaf
fdsfsd
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-07-03 13:10 fsdfsd
fdsfds
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-07-03 13:10 fsfs
fsfds
  

# re: 一套可嵌入或独立使用的翻页控件: WebPager(附源码) 2005-08-18 12:11 zell
这么久了不知道楼主更新了没有。
posted on 2006-01-12 10:20  把我的欢乐带给你  阅读(570)  评论(0)    收藏  举报