读书人

水晶报表动态表扩展 之 任意无关联表

发布时间: 2012-01-20 18:53:53 作者: rapoo

【原创】水晶报表动态表扩展 之 任意无关联表,任意列,任意数据源
本文是在<动态水晶报表:任意表,任意列,以及动态格线>
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,写入表名。

C# code
 class clsDyCrystalReportCore    {        /// <summary>        /// 将传入的datatable转换成报表模板所需要的datatable        /// 数据全部转换为string        /// </summary>        /// <param name="dt">来源表</param>        /// <param name="tblName">各单表名称</param>        /// <param name="fldsName">字段名称,以半角逗号分隔。</param>        /// <returns>报表模板所需要的datatable</returns>        public DataTable dtx(DataTable dt,String tblName,String fldsName)        {            String oneRow="";            DataSet1.BigTatableDataTable dtx1 = new DataSet1.BigTatableDataTable();                        object[] obj = new object[dt.Columns.Count];           //特别注意:所选择的表的列的数目需<=Bigtable的字段数目            //请自行填写保护代码            //先列名称写到每个表的第一行            dtx1.Rows.Add(dtx1.NewRow());            //第一行的第一列写表的名称            dtx1.Rows[0][0] = tblName;            //切割列名称字符串,写入第一行后面的位置            for (int i = 0; i < fldsName.Split(new char[] { ',' }).Length; i++)            {                                dtx1.Rows[0][i+1] = fldsName.Split(new char[] {','})[i];            }            //写入数据            for (int i = 0; i <dt.Rows.Count ; i++)            {                dtx1.Rows.Add(dtx1.NewRow());                //每一行的第一列,也就是f0,写入表名称。                dtx1.Rows[i+1][0] = tblName;                 //写数据                for (int j = 0; j < dt.Columns.Count ; j++)                {                    oneRow = oneRow + "," + dt.Rows[i][j].ToString();                    if (dt.Rows[i][j].ToString()=="" )                        dtx1.Rows[i+1][j+1] = " ";                     else                    dtx1.Rows[i+1][j+1] = dt.Rows[i][j].ToString();                   }                           }            return dtx1;        }    }



4:
好了,来看我们的前端代码。

C# code
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Text;using System.Windows.Forms;using CrystalDecisions.Shared;using CrystalDecisions.CrystalReports.Engine;using CrystalDecisions.Windows.Forms;using System.Data.OleDb;namespace DyCrystalReportDemo{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        private void button1_Click(object sender, EventArgs e)        {             String connstr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + System.Threading.Thread.GetDomain().BaseDirectory+ "bbtcrall.mdb" + ";";                        //打开数据库连接             OleDbConnection cn = new OleDbConnection(connstr);                        DataTable dtxAll = new DataTable(); //容纳所有数据            OleDbDataAdapter da = new OleDbDataAdapter();            clsDyCrystalReportCore xCore = new clsDyCrystalReportCore();                        //注意各表的字段数目不能大于我们设定的最大数目!            //请自行添加错误保护和对象释放代码            //第1个表            DataTable dt1 = new DataTable();            DataTable dtx1 = new DataTable();               da = new OleDbDataAdapter("SELECT * From Test1_1", cn);            da.Fill(dt1);            dtx1 = xCore.dtx(dt1,"表1","编号,姓名,发信日期,其他");            dtxAll.Merge(dtx1);            //第2个表,注意,这个表可以从不同的数据源获取!            //重新初始化            dt1 = new DataTable();            dtx1 = new DataTable();            da = new OleDbDataAdapter("SELECT * From Test1_2", cn);            da.Fill(dt1);            dtx1 = xCore.dtx(dt1, "表2", "编号,姓名,入职日期,日期1,日期2");            dtxAll.Merge(dtx1);                       //第3个表,注意,这个表可以从不同的数据源获取!            //重新初始化            dt1 = new DataTable();            dtx1 = new DataTable();            da = new OleDbDataAdapter("SELECT * From Test_4", cn);            da.Fill(dt1);            dtx1 = xCore.dtx(dt1, "表3", "年份,地区,指标,最大值,最小值");            dtxAll.Merge(dtx1);                        ReportDocument myReport = new ReportDocument();            string reportPath = System.Threading.Thread.GetDomain().BaseDirectory + "crystalreport1.rpt";            myReport.Load(reportPath);            //绑定数据集            myReport.SetDataSource(dtxAll);                       crystalReportViewer1.ReportSource = myReport;            crystalReportViewer1.RefreshReport();        }    }} 




注意,我们用了

dtxAll.Merge(dtx1);

将所有的数据合并在一个datatable里,从而达到我们开始设定的目标。
5:
执行一下,是如下效果,有点乱,是吧?

6:
这个时候f0就派上用场啦,在模板上增加一个f0的组,如下图所示。

 

7:
运行起来,帅多了吧?



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


[解决办法]
学习了
[解决办法]
非常感谢,谢谢
[解决办法]
thanks, xuexi
[解决办法]
学习
[解决办法]
UP..!你真是国家栋梁.
[解决办法]
jf
[解决办法]

[解决办法]
收藏了先
[解决办法]
dingdingding
[解决办法]
学习
[解决办法]
支持阿泰
学习
[解决办法]
up
[解决办法]
学习
[解决办法]
一个列包含不同类型的数据,格式化,显示或者导出很容易出问题吧
[解决办法]
收藏了,学习
[解决办法]
MARK
[解决办法]
ding
[解决办法]
学习了
[解决办法]
mark
[解决办法]
GOOD

[解决办法]
收藏了,阿泰总是给大家惊喜的,好东西
[解决办法]
b 错,支持一下
[解决办法]

[解决办法]
学习中,感谢。
[解决办法]
值得学习!
[解决办法]
用分砸死我吧
[解决办法]
好文共赏...
[解决办法]
好东西,对于水晶报表方面我一向觉得自己很浅薄。。。呵呵学习了
[解决办法]
学习!
[解决办法]
好贴,学习
[解决办法]
感谢,收藏
[解决办法]
up
------解决方案--------------------


学习了,非常感谢
[解决办法]
欣赏
[解决办法]
可借鉴一下.
[解决办法]
非常感谢!!
[解决办法]
啊泰,太佩服你了
[解决办法]
不错学习了。
[解决办法]
好全面……辛苦了 学习!
[解决办法]
值得收藏的贴子..
[解决办法]
UP
[解决办法]
真是学习了
[解决办法]
谢谢,收藏了,虽然我现在还不能很理解......
[解决办法]
学习

[解决办法]
留名

读书人网 >.NET

热点推荐