能实现如上图的的打印功能。
·所有字体,边距,header 高,行高,都可以自定义。
·支持自动计算每页行数与每页固定行数。
·支持页脚显示页数。
 
由于自己用和本人比较懒,所以把属性都设置成公有,赋值的时候小心。
using system;
using system.collections;
using system.componentmodel;
using system.drawing;
using system.drawing.printing;
using system.data;
using system.windows.forms;
namespace cjmanager
{
 public class cuteprinter
 {
 private datagrid datagrid;
 private printdocument printdocument;
 private pagesetupdialog pagesetupdialog;
 private printpreviewdialog printpreviewdialog;
 private string title="";
 
 int currentpageindex=0;
 int rowcount=0;
 int pagecount=0;
 int titlesize=16;
 bool iscustomheader=false;
 
 //brush alertbrush=new solidbrush(color.red);
 string[] header=null;//如果自定义就填入字符串,如果需要斜线分隔,就用/表示,例如:个数#名字 其中#为splitchar
 string[] uplineheader=null;//上行文字数组
 int[] uplineheaderindex=null;//上行的文字index,如果没有上行就设为-1;
 //bool iseverypageprinthead=true;//是否每一页都要打印列头。
 public bool iseverypageprinttitle=false;//是否每一页都要打印标题。
 public int headerheight=50;//标题高度。
 public int topmargin=60; //顶边距 
 public int celltopmargin=6;//单元格顶边距
 public int cellleftmargin=4;//单元格左边距
 public char splitchar='#';//当header要用斜线表示的时候
 public string falsestr="×";//如果传进来的datagrid中有 false,把其转换得字符。
 public string truestr="√";//如果传进来的datagrid中有 true,把其转换得字符。
 public int pagerowcount=7;//每页行数
 public int rowgap = 30;//行高
 public int colgap = 5;//每列间隔
 public int leftmargin = 50;//左边距
 public font titlefont=new font("arial",14);//标题字体
 public font font = new font("arial", 10);//正文字体
 public font headerfont = new font("arial", 9, fontstyle.bold);//列名标题
 public font footerfont=new font("arial",8);//页脚显示页数的字体
 public font uplinefont=new font("arial",9, fontstyle.bold);//当header分两行显示的时候,上行显示的字体。
 public font underlinefont=new font("arial",8);//当header分两行显示的时候,下行显示的字体。
 public brush brush = new solidbrush(color.black);//画刷
 public bool isautopagerowcount=true;//是否自动计算行数。
 public int buttommargin=80;//底边距
 public bool needprintpageindex=true;//是否打印页脚页数
 //string filterstr="";
 
 
 public cuteprinter(datagrid datagrid,string title,int titlesize)
 { 
 this.title=title;
 //this.titlesize=titlesize;
 this.datagrid = datagrid; 
 printdocument = new printdocument();
 printdocument.printpage += new printpageeventhandler(this.printdocument_printpage);
 
 } 
 public cuteprinter(datagrid datagrid,string title)
 { 
 this.title=title;
 
 this.datagrid = datagrid; 
 printdocument = new printdocument();
 printdocument.printpage += new printpageeventhandler(this.printdocument_printpage);
 } 
 public cuteprinter(datagrid datagrid)
 { 
 this.datagrid = datagrid; 
 printdocument = new printdocument();
 printdocument.printpage += new printpageeventhandler(this.printdocument_printpage);
 } 
 public bool settowlineheader(string[] uplineheader,int[] uplineheaderindex)
 {
 this.uplineheader=uplineheader;
 this.uplineheaderindex=uplineheaderindex;
 this.iscustomheader=true;
 return true;
 }
 public bool setheader(string[] header)
 {
 this.header=header;
 return true;
 }
 private void printdocument_printpage(object sender, system.drawing.printing.printpageeventargs e)
 {
 int width=e.pagebounds.width;
 int height=e.pagebounds.height;
 if(this.isautopagerowcount)
 pagerowcount=(int)((height-this.topmargin-titlesize-this.headerfont.height-this.headerheight-this.buttommargin)/this.rowgap);
 pagecount=(int)(rowcount/pagerowcount);
 if(rowcount%pagerowcount>0)
 pagecount++;
 int xoffset=(int)((width-e.graphics.measurestring(this.title,this.titlefont).width)/2);
 int colcount = 0;
 int x = 0;
 int y =topmargin;
 string cellvalue = ""; 
 int startrow=currentpageindex*pagerowcount;
 int endrow=startrow+this.pagerowcount<rowcount?startrow+pagerowcount:rowcount;
 int currentpagerowcount=endrow-startrow;
 if(this.currentpageindex==0 || this.iseverypageprinttitle)
 {
 e.graphics.drawstring(this.title,titlefont,brush,xoffset,y);
 y+=titlesize;
 }
 
 
 colcount = datagrid.tablestyles[0].gridcolumnstyles.count;
 y += rowgap;
 x = leftmargin;
 drawline(new point(x,y),new point(x,y+currentpagerowcount*rowgap+this.headerheight),e.graphics);//最左边的竖线
 int lastindex=-1;
 int lastlength=0;
 int indexj=-1;
 for(int j = 0; j < colcount; j++)
 {
 int colwidth=datagrid.tablestyles[0].gridcolumnstyles[j].width;
 if( colwidth> 0)
 {
 indexj++;
 if(this.header==null || this.header[indexj]=="")
 cellvalue = datagrid.tablestyles[0].gridcolumnstyles[j].headertext; 
 else
 cellvalue=header[indexj];
 if(this.iscustomheader)
 {
 if(this.uplineheaderindex[indexj]!=lastindex)
 {
 
 if(lastlength>0 && lastindex>-1)//开始画上一个upline
 {
 string uplinestr=this.uplineheader[lastindex];
 int upxoffset=(int)((lastlength-e.graphics.measurestring(uplinestr,this.uplinefont).width)/2);
 if(upxoffset<0)
 upxoffset=0;
 e.graphics.drawstring(uplinestr,this.uplinefont,brush,x-lastlength+upxoffset,y+(int)(this.celltopmargin/2));
 drawline(new point(x-lastlength,y+(int)(this.headerheight/2)),new point(x,y+(int)(this.headerheight/2)),e.graphics);//中线
 drawline(new point(x,y),new point(x,y+(int)(this.headerheight/2)),e.graphics);
 }
 lastindex=this.uplineheaderindex[indexj];
 lastlength=colwidth+colgap;
 }
 else
 {
 lastlength+=colwidth+colgap;
 }
 }
 //int currenty=y+celltopmargin;
 
 
 int xoffset=10;
 int yoffset=20;
 int leftwordindex=cellvalue.indexof(this.splitchar);
 if(this.uplineheaderindex!=null && this.uplineheaderindex[indexj]>-1)
 {
 
 if(leftwordindex>0)
 {
 string leftword=cellvalue.substring(0,leftwordindex);
 string rightword=cellvalue.substring(leftwordindex+1,cellvalue.length-leftwordindex-1);
 //上面的字
 xoffset=(int)(colwidth+colgap-e.graphics.measurestring(rightword,this.uplinefont).width);
 yoffset=(int)(this.headerheight/2-e.graphics.measurestring("a",this.underlinefont).height);
 
 //xoffset=6;
 //yoffset=10;
 e.graphics.drawstring(rightword,this.underlinefont,brush,x+xoffset-4,y+(int)(this.headerheight/2));
 e.graphics.drawstring(leftword,this.underlinefont,brush,x+2,y+(int)(this.headerheight/2)+(int)(this.celltopmargin/2)+yoffset-2);
 drawline(new point(x,y+(int)(this.headerheight/2)),new point(x+colwidth+colgap,y+headerheight),e.graphics);
 x += colwidth + colgap; 
 drawline(new point(x,y+(int)(this.headerheight/2)),new point(x,y+currentpagerowcount*rowgap+this.headerheight),e.graphics);
 }
 else
 {
 e.graphics.drawstring(cellvalue, headerfont, brush, x, y+(int)(this.headerheight/2)+(int)(this.celltopmargin/2)); 
 x += colwidth + colgap; 
 drawline(new point(x,y+(int)(this.headerheight/2)),new point(x,y+currentpagerowcount*rowgap+this.headerheight),e.graphics);
 }
 
 }
 else
 {
 if(leftwordindex>0)
 {
 string leftword=cellvalue.substring(0,leftwordindex);
 string rightword=cellvalue.substring(leftwordindex+1,cellvalue.length-leftwordindex-1);
 //上面的字
 xoffset=(int)(colwidth+colgap-e.graphics.measurestring(rightword,this.uplinefont).width);
 yoffset=(int)(this.headerheight-e.graphics.measurestring("a",this.underlinefont).height);
 e.graphics.drawstring(rightword,this.headerfont,brush,x+xoffset-4,y+2);
 e.graphics.drawstring(leftword,this.headerfont,brush,x+2,y+yoffset-4);
 drawline(new point(x,y),new point(x+colwidth+colgap,y+headerheight),e.graphics);
 x += colwidth + colgap; 
 drawline(new point(x,y),new point(x,y+currentpagerowcount*rowgap+this.headerheight),e.graphics);
 }
 else
 {
 e.graphics.drawstring(cellvalue, headerfont, brush, x, y+celltopmargin); 
 x += colwidth + colgap; 
 drawline(new point(x,y),new point(x,y+currentpagerowcount*rowgap+this.headerheight),e.graphics);
 }
 
 }
 }
 } 
 ////循环结束,画最后一个的upline
 if(this.iscustomheader)
 {
 
 if(lastlength>0 && lastindex>-1)//开始画上一个upline
 {
 string uplinestr=this.uplineheader[lastindex];
 int upxoffset=(int)((lastlength-e.graphics.measurestring(uplinestr,this.uplinefont).width)/2);
 if(upxoffset<0)
 upxoffset=0;
 e.graphics.drawstring(uplinestr,this.uplinefont,brush,x-lastlength+upxoffset,y+(int)(this.celltopmargin/2));
 drawline(new point(x-lastlength,y+(int)(this.headerheight/2)),new point(x,y+(int)(this.headerheight/2)),e.graphics);//中线
 drawline(new point(x,y),new point(x,y+(int)(this.headerheight/2)),e.graphics);
 } 
 
 }
 
 int rightbound=x;
 drawline(new point(leftmargin,y),new point(rightbound,y),e.graphics); //最上面的线
 //drawline(new point(leftmargin,y+this.headerheight),new point(rightbound,y+this.headerheight),e.graphics);//列名的下面的线
 y+=this.headerheight;
 //print all rows
 for(int i = startrow; i < endrow; i++)
 {
 
 x = leftmargin;
 for(int j = 0; j < colcount; j++)
 {
 if(datagrid.tablestyles[0].gridcolumnstyles[j].width > 0)
 {
 cellvalue = datagrid[i,j].tostring(); 
 if(cellvalue=="false")
 cellvalue=falsestr;
 if(cellvalue=="true")
 cellvalue=truestr;
 
 e.graphics.drawstring(cellvalue, font, brush, x+this.cellleftmargin, y+celltopmargin);
 x += datagrid.tablestyles[0].gridcolumnstyles[j].width + colgap;
 y = y + rowgap * (cellvalue.split(new char[] {'/r', '/n'}).length - 1); 
 }
 } 
 drawline(new point(leftmargin,y),new point(rightbound,y),e.graphics);
 y += rowgap;
 }
 drawline(new point(leftmargin,y),new point(rightbound,y),e.graphics);
 currentpageindex++;
 if(this.needprintpageindex)
 e.graphics.drawstring("共 "+pagecount.tostring()+" 页,当前第 "+this.currentpageindex.tostring()+" 页",this.footerfont,brush,width-200,(int)(height-this.buttommargin/2-this.footerfont.height));
 string s = cellvalue;
 string f3 = cellvalue;
 
 if(currentpageindex<pagecount)
 {
 e.hasmorepages=true; 
 }
 else
 {
 e.hasmorepages=false;
 this.currentpageindex=0;
 
 }
 //ipagenumber+=1;
 
 
 }
 private void drawline(point sp,point ep,graphics gp)
 {
 pen pen=new pen(color.black);
 gp.drawline(pen,sp,ep);
 }
 public printdocument getprintdocument()
 {
 return printdocument;
 }
 
 public void print()
 {
 
 
 
 rowcount=0;
 if(datagrid.datasource.gettype().tostring() == "system.data.datatable")
 {
 rowcount = ((datatable)datagrid.datasource).rows.count;
 }
 else if(datagrid.datasource.gettype().tostring() == "system.collections.arraylist")
 {
 rowcount = ((arraylist)datagrid.datasource).count;
 }
 try
 {
 pagesetupdialog = new pagesetupdialog();
 pagesetupdialog.document = printdocument;
 pagesetupdialog.showdialog();
 
 
 printpreviewdialog = new printpreviewdialog();
 printpreviewdialog.document = printdocument;
 printpreviewdialog.height = 600;
 printpreviewdialog.width = 800;
 
 printpreviewdialog.showdialog();
 }
 catch(exception e)
 {
 throw new exception("printer error." + e.message);
 }
 }
 } 
}
//用法示例,显示结果如顶图。
private void bnprint_click(object sender, system.eventargs e)
 {
 
 cuteprinter dgp=new cuteprinter(this.datagrid1,this.dlsearchyear.text+"年"+"专业",16);
 string[] uplinestr={"呵呵,hehe","xixi"};
 string[] header={"呵呵#xixi","hee#xcc","kdfj#djjj","kk#jj","kdjf","","","",""};
 dgp.setheader(header);//如果不用改原header就不用赋值。
 //注意,这里的列不包括width==0的列
 int[] uplineindex={-1,-1,0,0,0,-1,1,1};//注意,这里的列不包括width==0的列
 dgp.settowlineheader(uplinestr,uplineindex);
 dgp.print();
 }