【原创】水晶报表动态表扩展 之 任意无关联表,任意列,任意数据源
本文是在<动态水晶报表:任意表,任意列,以及动态格线>
http://www.cnblogs.com/babyt/archive/2009/04/08/1431328.html
原理基础上的一个扩展。
如果你之前没有看过此文,请务必仔细研读。否则本文你可能不能较快地理解。
本文适用场景:
出于显示效果或者打印节约纸张等的需要,将多个不同结构(设置来源于不同数据源)的表在同一个报表中展现。
一般我们可以通过子报表来实现这个效果。
不过一般一个子报表对应一个表,这样对于多个表操作起来就比较麻烦。
每个表都要做一个子报表,对于动态取表(表数目,表名称)的要求也满足不了。
虽然也可以借助SDK,对不同的表,动态增加一个子报表,但是代码量很大。
基本思路:
既然我们延续上文的原理,那么本方案的主要问题就是,如何把这任意多的表,塞到同一个datatable 里去
1:
我们同样要构造一个datatable来容纳我们的表数据。假设我们的表的最大列数是6,
那么我们需要创建一个7个列的datatable。
为什么上文是6个,这里要7个呢?
多出来的的这个字段f0,我们用来放表的名称。这样来区分数据是来源于哪个表的。
这样我们就创建了f0,f1~f6,共7个String行的datatable.
2:
好了,我们来改造上一个例子,模板基本上一样。只是多了个字段f0。但是界面上这个f0是不显示的,所以我们仍然用6个格子。
需要注意的是,有点不同:就是页眉上不再显示标头了,为什么这样做,下面会讲到。
3:
然后,来改造我们的核心方法
每个表的数据在写入前,先写一行列标题。这个标题,也替代了我们之前的页眉标题。
并且每一行数据的第一列,也就是f0,写入表名。
1
class
clsDyCrystalReportCore
2
{
3
///
<summary>
4
///
将传入的datatable转换成报表模板所需要的datatable
5
///
数据全部转换为string
6
///
</summary>
7
///
<param name="dt">
来源表
</param>
8
///
<param name="tblName">
各单表名称
</param>
9
///
<param name="fldsName">
字段名称,以半角逗号分隔。
</param>
10
///
<returns>
报表模板所需要的datatable
</returns>
11
12
public
DataTable dtx(DataTable dt,String tblName,String fldsName)
13
{
14
15
String oneRow
=
""
;
16
DataSet1.BigTatableDataTable dtx1
=
new
DataSet1.BigTatableDataTable();
17
18
object
[] obj
=
new
object
[dt.Columns.Count];
19
//
特别注意:所选择的表的列的数目需<=Bigtable的字段数目
20
//
请自行填写保护代码
21
22
//
先列名称写到每个表的第一行
23
dtx1.Rows.Add(dtx1.NewRow());
24
//
第一行的第一列写表的名称
25
dtx1.Rows[
0
][
0
]
=
tblName;
26
//
切割列名称字符串,写入第一行后面的位置
27
for
(
int
i
=
0
; i
<
fldsName.Split(
new
char
[] {
'
,
'
}).Length; i
++
)
28
{
29
30
dtx1.Rows[
0
][i
+
1
]
=
fldsName.Split(
new
char
[] {
'
,
'
})[i];
31
}
32
33
//
写入数据
34
for
(
int
i
=
0
; i
<
dt.Rows.Count ; i
++
)
35
{
36
37
dtx1.Rows.Add(dtx1.NewRow());
38
//
每一行的第一列,也就是f0,写入表名称。
39
dtx1.Rows[i
+
1
][
0
]
=
tblName;
40
//
写数据
41
for
(
int
j
=
0
; j
<
dt.Columns.Count ; j
++
)
42
{
43
oneRow
=
oneRow
+
"
,
"
+
dt.Rows[i][j].ToString();
44
if
(dt.Rows[i][j].ToString()
==
""
)
45
dtx1.Rows[i
+
1
][j
+
1
]
=
"
"
;
46
else
47
dtx1.Rows[i
+
1
][j
+
1
]
=
dt.Rows[i][j].ToString();
48
}
49
50
}
51
return
dtx1;
52
}
53
}
4:
好了,来看我们的前端代码。
1
using
System;
2
using
System.Collections.Generic;
3
using
System.ComponentModel;
4
using
System.Data;
5
using
System.Text;
6
using
System.Windows.Forms;
7
using
CrystalDecisions.Shared;
8
using
CrystalDecisions.CrystalReports.Engine;
9
using
CrystalDecisions.Windows.Forms;
10
using
System.Data.OleDb;
11
namespace
DyCrystalReportDemo
12
{
13
public
partial
class
Form1 : Form
14
{
15
public
Form1()
16
{
17
InitializeComponent();
18
}
19
20
private
void
button1_Click(
object
sender, EventArgs e)
21
{
22
String connstr
=
"
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=
"
+
System.Threading.Thread.GetDomain().BaseDirectory
+
"
bbtcrall.mdb
"
+
"
;
"
;
23
24
//
打开数据库连接
25
OleDbConnection cn
=
new
OleDbConnection(connstr);
26
27
DataTable dtxAll
=
new
DataTable();
//
容纳所有数据
28
OleDbDataAdapter da
=
new
OleDbDataAdapter();
29
clsDyCrystalReportCore xCore
=
new
clsDyCrystalReportCore();
30
31
//
注意各表的字段数目不能大于我们设定的最大数目!
32
//
请自行添加错误保护和对象释放代码
33
34
//
第1个表
35
DataTable dt1
=
new
DataTable();
36
DataTable dtx1
=
new
DataTable();
37
da
=
new
OleDbDataAdapter(
"
SELECT * From Test1_1
"
, cn);
38
da.Fill(dt1);
39
dtx1
=
xCore.dtx(dt1,
"
表1
"
,
"
编号,姓名,发信日期,其他
"
);
40
dtxAll.Merge(dtx1);
41
42
43
//
第2个表,注意,这个表可以从不同的数据源获取!
44
//
重新初始化
45
dt1
=
new
DataTable();
46
dtx1
=
new
DataTable();
47
da
=
new
OleDbDataAdapter(
"
SELECT * From Test1_2
"
, cn);
48
da.Fill(dt1);
49
dtx1
=
xCore.dtx(dt1,
"
表2
"
,
"
编号,姓名,入职日期,日期1,日期2
"
);
50
dtxAll.Merge(dtx1);
51
52
53
//
第3个表,注意,这个表可以从不同的数据源获取!
54
//
重新初始化
55
dt1
=
new
DataTable();
56
dtx1
=
new
DataTable();
57
da
=
new
OleDbDataAdapter(
"
SELECT * From Test_4
"
, cn);
58
da.Fill(dt1);
59
dtx1
=
xCore.dtx(dt1,
"
表3
"
,
"
年份,地区,指标,最大值,最小值
"
);
60
dtxAll.Merge(dtx1);
61
62
63
ReportDocument myReport
=
new
ReportDocument();
64
string
reportPath
=
System.Threading.Thread.GetDomain().BaseDirectory
+
"
crystalreport1.rpt
"
;
65
myReport.Load(reportPath);
66
67
//
绑定数据集
68
69
myReport.SetDataSource(dtxAll);
70
71
crystalReportViewer1.ReportSource
=
myReport;
72
crystalReportViewer1.RefreshReport();
73
}
74
75
}
76
}
77
注意,我们用了
dtxAll.Merge(dtx1);
将所有的数据合并在一个datatable里,从而达到我们开始设定的目标。
5:
执行一下,是如下效果,有点乱,是吧?
6:
这个时候f0就派上用场啦,在模板上增加一个f0的组,如下图所示。
7:
运行起来,帅多了吧?
格子有点难看,这个就不再本文中讨论了。以后专门讲讲这个画格子的问题。