各种不同的报表工具,其发布方式是不一样的。现在说说一些报表工具的发布方式.笔者对报表了解不多,可能有些认识上的错误,望大家指明.
DevExpress公司出品的报表工具 XtraReport ,它的报表设计器就是集成在VS.NET集成开发环境中,在我看来,它的报表设计器就是一种比较特殊的窗体设计器.把报表样式当作窗体表单来设计,于是它也就没有什么报表模板的概念,它的设计信息就保存在VB.NET或C#代码中。这种方法也就避免了写复杂的互换式报表设计器界面,VS.NET已经提供了这种设计器界面的支持,XtraReport也能保存报表到独立的模板文件中,只是加载报表模板对象后将对象以SOAP格式序列化到一个XML文件中。
这种发布方式是生成的详细的源代码的,程序员可以动手修改这些源代码来实现更灵活的功能,因此方便编程,报表代码可以编译到程序中,报表加载和运行速度快,而且减少了应用系统的文件个数,方便部署。但是修改报表需要重新编译,维护不方便,而且可移植性不好。当新旧版本的XtraReport编程接口变化比较大时,则报表难于移植。
一个最简单的XtraReport报表代码文件可能为,它就是XtraReport格式的报表模板文件
using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using DevExpress.XtraReports.UI;
namespace WindowsApplication2
{
/// <summary>
/// Summary description for XtraReport1.
/// </summary>
public class XtraReport1: DevExpress.XtraReports.UI.XtraReport
{
private DevExpress.XtraReports.UI.DetailBand Detail;
private DevExpress.XtraReports.UI.PageHeaderBand PageHeader;
private DevExpress.XtraReports.UI.PageFooterBand PageFooter;
private DevExpress.XtraReports.UI.XRLabel xrLabel1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public XtraReport1()
{
/// <summary>
/// Required for Windows.Forms Class Composition Designer support
/// </summary>
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Detail = new DevExpress.XtraReports.UI.DetailBand();
this.PageHeader = new DevExpress.XtraReports.UI.PageHeaderBand();
this.PageFooter = new DevExpress.XtraReports.UI.PageFooterBand();
this.xrLabel1 = new DevExpress.XtraReports.UI.XRLabel();
((System.ComponentModel.ISupportInitialize)(this)).BeginInit();
//
// Detail
//
this.Detail.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[]
{
this.xrLabel1
}
);
this.Detail.Height = 120;
this.Detail.Name = "Detail";
//
// PageHeader
//
this.PageHeader.Height = 30;
this.PageHeader.Name = "PageHeader";
//
// PageFooter
//
this.PageFooter.Height = 30;
this.PageFooter.Name = "PageFooter";
//
// xrLabel1
//
this.xrLabel1.Location = new System.Drawing.Point(108, 17);
this.xrLabel1.Name = "xrLabel1";
this.xrLabel1.Size = new System.Drawing.Size(238, 24);
this.xrLabel1.Text = "报表中显示的文本";
//
// XtraReport1
//
this.Bands.AddRange(new DevExpress.XtraReports.UI.Band[]
{
this.Detail, this.PageHeader, this.PageFooter
}
);
((System.ComponentModel.ISupportInitialize)(this)).EndInit();
}
#endregion
}
} |
当然,更多的报表工具是以报表模板文件的形式进行发布。报表设计器生成各种格式生成报表模板文件,有二进制的,有文本的,还有XML格式的。将这些报表模板文件放在合适的地方,而应用程序从指定位置加载报表模板,使用相对应的报表引擎解析报表模板,访问数据源然后输出报表。
这里拿旧版本的FastReport说说,FastReport是Delphi编写的,只有报表设计器和报表预览控件,没有独立的报表引擎,报表模板文件是二进制格式。在非Win32的B/S应用中,首先使用报表设计器生成一个个报表模板文件,上传到服务器某个目录中,然后HTML页面中嵌入一个报表预览控件,由于是C/S环境,报表预览控件不能连接数据库,因此服务器端编程序要读取数据,根据这些数据拼凑成javascript和vbscript脚本字符串发往客户端。在客户端的浏览器中,这些服务器程序生成的脚本语言调用报表预览控件的接口,让它下载报表模板文件,并填充数据到报表预览控件中,如此完成报表输出。整个发布过程比较艰难,因此做几张报表还是可以完成的,若要做大量报表,这种发布方式是不明智的。
微软的Reporting Service
算是比较新的重量级的报表工具了,专门做Web报表,不知道它能否方便的用在C/S系统中。它的报表引擎运行在服务器端。它的报表设计器是基于VS.NET集成开发环境,报表模板文件是XML格式。在实际应用中,首先开发者使用VS.NET编制报表模板,然后发布到报表服务器上,然后客户在浏览器中输入报表页面URL就可查看报表了。这种发布方式比较适合WEB应用,部署方便。
上面的说明,可以知道,通常有两种发布方式,基于源代码的发布方式和基于报表模板文件的发布方式。这两者的差别主要有
比较项目 |
报表模板文件发布方式 |
源代码发布方式 |
模板设计器 |
自己开发互换式设计器,设计器可以独立运行,也可嵌入到VS.NET开发环境。 |
由VS.NET开发环境提供支持,无需编写设计器。 |
自动生成源代码 |
无 |
VS.NET开发环境自动生成。 |
保存方式 |
报表模板文件。 |
源代码文件。 |
发布方式 |
报表模板文件。 |
可执行代码,包含在EXE或DLL中。 |
可移植性 |
高 |
低 |
灵活性 |
低 |
高,可以深入编程,因此可适应各种情况。 |
加载和运行速度 |
低,需要报表引擎加载和解析报表模板文件,动态的生成报表文档对象。 |
快,可执行代码加载后就可直接使用。 |
动态报表 |
可以支持,也可以不支持。 |
必须支持。 |
笔者正在开发的报表工具尝试着同时支持这两种报表发布模式,报表工具既可使用报表模板进行发布,又可生成源代码。其实写个报表工具,支持第一种方式或支持第二种方式都是可以想象的,但要这两者结合起来则一时还不可想象,因为这两者相差太大了。
笔者开发的报表工具的发布是基于报表模板文件的,因此需要进行升级。
第一步就是支持动态报表。在笔者看来,所谓动态报表就是报表引擎提供非常丰富的编程接口。应用程序可以使用这些接口,使用一个空白报表模板来动态的构造出一个实用的报表模板,其中无需报表模板编制工具。还好,我的报表工具是基于XDesignerLib的,而XDesignerLib就是一个中间件,就是为了让其他程序扩展的,因此编程接口非常丰富,我对报表引擎小修小改,也就完成了对动态报表的支持了。
第二步就是考虑如何生成源代码。此时报表设计器就客串为代码生成器,笔者的一些设计器由代码生成功能,比如笔者编写的数据库设计器XDBDesigner能根据数据结构自动生成各种代码,那里使用了XML+XSLT来生成代码。但根据报表模板来生成代码情况复杂,XSLT技术不够用,因此不采用XSLT方式。此外还能采用拼凑字符串的方式来生成代码,但生成的代码种类单一。因此采用CodeDom的方式来生成代码,其过程是遍历所有的报表元素,为每一个报表元素生成一小段CodeDom结构,然后将这些结构组合在一起就可以生成一个完整的代码树,然后使用
Microsoft.CSharp.CSharpCodeProvider 或 Microsoft.VisualBasic.VBCodeProvider
来生成C#代码或VB.NET代码,如果找到其他种类的编程语言的CodeProvider则还可以生成其他种类的编程代码。
比如一个报表设计样式为
![](http://www.cnblogs.com/images/cnblogs_com/xdesigner/groupcustomers.png)
则报表设计器生成的C#和VB.NET代码为
namespace MyNamespace {
using System;
using System.Data;
using System.Xml;
using XDesignerDom;
using XDesignerProperty;
using XDesignerGUI;
using XDesignerCommon;
using XDesigner.Report;
/// <summary>新增文档</summary>
public class MyClass : DesignReportDocument {
/// <summary>Initalize document.</summary>
public MyClass() {
// Begin of initalize document
this.Loading = true;
this.Desc = "新增文档";
this.Title = "新增文档";
this.HeadHeight = 72;
this.Bounds = new System.Drawing.Rectangle(0, 0, 601, 300);
this.PageLeftMargin = 96;
this.PageTopMargin = 96;
this.PageRightMargin = 96;
this.PageBottomMargin = 96;
// element reporttable1
DesignReportTable reporttable1 = this.CreateTableElement();
this.AppendChild(reporttable1);
reporttable1.ID = "reporttable1";
reporttable1.Bounds = new System.Drawing.Rectangle(0, 0, 599, 126);
reporttable1.PrintDockStyle = XDesigner.Report.PrintDockStyle.Top;
reporttable1.InnerDataSource = "地区列表";
// element Col0
DesignReportTableColumn Col0 = this.CreateTableColumnElement();
reporttable1.AppendChild(Col0);
Col0.ID = "Col0";
Col0.Width = 119;
// element Col1
DesignReportTableColumn Col1 = this.CreateTableColumnElement();
reporttable1.AppendChild(Col1);
Col1.ID = "Col1";
Col1.Width = 164;
// element Col2
DesignReportTableColumn Col2 = this.CreateTableColumnElement();
reporttable1.AppendChild(Col2);
Col2.ID = "Col2";
Col2.Width = 75;
// element Col3
DesignReportTableColumn Col3 = this.CreateTableColumnElement();
reporttable1.AppendChild(Col3);
Col3.ID = "Col3";
Col3.Width = 122;
// element Col4
DesignReportTableColumn Col4 = this.CreateTableColumnElement();
reporttable1.AppendChild(Col4);
Col4.ID = "Col4";
Col4.Width = 119;
// element Row0
DesignReportTableRow Row0 = this.CreateTableRowElement();
reporttable1.AppendChild(Row0);
Row0.ID = "Row0";
Row0.Height = 41;
Row0.TableHead = true;
// element A1
DesignReportTableCell A1 = this.CreateTableCellElement();
Row0.AppendChild(A1);
A1.ID = "A1";
A1.Bounds = new System.Drawing.Rectangle(0, 0, 599, 41);
A1.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Bold);
A1.ColSpan = 5;
A1.Text = "分组客户列表";
A1.Align = System.Drawing.StringAlignment.Center;
// element B1
DesignReportTableCell B1 = this.CreateTableCellElement();
Row0.AppendChild(B1);
B1.ID = "B1";
B1.Bounds = new System.Drawing.Rectangle(119, 0, 164, 30);
B1.BorderWidth = 1;
B1.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular);
B1.Align = System.Drawing.StringAlignment.Center;
// element C1
DesignReportTableCell C1 = this.CreateTableCellElement();
Row0.AppendChild(C1);
C1.ID = "C1";
C1.Bou
|