天天看点

对于使用RDLC报表实现相关报表需求的总结

最近公司需要在Winform程序中做一个报表打印模板,于是选择了微软的RDLC插件实现报表需求。

话不多说,先上结果。

对于使用RDLC报表实现相关报表需求的总结
对于使用RDLC报表实现相关报表需求的总结

一、报表的组成部分

该报表由两部分组成,同时用到了两个表格,第一个表格中的信息为主表中的数据。第二个表中的信息为明细表中的数据

第一部分:

对于使用RDLC报表实现相关报表需求的总结

第二部分:

对于使用RDLC报表实现相关报表需求的总结

第二部分又是由四个表格组成,由于个人能力有限,在一个表格中实现如结果所示的模板布局要求实在没办法实现,于是我就采取了四个表格去分别实现这些需求,能在一个表里实现的我尽量都在一个表里实现了。然后调整这四个表之间的边距,使他们拼到一起,展示时给人的感觉就像是整体一个表,其实是个合成表,哈哈~这里我是取了个巧。

第一个表:

对于使用RDLC报表实现相关报表需求的总结

第二个表:

对于使用RDLC报表实现相关报表需求的总结

第三个表:

对于使用RDLC报表实现相关报表需求的总结

其实第三个表是这样子的

对于使用RDLC报表实现相关报表需求的总结

我把第二列的列宽拉到很小,为的是将这个三个表拼接到一起打印预览时能显示在一张A4纸上,不然

会有单独一列在另外一张A4纸上显示,其他部分均是空白。同时第二列设置为展示时隐藏,肯定有人要问既然第二列没用,不需要展示,在设计表格时还占用空间,那为什么不把这列删掉呢?我也想删啊,可是它不让我删,当我尝试删除时,它就会报下面的错:

对于使用RDLC报表实现相关报表需求的总结

虽然tablix包含两列,但最左边那个是分组列,最右边那个是正文列。rdlc报表中Tablix中必须包含一列正文列,因此是删不掉的!

第四个表:

对于使用RDLC报表实现相关报表需求的总结

这里就是一个单行tablix然后合并单元格拉伸它的长和宽后就实现了上图的显示效果。

二、报表的数据集

这个RDLC的数据集有两个–分别为DataSet1和DataSet3:

对于使用RDLC报表实现相关报表需求的总结

它们都位于DataSet1.xsd文件中,DataSet1为DataSet1.xsd中的一个DataTable,只是它的名字为DataSet1,它是通过TableAdapter配置即在DataSet1.xsd文件通过SQL语句连接SQL Server数据库中的表而形成的,其实这个并不是RDLC文件的数据源,只是我比较懒,不想手动添加DataTable,然后自己再加入这些字段,那样太烦了。通过配置数据集的方法我可以快速获得我想要的这些字段,它们必须与数据库中的字段完全一致。改报表文件的数据源有两个,即一个报表文件中可以有多个数据源,但一个tablix表中只允许有一个数据源。DataSet3为DataSet1.xsd中的一个DataTable,它是手动添加的,不连接后台数据库,只有两个字段,要声明这两个字段的数据类型为Decimal。这两个DataTable建好以后,在ReportViewer控件所在的窗体文件中通过ADO.NET代码动态绑定数据到报表文件中。报表文件中的数据源的绑定方法都采用这种方法。

代码如下

private void FrmPrintReport_Load(object sender, EventArgs e)
        {
            //string dt = DateTime.Now.ToString("MMMM.dd,yyyy", CultureInfo.CreateSpecificCulture("en-US"));

            // TODO: 这行代码将数据加载到表“DataSet1.Packing_List_Detail”中。您可以根据需要移动或删除它。
            //Packing_List_DetailTableAdapter.Fill(DataSet1.Packing_List_Detail);
            ReportDataSource rds1 = new ReportDataSource
            {
                Name = "DataSet1",
                Value = GetData1()
            };
            ReportDataSource rds2 = new ReportDataSource
            {
                Name = "DataSet3",
                Value = GetData2()
            };
            rpv.SetDisplayMode(DisplayMode.PrintLayout);
            rpv.LocalReport.ReportPath = @"..\..\ForeignTradeReport.rdlc";
            rpv.LocalReport.DataSources.Clear();
            rpv.LocalReport.DataSources.Add(rds1);
            rpv.LocalReport.DataSources.Add(rds2);
            rpv.RefreshReport();
        }
           

注意:你的rdlc文件中添加了几个数据集,你的后台代码中就要绑定几个数据源,哪怕你用不到这个数据集以及数据源,否则运行时会报错!

三、报表各个部分的具体实现方法

  1. 第一部分

报表的第一部分只有一个表格,只要将数据集中的相关字段绑定到单元格中就可以了。纵向合并单元格的布局用到了分组的方法,分组依据选什么都可以。在内容单元格而不是表头单元格内选择新建行组。

  1. 第二部分

    ①第一个表:

    对于使用RDLC报表实现相关报表需求的总结

    这个表中的分组名为NosAndKindsOfPKGS,分组方式为

    Fields!NosAndKindsOfPKGS.Value。NosAndKindsOfPKGS在数据库中代表的含义为箱号,从1开始编号,一个箱号可能对应多个多行数据,但是他们都是同一箱里的且只有一箱,如果要实现如结果图所示的效果,分组列中的数据单元格内的表达式为First(Fields!NosAndKindsOfPKGS.Value, “DataSet1”)而不是Fields!NosAndKindsOfPKGS.Value,否则展示效果就为下图所示了。

    对于使用RDLC报表实现相关报表需求的总结

    本报表设计的第二个难点为在分组列左侧展示序号列,即实现上图中最左侧序号列的展示效果,我尝试了很多办法都没办法在一个表中实现,只能在NosAndKindsOfPKGS组右侧某列实现,但这个需求不是领导想要的。在tablix表中添加行父组后,默认置于首列,而且不能随意调动该分组列的位置,只能固定显示在添加时该列自动放置的位置。

    于是只能新建第二个表,并将此表与第一个表拼起来。即可实现在合成表的最左侧显示序号列。

    ②第二个表

    第二个表的行号的实现我并没有用RowNumber(Nothing)的方法去实现,而是在后台通过SQL 语句配置数据源时直接通过SqlServer的RowNumber()函数,关键语句为ROW_NUMBER() OVER(ORDER BY CY_MKT_PackingDetail.AutoID) AS RowNo,再rdlc文件的数据集DataSet1中添加RowNo字段即可,数据类型为int。然后将该字段直接绑定到内容单元格内。

    ③第三个表

    对于使用RDLC报表实现相关报表需求的总结

    该表的分组的组名为Measures,分组方式为NosAndKindsOfPKGS,即还是按照箱号分组,Measures表示的是一个箱子的容积大小,一个箱号对应多条数据,他们都在同一箱里,因此在为同一箱号的组中的第一条数据的measures字段记录箱子的容积,同一组中的其他行数据的measures字段为0.000。

    在数据库中同一装箱单下的明细表的信息为

    对于使用RDLC报表实现相关报表需求的总结

    分组中内容单元格绑定的值的表达式为:First(Fields!Measures.Value, “DataSet1”)

    右击内容单元格,选择添加总计,选择晚于,单元格内绑定的值的表达式为=SUM(Decimal.Parse(Fields!Measures.Value), “DataSet1”)

    因为DataSet1作为第三个表的数据集时,其中的Measures字段为string类型的,和数据库中的measures字段的数据类型一致,数据库中为varchar类型。

    ④第四个表

    对于使用RDLC报表实现相关报表需求的总结
    这个表的数据集为DataSet3,在ReportViewer所在窗体内.cs文件中书写ADO.NET代码为其配置数据源。关键代码如下:
public DataTable GetData2()
        {
            string sqlStr = @"SELECT  SUM([GrossWeight]) as G_W, SUM(CAST([Measures] AS decimal(5,3))) AS Meas FROM CY_MKT_PackingDetail WHERE  MainID='" + AutoID+"'";
            DataTable dataTable = SqlServerHelper.GetDataTable(sqlStr);
            return dataTable;
        }
           

RDLC报表的内置函数中有一个CountDistinct()函数,用于返回指定表达式中的所有非重复值的计数。在计算总箱数时正好用到了这个函数。

最后陈述:这个报表模板的设计我前前后后大概花了有二十天的时间去实现,包括前期的对RDLC报表的学习,通过这个需求我也只是学到了rdlc报表的一点皮毛,以后可能还会再用到,到时候希望自己能够加深对它的了解,此篇博文也为我以后利用rdlc报表实现相关需求做铺垫!