在WEB系统中,打印的确是比较烦人的问题,如果我们能制作一个属于自己的自定义的打印插件,那么我们在后续自定义打印的时候能随心所欲的控制打印,这样的效果对于程序员来说是非常开心的一件事件,本文将自己开发编写的C# 制作的HTML打印插件分享出来,让有同样需求的朋友提供一个参考;此插件是基于Microsoft .NET Framework 2.0 开发的,缺点是每台客户端在安装插件时,必须要安装Microsoft .NET Framework 2.0 ;本插件能实现 页眉、页脚、表头、标题、表尾的分页打印;支持纸张类型、自动补充空行等功能;由于技术有限,肯定有很多不足的地方,请批评指正!
由于本打印插件是基于我们开发平台的报表基础来开发设计的,所以打印控件的原理:通过JS将页面表格数据生成固定格式的XML字符串(图片通过64base图片格式)传送给打印插件,有打印插件自主绘图生成打印页面。E_Print插件可以在WEB或WinForm中使用:
打印插件完整源码:E_Print.rar (包含插件源码、打包程序、winform调试DEMO)
下面贴出源码:(在源码中有详细的注释说明)
using System; using System.Collections.Generic; using System.Text; using System.Drawing; namespace E_Print { /// <summary> /// 分页计算 /// </summary> public class PagingCalc { #region 私有变量 /// <summary> /// 表格区域 /// </summary> private RectangleF _tableRect; /// <summary> /// 报表行集 /// </summary> private List<Row> _rowsList; /// <summary> /// 是否每页打印标题 /// </summary> private bool _isAllPrintTitle; /// <summary> /// 是否每页打印表头 /// </summary> private bool _isAllPrintHead; /// <summary> /// 是否每页打印表尾 /// </summary> private bool _isAllPrintFoot; /// <summary> /// 标题行集 /// </summary> private List<Row> TitleList; /// <summary> /// 表头前行集 /// </summary> private List<Row> HForeList; /// <summary> /// 表头行集 /// </summary> private List<Row> HeadList; /// <summary> /// 数据行集 /// </summary> private List<Row> DataList; /// <summary> /// 表尾行集 /// </summary> private List<Row> FootList; /// <summary> /// 每页打印标题+表头高度 /// </summary> private float _myHeadPix; /// <summary> /// 每页打印表尾高度 /// </summary> private float _myFootPix; #endregion #region 构造方法 /// <summary> /// 构造函数 /// </summary> public PagingCalc() { _tableRect = new RectangleF(); _rowsList = new List<Row>(); _isAllPrintTitle = false; _isAllPrintHead = false; _isAllPrintFoot = false; TitleList = new List<Row>(); HForeList = new List<Row>(); HeadList = new List<Row>(); DataList = new List<Row>(); FootList = new List<Row>(); _myHeadPix = 0; _myFootPix = 0; } #endregion #region 属性方法 /// <summary> /// 获取--设置--表格区域 /// </summary> public RectangleF TableRect { get { return _tableRect; } set { _tableRect = value; } } /// <summary> /// 获取--设置--表格行集 /// </summary> public List<Row> RowsList { get { return _rowsList; } set { _rowsList = value; } } /// <summary> /// 获取--设置--是否每页打印标题 /// </summary> public bool IsAllPrintTitle { get { return _isAllPrintTitle; } set { _isAllPrintTitle = value; } } /// <summary> /// 获取--设置--是否每页打印表头 /// </summary> public bool IsAllPrintHead { get { return _isAllPrintHead; } set { _isAllPrintHead = value; } } /// <summary> /// 获取--设置--是否每页打印表尾 /// </summary> public bool IsAllPrintFoot { get { return _isAllPrintFoot; } set { _isAllPrintFoot = value; } } /// <summary> /// 获取--设置--每页打印标题+表头高度 /// </summary> public float MyHeadPix { get { return _myHeadPix; } set { _myHeadPix = value; } } /// <summary> /// 获取--设置--每页打印表尾巴高度 /// </summary> public float MyFootPix { get { return _myFootPix; } set { _myFootPix = value; } } #endregion #region 计算方法 /// <summary> /// 分页计算 /// </summary> /// <returns></returns> public List<PagingItem> CalcPages() { List<PagingItem> retPages = new List<PagingItem>(); // 无需分页 if (Get_TableAllHeight() <= TableRect.Height) { PagingItem tmItem0 = new PagingItem(); tmItem0.PageNum = 1; for (int y = 0; y < RowsList.Count; y++) { tmItem0.IndexList.Add(y); } retPages.Add(tmItem0); } else // 需要分页 { // 有设置了 每页打印标题、表头、表位 其中的任意一个 if (Get_IsCusSet_THDF()) // 则执行每页相对分页 { Paging_Relative(0, ref retPages); // 计算每页打印头尾高度 MyHeadPix = 0; if (IsAllPrintTitle) { MyHeadPix += Get_TableTileHeight(); } if (IsAllPrintHead) { MyHeadPix += Get_TableHeadHeight(); } if (IsAllPrintFoot) { MyFootPix = Get_TableFootHeight(); } } else // 执行直接数据分页 { Paging_Direct(0, ref retPages); } } return retPages; } /// <summary> /// 直接分页 /// </summary> /// <param name="startR">开始行号</param> /// <param name="pages">页面数组</param> private void Paging_Direct(int startR, ref List<PagingItem> pages) { float p_Height = TableRect.Height; PagingItem p_Item = new PagingItem(); p_Item.PageNum = pages.Count + 1; for (int t = startR; t < RowsList.Count; t++) { // 检查行内单元格是否不允许分页两种情况:条形码,图片 if (Paging_CheckCell(RowsList[t], p_Height)) { startR = t; pages.Add(p_Item); Paging_Direct(startR, ref pages); break; } else { p_Height -= RowsList[t].RowHeight; if (p_Height <= 0) { startR = t; pages.Add(p_Item); Paging_Direct(startR, ref pages); break; } else { p_Item.IndexList.Add(t); if (t == RowsList.Count - 1) { pages.Add(p_Item); } } } } } /// <summary> /// 相对分页 /// </summary> /// <param name="startR">开始序号</param> /// <param name="pages">页面数组</param> private void Paging_Relative(int startR, ref List<PagingItem> pages) { SplitReportArea(); // 拆分表行 float p_Height = TableRect.Height; // 页面总高 PagingItem p_Item = new PagingItem(); // 分页页面 p_Item.PageNum = pages.Count + 1; // 分页页码 bool runNext = false; // 继续分页 #region 每页打印标题 // 每页打印标题 if (IsAllPrintTitle) { p_Height -= Get_TableTileHeight(); foreach (Row p_Row in TitleList) p_Item.IndexList.Add(p_Row.RowIndex); } else { if (p_Item.PageNum == 1) // 第一页特殊处理 { p_Height -= Get_TableTileHeight(); foreach (Row p_Row in TitleList) p_Item.IndexList.Add(p_Row.RowIndex); } } #endregion #region 每页打印表头 // 每页打印表头 if (IsAllPrintHead) { if (p_Item.PageNum == 1) // 第一页特殊处理 { // 计算表头前的行高 p_Height -= Get_TableHForHeight(); foreach (Row p_Row in HForeList) p_Item.IndexList.Add(p_Row.RowIndex); } // 计算表头行的高度 p_Height -= Get_TableHeadHeight(); foreach (Row p_Row in HeadList) p_Item.IndexList.Add(p_Row.RowIndex); } else { if (p_Item.PageNum == 1) // 第一页特殊处理 { // 计算表头前的行高 p_Height -= Get_TableHForHeight(); foreach (Row p_Row in HForeList) p_Item.IndexList.Add(p_Row.RowIndex); // 计算表头行的高度 p_Height -= Get_TableHeadHeight(); foreach (Row p_Row in HeadList) p_Item.IndexList.Add(p_Row.RowIndex); } } #endregion #region 每页数据区域 // 每页数据划分 if (IsAllPrintFoot) { p_Height -= Get_TableFootHeight(); // 表格高度 先减去表尾的高度 } for (int t = startR; t < DataList.Count; t++) { // 检查行内单元格是否不允许分页两种情况:条形码,图片 if (Paging_CheckCell(DataList[t], p_Height)) // 此情况下,单元格不能分割,并且高度超过页面剩余高度,所以要启动新的一页 { startR = t; runNext = true; break; } else { p_Height -= DataList[t].RowHeight; if (p_Height <= 0) { startR = t; runNext = true; break; } else { p_Item.IndexList.Add(DataList[t].RowIndex); } } } #endregion #region 每页打印表尾 // 每页打印表尾 if (IsAllPrintFoot) { foreach (Row p_Row in FootList) p_Item.IndexList.Add(p_Row.RowIndex); } #endregion #region 添加分页页面 pages.Add(p_Item); if (runNext) { Paging_Relative(startR, ref pages); } #endregion } /// <summary> /// 检查行内单元格如果是图片 /// 并且合并行数大于1 /// </summary> /// <param name="cRow"></param> /// <param name="cHeight"></param> /// <returns></returns> private bool Paging_CheckCell(Row cRow, float cHeight) { foreach (Cell cCell in cRow.RowCells) { if (cCell.IsImage == true) { if (cCell.RectH > cHeight) return true; } } return false; } #endregion #region 辅助方法 /// <summary> /// 获取--报表全部高度 /// </summary> /// <returns></returns> private float Get_TableAllHeight() { float retHight = 0; for (int k = 0; k < RowsList.Count; k++) { Row t_Row = RowsList[k]; retHight += t_Row.RowHeight; } return retHight; } /// <summary> /// 获取是否设置了标题、表头、表尾 中的任意一个 /// </summary> /// <returns></returns> private bool Get_IsCusSet_THDF() { string tmType = ""; foreach (Row cusRow in this.RowsList) { tmType = cusRow.RowType.ToLower().Trim(); if (tmType == "t" || tmType == "h" || tmType == "f") return true; } return false; } /// <summary> /// 获取--报表标题高度 /// </summary> /// <returns></returns> private float Get_TableTileHeight() { float retHight = 0; for (int k = 0; k < TitleList.Count; k++) retHight += TitleList[k].RowHeight; return retHight; } /// <summary> /// 获取--报表表头前高度 /// </summary> /// <returns></returns> private float Get_TableHForHeight() { float retHight = 0; for (int k = 0; k < HForeList.Count; k++) retHight += HForeList[k].RowHeight; return retHight; } /// <summary> /// 获取--报表表头高度 /// </summary> /// <returns></returns> private float Get_TableHeadHeight() { float retHight = 0; for (int k = 0; k < HeadList.Count; k++) retHight += HeadList[k].RowHeight; return retHight; } /// <summary> /// 获取--报表表尾高度 /// </summary> /// <returns></returns> private float Get_TableFootHeight() { float retHight = 0; for (int k = 0; k < FootList.Count; k++) retHight += FootList[k].RowHeight; return retHight; } /// <summary> /// 拆分报表区域 /// </summary> public void SplitReportArea() { TitleList = new List<Row>(); HForeList = new List<Row>(); HeadList = new List<Row>(); DataList = new List<Row>(); FootList = new List<Row>(); for (int m = 0; m < RowsList.Count; m++) { Row mmRow = RowsList[m]; switch (mmRow.RowType.ToLower()) { case "t": // 标题 TitleList.Add(mmRow); break; case "h": // 表头 HeadList.Add(mmRow); break; case "f": // 表尾 FootList.Add(mmRow); break; case "d": // 数据 default: DataList.Add(mmRow); break; } } // 设置表头前行集 if (TitleList.Count == 0 && HeadList.Count > 0) { List<Row> tmpList = new List<Row>(); for (int n = 0; n < DataList.Count; n++) { if (DataList[n].RowIndex < HeadList[0].RowIndex) { HForeList.Add(DataList[n]); tmpList.Add(DataList[n]); } } for (int n = 0; n < tmpList.Count; n++) { DataList.Remove(tmpList[n]); } tmpList.Clear(); } // 重设表尾 不是每页打印表尾情况下,那么表位就去掉 if (!IsAllPrintFoot) { foreach (Row tRow in FootList) DataList.Add(tRow); FootList.Clear(); } } #endregion } }