需求如下
:
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
替换旧的报表浏览器
这不是本文的要点,好了
.
先撇开这个不谈
,
我们知道
,
报表浏览器的工作原理是这样的
。
·
数据源
可以是传统数据库,也可以是XML表格,当然,也可以是自定义的对象
Data Adapter 及 Connection 等
用来连接传统的数据库
DataSet
用来存储数据,同时可以直接操作XML文件
BindingSource
利用DateSet来填充BindingSource,这一步数据中转逻辑上有点多余,但是必不可少
ReportDataSource
利用BindingSource来填充ReportDataSource,......-_-!!
ReportViewer
利用ReportDataSource填充的 数据 及 指定给它的RDLC报表文件来显示报表
好了,了解了上面的原理后,我们就可以开始让我们的报表浏览器工作起来了。
报表浏览器
---
指定报表定义文件和报表定义文件所绑定的数据源
,
(数据源可以是数据集或者自定义对象
,
)
(
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()
‘假如你从一个下拉框中选择新的报表定义文件后就执行这句代码,可以将报表浏览器的配置清空,然后重新配置报表浏览器呈现新的报表,代码如下。
Me
.ReportViewer1.LocalReport.ReportEmbeddedResource = "rpDemo.
NewReport
.rdlc"
‘
注意,这里指定新的报表定义文件了
Dim reportds As New Microsoft.Reporting.WinForms.ReportDataSource("rpDemo_demo2", bdds)
‘这里的两个参数也变了。因为要显示新的报表,就重新指定了新的报表定义文件,报表定义文件变了,所以第一个参数指定的报表数据源当然也跟着变了。而第二个参数指定的是绑定源,我们不需要更改,只是提供给绑定源的数据实例要变而已。demo2list而不再是demolist
bdds.DataSource = New demo2list
Me.ReportViewer1.LocalReport.DataSources.Add(reportds)
Me.ReportViewer1.RefreshReport()
2
如何更改报表的数据源
更改数据的方法也很简单,由于我们使用了绑定源对象,所以对于数据源的更改,报表浏览器是不需要理会的,这就是绑定源的好处了。绑定源对报表数据源负责。
ds.Add(New demo("xyz", "asd", "ddd"))
‘往我们的demolist集合中插入一个对象
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
http://www.cnblogs.com/waxdoll/archive/2006/03/04/342910.html
http://blog.sina.com.cn/s/blog_4b0754cf010008e1.html
想做一个报表设计器的朋友,可以参考下速达的http://www.superdata.com.cn/down/Down_Tryout.aspx
其中的5000工业版和7000工业版都有打印样式设计的界面可以参考。
有这方面需求的朋友,不妨将你开发的经验分享下,或者在我的博客留下你的博客地址,大家互相进步。
想对Reporting Services有进一步了解的朋友也可以在这里提些问题,我能帮忙的都尽量帮,有好的资料可以在这里发布下,谢谢!