续:利用XML实现通用WEB报表打印(实现篇)

本文详细介绍了如何利用XML来实现通用的WEB报表打印。从软件原理到结构设计,再到具体的代码实现,逐一剖析,最后探讨了方案的扩充可能性及项目总结。
摘要由CSDN通过智能技术生成
续:利用XML实现通用WEB报表打印(实现篇)

摘要:
本文结合代码详细讲解了《利用XML实现通用WEB报表打印》(以下简称"《利》")一文中所介绍的报表打印中的.Net Web控件方案的实现及扩充过程。本文为《利》文的续作,文中所举的代码示例均为C#语言编写。

目录:
  • 引言
  • 软件原理
  • 结构设计
  • 代码实现
  • 方案扩充
  • 总结

引言:
在《利》刊出后,有大量的读者发E-Mail给我表示对该方案非常感兴趣,同时还询问具体如何实现报表格式的解析和打印细节并索取该程序的源代码。读者的热情让我始料未及,虽然我一一对来信进行解答和发送了源代码,但是还是深感抱歉和遗憾,因为时间和精力的关系,我不可能对每封信都作出很详细的答复,而且我写的源代码也很乱,事实上,是我花了两个小时赶写出来的(原来的程序因为硬盘故障被销毁了),不但没有什么注解而且还不完善,包括一些标签还没有被实现。
为了弥补以前的缺憾,我花了一些时间改进了程序的结构,重写了全部的源代码,实现了所有标签的功能,下面就要开始讲解该程序的设计和编码过程,在看此文之前,强烈推荐您先阅读《利》一文来了解一下相关的概念,如果在该文中已经有清楚讲解的部分,本文将不再详细介绍,这里只将主要讲解《利》文没有提及或是介绍得不清楚和读者来信提问最多的部分。

软件原理:
该软件的原理其实很简单,就是要方便的解析出定义好的XML格式标记,解读出文件中标记的参数定义,最后将这些信息还原成打印机输出的图形格式。
为了能表达出复杂的报表样式,我们需要定义一些标记,在这些标记中附加上具体的样式信息,作用类似HTML的标签,而我们的解析程序就相当于IE浏览器,所不同的是IE将图形输出到屏幕,而我们是将图形输出到打印机,由于打印机相对于显示屏的特殊性(例如分页),因此我们不能直接采用网页浏览器的标签解析功能来打印,需要自己来做一个满足需要的"打印浏览器"。
针对大多数报表的功能需要,我只定义了两种格式标签:文本(text)和表格(table),它们的具体属性定义和另外一些设置性的标签定义请参考《利》文,这里再补充一幅结构图帮助读者理解。如下所示:


结构设计:
为了描述所有的样式标记,我先定义了一个抽象基类PrintElement,它拥有一个虚拟方法Draw,然后对应表格和文本,从PrintElement派生出两个子类,分别是Table和Text,我还创建了一个Parser类用来解析不同的样式标记和创建对应的对象,它拥有一个静态的方法CreateElement,用来根据不同的格式标签创建出对应的对象。结构图如下所示:

读过《设计模式》的读者一定已经看出来了,这种设计应用了设计模式中的一个非常著名的模式:Abstract Factory。这里使用该模式的好处就是让标签对象和解析器都独立出来,降低了系统的耦合度,有利于今后在需要的时候可以很容易的增加其它的格式标签(下文将会举一个实例)和方便的更换不同的用户界面(图中Client表示Windows应用程序或者是网页插件)。

代码实现:
首先,创建一个"Windows控件库"的新项目,在项目名称处写入RemotePrint,如下图所示:

然后把新建项目中的那个默认的UserControl1类,它的构造函数名和文件名都改成PrintControl。再将它的背景颜色设置为白色,添加三个按纽,并将它们的Enable属性都设置为false,Anchor属性设置为Bottom, Right,再添加一个Label控件用来显示程序状态,它的Anchor属性设置为Left。如下图所示:

再从控件栏中拖入三个打印对象:PrintDocument, PageSetupDialog, PrintPreviewDialog,如下图所示:

将其中的pageSetupDialog1和printPreviewDialog1的Document属性均设置为printDocument1。
然后为项目添加一个PrintElement的新类,代码如下:
using System;
using System.Xml;
using System.Drawing;

namespace RemotePrint
{
	public class PrintElement
	{
		public PrintElement()
		{
		}

		public virtual bool Draw(Graphics g)
		{
			return false;
		}
	}
}
该类中只有一个虚拟方法Draw,注意它规定需要返回一个bool值,这个值的作用是用来指示标签是否在页内打印完毕。
然后再添一个Table的新类,代码如下:
using System;
using System.Xml;
using System.Drawing;

namespace RemotePrint
{
	public class Table : PrintElement
	{
		private XmlNode table;
		public static int count = 0, pc = 1;

		public Table(XmlNode Table)
		{
			table = Table;
		}

		public override bool Draw(Graphics g)
		{
			//表格坐标
			int tableX = int.Parse(table.Attributes["x"].InnerText);
			int tableY = int.Parse(table.Attributes["y"].InnerText);
			int x = tableX, y = tableY;
			DrawTopLine(g, table);//画表格顶线
			Pen pen = new Pen(Color.FromName(table.Attributes["bordercolor"].InnerText), 
				float.Parse(table.Attributes["border"].InnerText));
			int trheight = 0;
			//表头
			foreach(XmlNode tr in table["tablehead"].ChildNodes)
			{
				trheight = int.Parse(tr.Attributes["height"].InnerText);
				DrawTR(x, y, tr, pen, g);
				y += trheight;
			}
			//表项
			for(int i = 0; i < int.Parse(table.Attributes["maxlines"].InnerText); i++)
			{
				XmlNode tr = table["tablebody"].ChildNodes[count];
				trheight = int.Parse(tr.Attributes["height"].InnerText);
				DrawTR(x, y, tr, pen, g);
				y += trheight;
				count++;
				if(count == table["tablebody"].ChildNodes.Count)
					break;
			}
			x = tableX;
			//表底
			foreach(XmlNode tr in table["tablefoot"].ChildNodes)
			{
				trheight = int.Parse(tr.Attributes["height"].InnerText);
				DrawTR(x, y, tr, pen, g);
				y += trheight;
			}
			int currentpage = pc;
			pc++;
			bool hasPage = false;

			if(count < table["tablebody"].ChildNodes.Count - 1)
			{
				hasPage = true;//需要继续打印
			}
			else
			{
				count = 0;
				pc = 1;
				hasPage = false;//表格打印完毕
			}
			return hasPage;
		}

		private void DrawTopLine(Graphics g, XmlNode tabl
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、应用场景与出发点 同一个系统中,为了解决不同的客户可能需要设计不同的单据打印模板实现此方法可能是: 1、设计不同的自带RDLC报表文件,根据当前客户加载不同的报表打印 2、GDI+绘图 和 打印组件 ,不同的客户创建不同的绘图XML格式的模板内容 3、其他第三方组件 主要对比一下前两种方法,第一种方法不好之处在于,不灵活,开发者必须地每个客户制订一个报表,不推荐采用。第二种方法,修改对应的模板内容就可以了, 模板内容可以是Xml文件,也可以是存放在数据库中的Xml格式字符串。推荐采用这种方法。然后这种方法的也有一个棘手问题 :如何让用户快速、方便地设计打印模板,本示例就是为了解决这个问题。 二、实现思路与原理 功能概要:设计一个界面,支持用户自由添加 要打印的项,文本,直线,图片 等,并且可以方便改变打印项的 字体、颜色、粗细、位置,设计时支持效果预览。 技术要点:GDI+绘图、拖动控件、XML解析、自定义控件 三、相关类介绍 绘图工具类:DrawHelper 实现 xml格式模板打印项 之间进行互相转换,在目标画板中绘制 拖动工具类:WinHelper 实现控件的鼠标拖动,键盘移动 自定义控件:用于显示文字的文本框 TextBoxExt、用于显示直线的标签 LabelExt 主窗体代码:用于用户操作,添加,删除,编辑,打印项 详细介绍请参照我的博文:http://de.cel.blog.163.com/blog/static/51451236201472215450939/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值