您的位置:首页 > 其它

reportviewer动态加载报表的实现以及动态控制报表,套打,存折打印模式等的一些探讨,欢迎批评指正!

2007-11-19 13:44 609 查看
需求如下:
1.可以在一个界面中列出多张报表,根据用户的选择,浏览指定的报表,用户可以随意选择,切换新报表,也即是报表可以被替换的。
2.可以实现对所选择的报表,替换它的数据源,或者往数据源增加或删除行(如果数据源绑定的是自定义对象集合,则可以往集合插入或移除对象),也即是报表的数据是可以被替换的。
3如何让最终用户控制报表,我的意思是:可以让用户在默认报表的情况下,更改下列宽行高,隐藏排序列,设置页眉页脚或者表标题,等等。应用了这些功能后,在报表浏览器看到新的结果。
4套打报表,连续打印,存折打印模式.
5.有界面和无界面的打印.
实现思路如下:
1,如何让一个报表浏览器适应多张报表?
在网上找了很多资料,在这方面的介绍很少,看了一个博客朋友的文章http://blog.csdn.net/qiujiahao/archive/2007/08/09/1733415.aspx,是通过动态加载报表浏览器(ReportViewer)的方式来实现动态切换报表,不过,感觉很奇怪,换个URL,难道IE浏览器就把原先的IE关了再开新的IE来浏览网页吗?但是,它的变通思路还是值得借鉴的。这里是该博友文章的要点
ControlCollection coll = ReportViewer1.Parent.Controls;


int oldIndex = coll.IndexOf(ReportViewer1);


ReportViewer newViewer = new ReportViewer();


coll.AddAt(oldIndex, newViewer); 注意,如果是VB代码,此处没有AddAt方法,需要你为添加进去的对象指定好索引后再Add进去


coll.Remove(ReportViewer1);
上面的意思是把新的报表浏览器reportviewer替换旧的报表浏览器
这不是本文的要点,好了.先撇开这个不谈,我们知道,报表浏览器的工作原理是这样的。



[align=left]· 数据源
  可以是传统数据库,也可以是XML表格,当然,也可以是自定义的对象
Data Adapter 及 Connection 等
  用来连接传统的数据库
DataSet
  用来存储数据,同时可以直接操作XML文件
BindingSource
  利用DateSet来填充BindingSource,这一步数据中转逻辑上有点多余,但是必不可少
ReportDataSource
  利用BindingSource来填充ReportDataSource,......-_-!!
ReportViewer
利用ReportDataSource填充的 数据 及 指定给它的RDLC报表文件来显示报表[/align]
好了,了解了上面的原理后,我们就可以开始让我们的报表浏览器工作起来了。
报表浏览器---指定报表定义文件和报表定义文件所绑定的数据源,(数据源可以是数据集或者自定义对象,)
(1)其中报表定义文件的指定方法:Me.ReportViewer1.LocalReport.ReportEmbeddedResource = "rpDemo.OldReport.rdlc",在这里,我是将报表定义文件OldReport.rdlc嵌入到项目中的,如果你的报表定义文件存在于项目之外,则可以使用Me.ReportViewer1.LocalReport.ReportPath来指定报表定义文件(.其中"rpDemo. OldReport.rdlc 前面的rpDemo是项目名.)
(2)其中报表定义文件所需要的数据源指定方式如下:
代码是在winform中写的。
Private bdds As BindingSource ‘全局变量,绑定源,在窗体初始化的时候被创建,绑定源就像个中间对象,连接着报表浏览器和报表的数据源,使得报表浏览器能显示报表的数据。
Privat e ds As demolist ‘这个ds是提供给绑定源的,而绑定源提供给报表源,报表源提供给报表浏览器的localreport属性下的datasources属性。将ds设置为全局变量,以便可以在子程序中更改DS的数据。来测试报表适应数据源的改变。
Sub New()
' 此调用是 Windows 窗体设计器所必需的。
InitializeComponent()
' 在 InitializeComponent() 调用之后添加任何初始化。
If Me.components Is Nothing Then Me.components = New System.ComponentModel.Container
bdds = New BindingSource(Me.components) ‘创建绑定源对象的时候需要指定容器,以便于绑定源跟该容器下的报表浏览器绑定起来。
End Sub

然后创建ReportDataSource对象,并将它的名字指定为报表定义文件中绑定的数据源,将它的值指定为bdds绑定源
Dim reportds As New Microsoft.Reporting.WinForms.ReportDataSource("rpDemo_demo", bdds) ' 第一个参数指定的是我们在制作报表的时候为报表提供的数据源,第二个参数是绑定源对象,这样绑定源跟报表数据源就产生关联了。
ds = New demolist
bdds.DataSource = ds ‘将数据实例提供给绑定源,我这里的数据实例是个对象集而不是数据集
Me.ReportViewer1.LocalReport.DataSources.Add(reportds) ’最后一步,将报表数据源将到报表中

(3)好了。一个报表浏览器就配置好了定义文件和数据源了
Me.ReportViewer1.RefreshReport() ‘这样就可以呈现报表了。
(4) Me.ReportViewer1.Reset() ‘假如你从一个下拉框中选择新的报表定义文件后就执行这句代码,可以将报表浏览器的配置清空,然后重新配置报表浏览器呈现新的报表,代码如下。
[align=left]Me.ReportViewer1.LocalReport.ReportEmbeddedResource = "rpDemo. NewReport.rdlc" ‘注意,这里指定新的报表定义文件了[/align]
[align=left] [/align]
[align=left] Dim reportds As New Microsoft.Reporting.WinForms.ReportDataSource("rpDemo_demo2", bdds) ‘这里的两个参数也变了。因为要显示新的报表,就重新指定了新的报表定义文件,报表定义文件变了,所以第一个参数指定的报表数据源当然也跟着变了。而第二个参数指定的是绑定源,我们不需要更改,只是提供给绑定源的数据实例要变而已。demo2list而不再是demolist[/align]
[align=left] bdds.DataSource = New demo2list[/align]
[align=left] Me.ReportViewer1.LocalReport.DataSources.Add(reportds)[/align]
Me.ReportViewer1.RefreshReport()
2如何更改报表的数据源
更改数据的方法也很简单,由于我们使用了绑定源对象,所以对于数据源的更改,报表浏览器是不需要理会的,这就是绑定源的好处了。绑定源对报表数据源负责。
[align=left]ds.Add(New demo("xyz", "asd", "ddd")) ‘往我们的demolist集合中插入一个对象[/align]
Me.ReportViewer1.RefreshReport() ‘新插入的对象被显示了

3需求3 动态控制报表(可以让用户稍微调整报表的样式)
思路有三个
A. 报表对象是否公开了这些方法呢?这是最先想到的 ReportViewer.localReport.在这里,localreport下的有关控制报表项的方法都是只读的。行不通
B. 写一个动态生成报表定义文件的程序,由于报表定义文件是基于XML格式的,所以只要了解他的结构,就可以做到,不过,当你想生成的报表格式比较复杂的时候,对于你这个自定义报表生成器的要求就高很多了,并不建议这么做,有个老兄对这个报表定义文件的解析有很多的了解,可以参考他的博客http://blog.csdn.net/flygoldfish/archive/2005/12/16/554035.aspx
C. 将报表定义文件使用XMLDOCUMNET这样的类,在内存中对该文件的XML元素做更改,然后将更改后的定义文件重新加载到报表浏览器,这样的方法比较好,参考此博友的文章
D. http://www.cnblogs.com/dlwang2002/archive/2007/02/14/410499.html
E.
由于我未在这方面做测试,希望有需求的朋友如果做出来的话,在我的博客留个言,大家交流一下。其原理就是更改报表定义文件的XML元素来达到更改报表项的目的。

4需求4套打的实现.和单据连续打印的问题
套打就是像打印发票一样,纸张是印刷好了特定的格式了,而报表只负责打印数据,实现的思路主要是在使用Reporting services的报表设计器制作报表的时候,对控件的位置指定表达式,这样,在程序中编码,计算出该控件应该所在的位置,计算元素可以从报表对象中取得.
对于连续打印的问题,请记得先在最外部使用一个列表控件,把表格控件放在列表控件里面,这样即可实现一份格式,不同的数据行,打印的时候就可以打出多份报表(如员工资料报表)由于我还没做完,等我做出后再发布.

5需求,界面打印不需要提了,reportviewer控件有打印的功能,非界面打印,可以用到localreport和printdocument的printpage事件,在这个事件中进行处理,主要用到localreport.Render方法,MSDN帮助有这个例子,可以在帮助中搜索localreport找到,这里不多说了。
总结:
需求1的实现对于报表浏览器来说,第一是报表定义文件变了,第二是报表定义文件所要求的数据源也变了。对于第一个变化,需要重新指定报表定义文件即可,对于第二个变化,我们需要指定新的报表数据源,然后将绑定源所依赖的数据实例也替换成报表数据源所需要的。别忘了替换报表之前先调用报表浏览器的Reset方法,将旧报表的设置清掉。
至于需求2,其实正是因为绑定源的存在,所以只需要操作数据实例即可。
至于需求3,我觉得其实可以将报表文件导出EXCEL文件给最终用户,毕竟在EXCEL中去调整会方便很多。另外,使用报表模型项目,将现成的报表生成器配合报表模型,最终用户也是可以自己设计报表的。使用程序更改报表定义文件的方法,工作量会大很多,只能实现有限的动态控制而已了。
需求四的套打,也存在这样的需求,像打印存折那样打印,也即是旧记录不打而只打新记录,我的思路是对要打印的行的颜色设置表达式,在提供的数据中包含一个字段控制是否已经打印,已经打印过的则让该行颜色为白色,这样旧记录既会占位,也不打印,即可只打印新的记录了。当然,使用控件的位置表达式,会更灵活,但编程就需要计算位置了。
相关参考:以下的URL包含一些打印报表中遇到的问题,可以在这些博客做些参考。http://www.cnblogs.com/dlwang2002/archive/2007/02/14/410499.html
http://blog.csdn.net/flygoldfish/archive/2005/12/16/554035.aspx
/article/4624799.html
http://blog.sina.com.cn/s/blog_4b0754cf010008e1.html
想做一个报表设计器的朋友,可以参考下速达的http://www.superdata.com.cn/down/Down_Tryout.aspx
其中的5000工业版和7000工业版都有打印样式设计的界面可以参考。
有这方面需求的朋友,不妨将你开发的经验分享下,或者在我的博客留下你的博客地址,大家互相进步。
想对Reporting Services有进一步了解的朋友也可以在这里提些问题,我能帮忙的都尽量帮,有好的资料可以在这里发布下,谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐