asp.net中使用自定义控件的方式实现一个分页控件的代码

一、概述

  在web开发中,常常需要显示一些数据,而为了方便排版及浏览,我们只需要显示所有记录中的一部分。一般情况下,我们采用分页来实现这个需求。实现分页的方法多种多样,在本文中,我们采用了一个分页空间来记录记录总数、当前页、总页数及页面大小等。为了有一个直观上的印象,先展示该控件运行后的效果,效果如下图所示:

  

asp.net中使用自定义控件的方式实现一个分页控件的代码

  二、实现方案

  为了实现该效果图,在asp.net中,可以使用Custom Controls and User Controls两种方式,User Controls的实现方式及其简单,而且使用起来和平时使用Controls的方式差别极大,所以我们采用Custom Controls实现。

  参考资料:Professional ASP.NET 2.0 Server Control and Component Development

  三、分页控件的实现

  1)、新建一个ASP.NET Server Control项目,

  2)、在该项目中添加一个ASP.NET Server Control的Item,并设置其Name为PageOn,

  3)、修改该类继承于CompositeControl类,并修改其Attribute为如下所示:

  

复制代码 代码如下:

  [DefaultProperty("PageSize")]

  [ToolboxData("<{0}:PageOn runat=server Width=100%></{0}:PageOn>")]

  public class PageOn : CompositeControl

  注:自定义控件必须继承自Control或者其子类。

  4)、 定义需要被组合的控件

  

复制代码 代码如下:

  Label lblMessage;

  LinkButton btnFirst;

  LinkButton btnPrev;

  LinkButton btnNext;

  LinkButton btnLast;

  TextBox txtGoPage;

  Button btnGo;

  5)、定义分页控件需要用到的Proptery

  分页控件主要包括页面大小、当前页、总记录数及总页数等属性,并需要保存在ViewState中,详细代码如下所示:

  

复制代码 代码如下:

  public int RowCount

  {

  get

  {

  if (ViewState["m_rowCount"] == null || int.Parse(ViewState["m_rowCount"].ToString()) < 0)

  {

  ViewState["m_rowCount"] = 0;

  }

  return int.Parse(ViewState["m_rowCount"].ToString());

  }

  set

  {

  if (value < 0)

  {

  ViewState["m_rowCount"] = 0;

  }

  else

  {

  ViewState["m_rowCount"] = value;

  }

  this.RecreateChildControls();

  }

  }

  public int CurPage

  {

  get

  {

  if (ViewState["m_curPage"] ==null || int.Parse(ViewState["m_curPage"].ToString()) < 1)

  {

  ViewState["m_curPage"] = 1;

  }

  return int.Parse(ViewState["m_curPage"].ToString());

  }

  set

  {

  if (value < 1)

  {

  ViewState["m_curPage"] = 1;

  }

  else if (value > PageCount)

  {

  ViewState["m_curPage"] = PageCount;

  }

  else

  {

  ViewState["m_curPage"] = value;

  }

  }

  }

  public int PageCount

  {

  get

  {

  return RowCount / PageSize + 1;

  }

  }

  public int PageSize

  {

  get

  {

  if (ViewState["m_pageSize"] ==null || int.Parse(ViewState["m_pageSize"].ToString()) < 1)

  {

  ViewState["m_pageSize"] = 15;

  }

  return int.Parse(ViewState["m_pageSize"].ToString());

  }

  set

  {

  if (value > 0)

  {

  ViewState["m_pageSize"] = value;

  this.RecreateChildControls();

  }

  }

  }

  6)、生成自定义控件的子空间

  生成自定义空间的子空间需要override基类Control中的CreateChildControls()方法,详细代码如下所示:

  

复制代码 代码如下:

  protected override void CreateChildControls()

  {

  Controls.Clear();

  lblMessage = new Label();

  lblMessage.Text = "当前第" + CurPage + "页 共" + PageCount + "页  共" + RowCount + "条记录";

  lblMessage.ID = "lblMessage";

  Controls.Add(lblMessage);

  btnFirst = new LinkButton();

  btnFirst.Text = "首页";

  btnFirst.CommandName = "first";

  btnFirst.ID = "btnFirst";

  if (CurPage <= 1)

  {

  btnFirst.Enabled = false;

  }

  Controls.Add(btnFirst);

  btnPrev = new LinkButton();

  btnPrev.Text = "上一页";

  btnPrev.CommandName = "prev";

  btnPrev.ID = "btnPrev";

  if (CurPage <= 1)

  {

  btnPrev.Enabled = false;

  }

  Controls.Add(btnPrev);

  btnNext = new LinkButton();

  btnNext.Text = "下一页";

  btnNext.CommandName = "next";

  btnNext.ID = "btnNext";

  if (CurPage >= PageCount)

  {

  btnNext.Enabled = false;

  }

  Controls.Add(btnNext);

  btnLast = new LinkButton();

  btnLast.Text = "末页";

  btnLast.CommandName = "last";

  btnLast.ID = "btnLast";

  if (CurPage >= PageCount)

  {

  btnLast.Enabled = false;

  }

  Controls.Add(btnLast);

  txtGoPage = new TextBox();

  txtGoPage.TabIndex = 1;

  txtGoPage.ID = "txtGoPage";

  txtGoPage.Attributes.Add("onkeyup", @"this.value=this.value.replace(/\D/g,'')");

  txtGoPage.Attributes.Add("onafterpaste", @"this.value=this.value.replace(/\D/g,'')");

  Controls.Add(txtGoPage);

  btnGo = new Button();

  btnGo.TabIndex = 2;

  btnGo.CommandName = "go";

  btnGo.Text = "GO";

  btnGo.ID="btnGO";

  Controls.Add(btnGo);

  Debug.WriteLine("ffffffffffffffffffffffffffffffffffffffffffffffffff");

  base.CreateChildControls();

  }

  7)、定义自定义控件的布局

  第6步完成后,所有定义的控件都会顺序显示到页面上了,但是这样的效果不友好,如果对于多行的空间更是如此,所有我们需要定义控件的布局,自定义控件的布局需要重写RenderContents()方法及TagKey属性,此示例中的代码如下所示:

  

复制代码 代码如下:

  protected override void RenderContents(HtmlTextWriter output)

  {

  output.RenderBeginTag(HtmlTextWriterTag.Tr);

  output.AddStyleAttribute("text-align", "left");

  output.RenderBeginTag(HtmlTextWriterTag.Td);

  output.Write("  ");

  lblMessage.RenderControl(output);

  output.RenderEndTag();

  output.AddStyleAttribute("text-align", "right");

  output.RenderBeginTag(HtmlTextWriterTag.Td);

  btnFirst.RenderControl(output);

  output.Write("  ");

  btnPrev.RenderControl(output);

  output.Write("  ");

  btnNext.RenderControl(output);

  output.Write("  ");

  btnLast.RenderControl(output);

  output.Write("到");

  output.AddStyleAttribute(HtmlTextWriterStyle.Width, "30px");

  txtGoPage.RenderControl(output);

  output.Write("页");

  btnGo.RenderControl(output);

  output.Write("  ");

  output.RenderEndTag();

  output.RenderEndTag();

  }

  protected override HtmlTextWriterTag TagKey

  {

  get

  {

  return HtmlTextWriterTag.Table;

  }

  }

  上面的代码中,我们使用Table来布局,也可以使用其它的布局方式,比如DIV+CSS。

  8)、捕捉并处理控件的事件

  到此以后,这些代码已经可以生成文章开头图所显示的效果,但是什么事情也做不了,不能响应该控件上的事件,所有还需要继续实现该控件上的事件代码,实现这些事件采用冒泡所有子控件的事件来实现。

  首先,定义一个委托:

  

复制代码 代码如下:

  public delegate void PageOnEventHandler(object sender, EventArgs args);

  其次,定义基于该委托的事件:

  

复制代码 代码如下:

  public event PageOnEventHandler RecPageChanged;

  最后,重写冒泡事件,并根据参数特征,捕获需要处理的事件,使其调用需要的方法。

  

复制代码 代码如下:

  protected override bool OnBubbleEvent(object source, EventArgs args)

  {

  bool handled = false;

  CommandEventArgs cea = args as CommandEventArgs;

  if(cea == null)

  {

  return handled;

  }

  switch (cea.CommandName)

  {

  case "first":

  handled = true;

  CurPage = 1;

  break;

  case "prev":

  handled = true;

  if (CurPage > 1)

  {

  CurPage--;

  }

  else

  {

  CurPage = 1;

  }

  break;

  case "next":

  handled = true;

  if (CurPage < PageCount)

  {

  CurPage ++ ;

  }

  else

  {

  CurPage = PageCount;

  }

  break;

  case "last":

  handled = true;

  CurPage = PageCount;

  break;

  case "go":

  string strGo = txtGoPage.Text.Trim();

  int iGo;

  if (!string.IsNullOrEmpty(strGo) && int.TryParse(strGo, out iGo))

  {

  handled = true;

  CurPage = iGo;

  }

  break;

  }

  if (handled)

  {

  if (this.RecPageChanged != null)

  {

  RecPageChanged(this, args);

  this.RecreateChildControls();

  }

  return handled;

  }

  else

  {

  return base.OnBubbleEvent(source, args);

  }

  }

  

  到此就完成了分页控件的开发。

  注:可以定制该控件的样式,或者使用属性暴露子控件的属性来控制样式等.

  四、使用分页控件

  完成自定义控件的开发后,在Toolbox中Choose Items或者直接在需要使用该自定义控件的项目中引用该项目或者DLL,即可在Toolbox中显示自定义控件了。然后用拖拽的方式即可把分页控件放到需要的地方,就像使用button控件一样简单。

  然后再该页面的后台代码的OnLoad事件中,注册需要被调用的方法到该控件的RecPageChanged事件中,如下所示:

  

复制代码 代码如下:

  PageOn1.RecPageChanged += new CustomControl.PageOnEventHandler(PageOn1_RecPageChanged);

  最后,只需要在方法PageOn1_RecPageChanged中编写自己的代码即可。

  

复制代码 代码如下:

  void PageOn1_RecPageChanged(object sender, EventArgs args)

  {

  //To do something

  }

  控件的详细代码如下:

  

复制代码 代码如下:

  namespace CustomControl

  {

  public delegate void PageOnEventHandler(object sender, EventArgs args);

  [DefaultProperty("PageSize")]

  [ToolboxData("<{0}:PageOn runat=server Width=100%></{0}:PageOn>")]

  public class PageOn :CompositeControl

  {

  #region

  Label lblMessage;

  LinkButton btnFirst;

  LinkButton btnPrev;

  LinkButton btnNext;

  LinkButton btnLast;

  TextBox txtGoPage;

  Button btnGo;

  #endregion

  protected override void CreateChildControls()

  {

  Controls.Clear();

  lblMessage = new Label();

  lblMessage.Text = "当前第" + CurPage + "页 共" + PageCount + "页  共" + RowCount + "条记录";

  lblMessage.ID = "lblMessage";

  Controls.Add(lblMessage);

  btnFirst = new LinkButton();

  btnFirst.Text = "首页";

  btnFirst.CommandName = "first";

  btnFirst.ID = "btnFirst";

  if (CurPage <= 1)

  {

  btnFirst.Enabled = false;

  }

  Controls.Add(btnFirst);

  btnPrev = new LinkButton();

  btnPrev.Text = "上一页";

  btnPrev.CommandName = "prev";

  btnPrev.ID = "btnPrev";

  if (CurPage <= 1)

  {

  btnPrev.Enabled = false;

  }

  Controls.Add(btnPrev);

  btnNext = new LinkButton();

  btnNext.Text = "下一页";

  btnNext.CommandName = "next";

  btnNext.ID = "btnNext";

  if (CurPage >= PageCount)

  {

  btnNext.Enabled = false;

  }

  Controls.Add(btnNext);

  btnLast = new LinkButton();

  btnLast.Text = "末页";

  btnLast.CommandName = "last";

  btnLast.ID = "btnLast";

  if (CurPage >= PageCount)

  {

  btnLast.Enabled = false;

  }

  Controls.Add(btnLast);

  txtGoPage = new TextBox();

  txtGoPage.TabIndex = 1;

  txtGoPage.ID = "txtGoPage";

  txtGoPage.Attributes.Add("onkeyup", @"this.value=this.value.replace(/\D/g,'')");

  txtGoPage.Attributes.Add("onafterpaste", @"this.value=this.value.replace(/\D/g,'')");

  Controls.Add(txtGoPage);

  btnGo = new Button();

  btnGo.TabIndex = 2;

  btnGo.CommandName = "go";

  btnGo.Text = "GO";

  btnGo.ID="btnGO";

  Controls.Add(btnGo);

  Debug.WriteLine("ffffffffffffffffffffffffffffffffffffffffffffffffff");

  base.CreateChildControls();

  }

  public int RowCount

  {

  get

  {

  if (ViewState["m_rowCount"] == null || int.Parse(ViewState["m_rowCount"].ToString()) < 0)

  {

  ViewState["m_rowCount"] = 0;

  }

  return int.Parse(ViewState["m_rowCount"].ToString());

  }

  set

  {

  if (value < 0)

  {

  ViewState["m_rowCount"] = 0;

  }

  else

  {

  ViewState["m_rowCount"] = value;

  }

  this.RecreateChildControls();

  }

  }

  public int CurPage

  {

  get

  {

  if (ViewState["m_curPage"] ==null || int.Parse(ViewState["m_curPage"].ToString()) < 1)

  {

  ViewState["m_curPage"] = 1;

  }

  return int.Parse(ViewState["m_curPage"].ToString());

  }

  set

  {

  if (value < 1)

  {

  ViewState["m_curPage"] = 1;

  }

  else if (value > PageCount)

  {

  ViewState["m_curPage"] = PageCount;

  }

  else

  {

  ViewState["m_curPage"] = value;

  }

  }

  }

  public int PageCount

  {

  get

  {

  return RowCount / PageSize + 1;

  }

  }

  public int PageSize

  {

  get

  {

  if (ViewState["m_pageSize"] ==null || int.Parse(ViewState["m_pageSize"].ToString()) < 1)

  {

  ViewState["m_pageSize"] = 15;

  }

  return int.Parse(ViewState["m_pageSize"].ToString());

  }

  set

  {

  if (value > 0)

  {

  ViewState["m_pageSize"] = value;

  this.RecreateChildControls();

  }

  }

  }

  protected override void RenderContents(HtmlTextWriter output)

  {

  output.RenderBeginTag(HtmlTextWriterTag.Tr);

  output.AddStyleAttribute("text-align", "left");

  output.RenderBeginTag(HtmlTextWriterTag.Td);

  output.Write("  ");

  lblMessage.RenderControl(output);

  output.RenderEndTag();

  output.AddStyleAttribute("text-align", "right");

  output.RenderBeginTag(HtmlTextWriterTag.Td);

  btnFirst.RenderControl(output);

  output.Write("  ");

  btnPrev.RenderControl(output);

  output.Write("  ");

  btnNext.RenderControl(output);

  output.Write("  ");

  btnLast.RenderControl(output);

  output.Write("到");

  output.AddStyleAttribute(HtmlTextWriterStyle.Width, "30px");

  txtGoPage.RenderControl(output);

  output.Write("页");

  btnGo.RenderControl(output);

  output.Write("  ");

  output.RenderEndTag();

  output.RenderEndTag();

  }

  protected override HtmlTextWriterTag TagKey

  {

  get

  {

  return HtmlTextWriterTag.Table;

  }

  }

  public event PageOnEventHandler RecPageChanged;

  protected override bool OnBubbleEvent(object source, EventArgs args)

  {

  bool handled = false;

  CommandEventArgs cea = args as CommandEventArgs;

  if(cea == null)

  {

  return handled;

  }

  switch (cea.CommandName)

  {

  case "first":

  handled = true;

  CurPage = 1;

  break;

  case "prev":

  handled = true;

  if (CurPage > 1)

  {

  CurPage--;

  }

  else

  {

  CurPage = 1;

  }

  break;

  case "next":

  handled = true;

  if (CurPage < PageCount)

  {

  CurPage ++ ;

  }

  else

  {

  CurPage = PageCount;

  }

  break;

  case "last":

  handled = true;

  CurPage = PageCount;

  break;

  case "go":

  string strGo = txtGoPage.Text.Trim();

  int iGo;

  if (!string.IsNullOrEmpty(strGo) && int.TryParse(strGo, out iGo))

  {

  handled = true;

  CurPage = iGo;

  }

  break;

  }

  if (handled)

  {

  if (this.RecPageChanged != null)

  {

  RecPageChanged(this, args);

  this.RecreateChildControls();

  }

  return handled;

  }

  else

  {

  return base.OnBubbleEvent(source, args);

  }

  }

  }

  }

  OK,完成