动态水晶报表扩展:任意无关联多表,任意列,任意数据源

【原创】水晶报表动态表扩展 之 任意无关联表,任意列,任意数据源

本文是在<动态水晶报表:任意表,任意列,以及动态格线>
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:

运行起来,帅多了吧?


格子有点难看,这个就不再本文中讨论了。以后专门讲讲这个画格子的问题。

 

   

你可能感兴趣的:(数据源)