工作需要,要实现windows应用程序中用的datagrid具有分页功能,不知道ms怎么想的,asp.net的datagrid有这样的功能,为什么不在winForm的datagrid里面提供这样的功能,还得让我费这么大劲儿来重写这个控件,真是麻烦。
首先,我们要做一个类来继承系统的datagrid:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace oilx.PagingDataGrid
{
public class PagingDataGrid : DataGrid
{
// 声明一些必要的全局变量。
private System.ComponentModel.Container components = null;
/// <summary>
///
/// </summary>
private const int MarkerWith = 14;
/// <summary>
///
/// </summary>
private Point _pointTopLeft;
/// <summary>
///
/// </summary>
private int _row = 1;
//
private int _rowNumberFigure = 0;
private bool _zeroPadding = false;
/// <summary>
///
/// </summary>
private string _rowHeaderCaption = String.Empty;
/// <summary>
///
/// </summary>
private int _pageSize = 10;
/// <summary>
///
/// </summary>
private int _currentPageCount = 1;
/// <summary>
///
/// </summary>
private bool _allowPaging = false;
/// <summary>
///
/// </summary>
private int _previousPageCount = -1;
/// <summary>
///
/// </summary>
private DataTable _pageDataSource;
/// <summary>
///构造函数
/// </summary>
/// <param name="container"></param>
public PagingDataGrid (System.ComponentModel.IContainer container)
{
container.Add(this);
InitializeComponent();
InitiarizeControl();
}
/// <summary>
///构造函数重载
/// </summary>
public FixdItemDataGrid()
{
InitializeComponent();
InitiarizeControl();
}
// 下面我们需要增加一些用于分页的公共属性
/// <summary>
/// 页面大小,即每页现实的数据条数
/// </summary>
[Browsable(true),Description("页面大小")]
public int PageSize
{
get
{
return _pageSize;
}
set
{
_pageSize = value;
}
}
/// <summary>
/// 分页数
/// </summary>
[Browsable(true),Description("分页数")]
public int PageCount
{
get
{
if(DataSource == null)
{
return 0;
}
if(_pageDataSource == null || _pageDataSource.Rows.Count <= 0)
{
return 0;
}
int i = _pageDataSource.Rows.Count%PageSize==0?0:1;
return _pageDataSource.Rows.Count/PageSize+i;
}
}
/// <summary>
/// 当前页数
/// </summary>
[Browsable(true),Description("当前页数")]
public int CurrentPageCount
{
get
{
if(_currentPageCount < 0)
{
return 1;
}
if(_currentPageCount >= PageCount)
{
return PageCount;
}
return _currentPageCount;
}
set
{
if(value >=PageCount)
{
_currentPageCount = PageCount;
}
_currentPageCount = value;
}
}
/// <summary>
///是否允许分页
/// </summary>
[Browsable(true),Description("是否允许分页")]
public bool AllowPaging
{
get
{
return _allowPaging;
}
set
{
_allowPaging = value;
}
}
/// <summary>
///行标题
/// </summary>
[Browsable(true),Description("行标题")]
public string RowHeaderCaption
{
get
{
return _rowHeaderCaption;
}
set
{
_rowHeaderCaption = value;
}
}
// 基本工作都作完了,下面开始我们分页的重点,go!
// 我们需要重写系统一个方法,那就是:
/// <summary>
/// 该方法在数据源被修改的时候激活。
/// </summary>
/// <param name="e"></param>
protected override void OnDataSourceChanged(System.EventArgs e)
{
base.OnDataSourceChanged(e);
// 如果数据源为空那么就返回。
if( this.DataSource == null )
{
return;
}
// 下面判断数据源的类型,一般情况下,datagrid数据源形式为3种,1,dataset,2,datatable,3,dataview。
// 在这里我们要做的是把数据源的数据保存到另外一个变量里面,这样当我们在作分页
//的时候,需要修改数据源时,可以把这个变量当作原始的数据源来进行判断。
if(this.DataSource is DataSet)
{
if( ((DataSet)DataSource).Tables.Count > 0)
{
this.DataSource = ((DataSet)DataSource).Tables[0];
}
else
{
return;
}
}
if(_pageDataSource == null)
{
if(DataSource is DataSet)
{
if(((DataSet)DataSource).Tables[0].Rows.Count <=0)
{
return;
}
_pageDataSource = ((DataSet)DataSource).Tables[0].Clone();
for(int i = 0;i<((DataSet)DataSource).Tables[0].Rows.Count;i++)
{
DataRow drRow = _pageDataSource.NewRow();
drRow.ItemArray = ((DataSet)DataSource).Tables[0].Rows[i].ItemArray;
_pageDataSource.Rows.Add(drRow);
}
}
else if(DataSource is DataTable)
{
if(((DataTable)DataSource).Rows.Count <= 0)
{
return;
}
_pageDataSource = ((DataTable)DataSource).Clone();
for(int i = 0;i<((DataTable)DataSource).Rows.Count;i++)
{
DataRow drRow = _pageDataSource.NewRow();
drRow.ItemArray = ((DataTable)DataSource).Rows[i].ItemArray;
_pageDataSource.Rows.Add(drRow);
}
}
else if(DataSource is DataView)
{
if( ((DataView)DataSource).Table.Rows.Count <= 0)
{
return;
}
_pageDataSource = ((DataView)DataSource).Table.Clone();
for(int i = 0;i<((DataView)DataSource).Table.Rows.Count;i++)
{
DataRow drRow = _pageDataSource.NewRow();
drRow.ItemArray = ((DataView)DataSource).Table.Rows[i].ItemArray;
_pageDataSource.Rows.Add(drRow);
}
}
}
_pointTopLeft = new Point(this.GetCellBounds(0,0).X + 4, this.GetCellBounds(0,0).Y + 4);
}
// 上面的所作的只是把原数据源数据导入到_pageDataSource这个datatable里面,在这里有
//人可能要问为什么不用 _pageDataSource = (DataTable)this.DataSource;
// 而使用
//DataRow drRow = _pageDataSource.NewRow();
//drRow.ItemArray = ((DataView)DataSource).Table.Rows[i].ItemArray;
//_pageDataSource.Rows.Add(drRow);
//这是因为DataTable是引用类型,如果直接付值的话,那么当原数据源的数据被修改时,——//_pageDataSource也会被修改。
//好了,临时数据已经处理完了,那么真正的分页处理开始,大家都知道,.net控件要显示在窗体//上,那么需要我们把它的实体画上去,那么ms.net在所有控件都提供了下面这样的方法,可以//让我们把控件按照我们修改后的形式表现出来:
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
base.OnPaint(e);
if( this.DataSource == null )
{
return;
}
if(DataSource != null && DataSource is DataSet)
{
return;
}
// 在这里我们开始对分页进行进行处理
if(AllowPaging)
{
if(_pageDataSource != null)
{
if(_previousPageCount != CurrentPageCount)
{
// 判断当前是第几页
int i = CurrentPageCount*PageSize-PageSize;
if(i<0)
{
i = 0;
}
//下面判断是否为最后一页
if(i <= _pageDataSource.Rows.Count)
{
DataTable dtPage = _pageDataSource.Clone();
int iCount = 0;
根据PageSize来生成一个dataTable,重新进行数据源绑定。
for(;i<_pageDataSource.Rows.Count;i++)
{
DataRow drRow = dtPage.NewRow();
drRow.ItemArray= _pageDataSource.Rows[i].ItemArray;
dtPage.Rows.Add(drRow);
iCount ++;
if(iCount>=PageSize)
{
break;
}
}
// 绑定新的数据源
this.DataSource = dtPage;
}
_previousPageCount = CurrentPageCount;
}
}
}
// RowHeaders如果为true,那么我们要给RowHeader上面标上序号和标题
if(this.RowHeadersVisible)
{
DataGrid.HitTestInfo hti = this.HitTest(_pointTopLeft);
int iRowhti = hti.Row;
if(iRowhti < 0)
{
iRowhti = 0;
}
int iDelta = this.GetCellBounds(iRowhti, 0).Height + 1;
int iHeight = this.GetCellBounds(iRowhti, 0).Top + 1;
// 这个方法里面是显示RowHeaders的标题,详见该方法实现
ShowColumnTitles(e);
CurrencyManager cm = (CurrencyManager) this.BindingContext[this.DataSource, this.DataMember];
while(iHeight < this.Height - iDelta && iRowhti < cm.Count)
{
string strText = String.Empty;
if(_zeroPadding)
{
strText = String.Format("{0}", _row + iRowhti).PadLeft(_rowNumberFigure, '0');
}
else
{
strText = String.Format("{0}", _row + iRowhti);
}
e.Graphics.DrawString(strText, this.Font, new SolidBrush(Color.Black), 20, iHeight);
// 下面处理的是在RowHeaders上面画一条分割线,为了有阴影的感觉,我画了一条灰色和白色两条,看着还挺像 ^_^
if(!this.CaptionVisible)
{
ShowSepalatorLine(e, new Point(17, 2), new Point(17, iHeight-2 + this.PreferredRowHeight),Color.Gray);
ShowSepalatorLine(e, new Point(18, 2), new Point(18, iHeight-2 + this.PreferredRowHeight),Color.White);
}
else
{
ShowSepalatorLine(e, new Point(17, 20), new Point(17, iHeight-2 + this.PreferredRowHeight),Color.Gray);
ShowSepalatorLine(e, new Point(18, 20), new Point(18, iHeight-2 + this.PreferredRowHeight),Color.White);
}
iHeight += iDelta;
iRowhti++;
}
_row =CurrentPageCount*PageSize-PageSize+1;
if(_row < 0)
{
_row =1;
}
}
}
// 画线
private void ShowSepalatorLine(PaintEventArgs e, Point ptStart, Point ptEnd,Color lineColor)
{
Pen pen = new Pen(new SolidBrush(lineColor), 1);
e.Graphics.DrawLine(pen, ptStart, ptEnd);
}
/// <summary>
/// 显示RowHeaders的标题
/// </summary>
/// <param name="e"></param>
/// <param name="source"></param>
private void ShowColumnTitles(PaintEventArgs e)
{
string strHeader = RowHeaderCaption;
int iX = MarkerWith + 5;
int iWith = this.RowHeaderWidth;
using(StringFormat sf = new StringFormat())
{
sf.FormatFlags = StringFormatFlags.NoWrap;
sf.Trimming = StringTrimming.EllipsisCharacter;
sf.Alignment = StringAlignment.Near;
sf.LineAlignment = StringAlignment.Center;
RectangleF rect;
if(!CaptionVisible)
{
rect = new RectangleF(new PointF(iX, 3), new SizeF(iWith, this.PreferredRowHeight));
}
else
{
rect = new RectangleF(new PointF(iX, 20), new SizeF(iWith, this.PreferredRowHeight));
}
e.Graphics.DrawString(strHeader, this.Font, new SolidBrush(Color.Black), rect, sf);
}
}
/// <summary>
/// ?}?E?X?|?C?“?^‚???“®¸?—¯
/// </summary>
/// <param name="e"></param>
protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
{
DataGrid.HitTestInfo hitTestInfo = this.HitTest(new Point(e.X, e.Y)) if(hitTestInfo.Type == DataGrid.HitTestType.RowResize)
{
return;
}
base.OnMouseMove(e);
}
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
{
DataGrid.HitTestInfo hitTestInfo = this.HitTest(new Point(e.X, e.Y));
if(hitTestInfo.Type == DataGrid.HitTestType.RowResize)
{
return;
}
base.OnMouseDown(e);
}
}
}
好了,到这里这个,这个分页的datagrid就算完了。
程序实现:
dataGrid1.CurrentPageCount ++;
dataGrid1.Invalidate();
一定要写dataGrid1.Invalidate();这个方法,不然datagrid不能刷新,看不到分页效果!