欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

在Winform开发中使用Grid++报表

程序员文章站 2022-07-11 09:40:19
之前一直使用各种报表工具,如RDLC、DevExpress套件的XtraReport报表,在之前一些随笔也有介绍,最近接触锐浪的Grid++报表,做了一些测试例子和辅助类来处理报表内容,觉得还是很不错的,特别是它的作者提供了很多报表的设计模板案例,功能还是非常强大的。试着用来做一些简单的报表,测试下... ......

之前一直使用各种报表工具,如rdlc、devexpress套件的xtrareport报表,在之前一些随笔也有介绍,最近接触锐浪的grid++报表,做了一些测试例子和辅助类来处理报表内容,觉得还是很不错的,特别是它的作者提供了很多报表的设计模板案例,功能还是非常强大的。试着用来做一些简单的报表,测试下功能,发现常规的二维表、套打、条形码二维码等我关注的功能都有,是一个比较强大的报表控件,本篇随笔主要介绍在winform开发中使用grid++报表设计报表模板,以及绑定数据的处理过程。

1、报表模板设计

这个报表系统,报表模板提供了很多案例,我们可以大概浏览下其功能。

在Winform开发中使用Grid++报表

它对应在相应的文件目录里面,我们可以逐一查看了解下,感觉提供这么多报表还是很赞的,我们可以参考着来用,非常好。

在Winform开发中使用Grid++报表

整个报表主要是基于现有数据进行一个报表的模板设计的,如果要预览效果,我们一般是需要绑定现有的数据,可以从各种数据库提供数据源,然后设计报表模板,进行实时的数据和格式查看及调整。

空白的报表模板大概如下所示,包含页眉页脚,以及明细表格的内容。

在Winform开发中使用Grid++报表

根据它的教程,模仿着简单的做了一个报表,也主要是设计报表格式的调整,和数据源的处理的关系,我们做一个两个报表就可以很快上手了。

为了动态的加入我们表格所需要的列,我们可以通过数据库里面的字段进行加入,首先提供数据源,指定我们具体的表即可(如果是自定义的信息,则可以手工添加字段)

在Winform开发中使用Grid++报表

这个里面就是配置不同的数据库数据源了

在Winform开发中使用Grid++报表

如sqlserver数据库的配置信息如下。

在Winform开发中使用Grid++报表

为了方便,我们可以利用案例的access数据库,也就是northwind.mdb来测试我们的报表,弄好这些我们指定对应的数据表数据即可。

在Winform开发中使用Grid++报表

这里面配置好数据库表信息后,我们就可以用它生成相关的字段和对应的列信息了

在Winform开发中使用Grid++报表

修改列的表头,让它符合中文的表头列,如下所示。

在Winform开发中使用Grid++报表

我们在页脚出,加入了打印时间,页码的一些系统变量,具体操作就是添加一个综合文本,然后在内容里面插入指定的域内容即可,如下所示

在Winform开发中使用Grid++报表

预览报表,我们就可以看到具体的报表格式显示了。

 在Winform开发中使用Grid++报表

通过上面的操作,感觉生成一个报表还是很方便的,接着我有根据需要做了一个二维码的报表显示,方便打印资产标签。

 在Winform开发中使用Grid++报表

绑定数据源显示的报表视图如下所示,看起来还是蛮好的。

在Winform开发中使用Grid++报表

 

2、数据绑定

一般我们绑定数据源,有的时候可以直接指定数据库连接,有时候可以绑定具体的数据列表,如datatable或者list<t>这样的数据源,不同的方式报表控件的代码绑定不同。

直接绑定数据表的路径如下所示。

        /// <summary>
        /// 普通连接数据库的例子-打印预览
        /// </summary>
        private void btnnormaldatabase_click(object sender, eventargs e)
        {
            report = new gridppreport();
            string reportpath = path.combine(application.startuppath, "reports\\testgrid++.grf");
            string dbpath = path.combine(application.startuppath, "data\\northwind.mdb");

            //从对应文件中载入报表模板数据
            report.loadfromfile(reportpath);
            //设置与数据源的连接串,因为在设计时指定的数据库路径是绝对路径。
            if (report.detailgrid != null)
            {
                string connstr = utility.getdatabaseconnectionstring(dbpath);
                report.detailgrid.recordset.connectionstring = connstr;
            }

            report.printpreview(true);
        }

而如果需要绑定和数据库无关的动态数据源,那么就需要通过控件的fetchrecord进行处理了,如下代码所示。

report.fetchrecord += new _igridppreportevents_fetchrecordeventhandler(reportfetchrecord);

通过这样我们增加每一个对应的列单元格信息,如下是随带案例所示

        //在c#中一次填入一条记录不能成功,只能使用一次将记录全部填充完的方式
        private void reportfetchrecord()
        {
            //将全部记录一次填入
            report.detailgrid.recordset.append();
            fillrecord1();
            report.detailgrid.recordset.post();

            report.detailgrid.recordset.append();
            fillrecord2();
            report.detailgrid.recordset.post();

            report.detailgrid.recordset.append();
            fillrecord3();
            report.detailgrid.recordset.post();
        }

        private void fillrecord1()
        {
            c1field.asstring = "a";
            i1field.asinteger = 1;
            f1field.asfloat = 1.01;
        }

        private void fillrecord2()
        {
            c1field.asstring = "b";
            i1field.asinteger = 2;
            f1field.asfloat = 1.02;
        }

        private void fillrecord3()
        {
            c1field.asstring = "c";
            i1field.asinteger = 3;
            f1field.asfloat = 1.03;
        }

这样处理肯定很麻烦,我们常规做法是弄一个辅助类,来处理datatable和list<t>等这样类型数据的动态增加操作。

        /// <summary>
        /// 绑定实体类集合的例子-打印预览
        /// </summary>
        private void btnbindlist_click(object sender, eventargs e)
        {
            report = new gridppreport();
            //从对应文件中载入报表模板数据
            string reportpath = path.combine(application.startuppath, "reports\\testlist.grf");
            report.loadfromfile(reportpath);
            report.fetchrecord += reportlist_fetchrecord;

            report.printpreview(true);
        }
        /// <summary>
        /// 绑定datatable的例子-打印预览
        /// </summary>
        private void btnbinddatatable_click(object sender, eventargs e)
        {
            report = new gridppreport();
            //从对应文件中载入报表模板数据
            string reportpath = path.combine(application.startuppath, "reports\\testlist.grf");
            report.loadfromfile(reportpath);
            report.fetchrecord += reportlist_fetchrecord2;

            report.printpreview(true);
        }

        private void reportlist_fetchrecord()
        {
            list<productinfo> list = bllfactory<product>.instance.getall();
            gridreporthelper.fillrecordtoreport<productinfo>(report, list);
        }
        private void reportlist_fetchrecord2()
        {
            var datatable = bllfactory<product>.instance.getalltodatatable();
            gridreporthelper.fillrecordtoreport(report, datatable);
        }

其中辅助类 gridreporthelper 代码如下所示。

    /// <summary>
    /// gird++报表的辅助类
    /// </summary>
    public class gridreporthelper
    {
        private struct matchfieldpairtype
        {
            public igrfield grfield;
            public int matchcolumnindex;
        }

        /// <summary>
        /// 将 datareader 的数据转储到 grid++report 的数据集中
        /// </summary>
        /// <param name="report">报表对象</param>
        /// <param name="dr">datareader对象</param>
        public static void fillrecordtoreport(igridppreport report, idatareader dr)
        {
            matchfieldpairtype[] matchfieldpairs = new matchfieldpairtype[math.min(report.detailgrid.recordset.fields.count, dr.fieldcount)];

            //根据字段名称与列名称进行匹配,建立datareader字段与grid++report记录集的字段之间的对应关系
            int matchfieldcount = 0;
            for (int i = 0; i < dr.fieldcount; ++i)
            {
                foreach (igrfield fld in report.detailgrid.recordset.fields)
                {
                    if (string.compare(fld.runningdbfield, dr.getname(i), true) == 0)
                    {
                        matchfieldpairs[matchfieldcount].grfield = fld;
                        matchfieldpairs[matchfieldcount].matchcolumnindex = i;
                        ++matchfieldcount;
                        break;
                    }
                }
            }

            // 将 datareader 中的每一条记录转储到grid++report 的数据集中去
            while (dr.read())
            {
                report.detailgrid.recordset.append();
                for (int i = 0; i < matchfieldcount; ++i)
                {
                    var columnindex = matchfieldpairs[i].matchcolumnindex;
                    if (!dr.isdbnull(columnindex))
                    {
                        matchfieldpairs[i].grfield.value = dr.getvalue(columnindex);
                    }
                }
                report.detailgrid.recordset.post();
            }
        }

        /// <summary>
        /// 将 datatable 的数据转储到 grid++report 的数据集中
        /// </summary>
        /// <param name="report">报表对象</param>
        /// <param name="dt">datatable对象</param>
        public static void fillrecordtoreport(igridppreport report, datatable dt)
        {
            matchfieldpairtype[] matchfieldpairs = new matchfieldpairtype[math.min(report.detailgrid.recordset.fields.count, dt.columns.count)];

            //根据字段名称与列名称进行匹配,建立datareader字段与grid++report记录集的字段之间的对应关系
            int matchfieldcount = 0;
            for (int i = 0; i < dt.columns.count; ++i)
            {
                foreach (igrfield fld in report.detailgrid.recordset.fields)
                {
                    if (string.compare(fld.name, dt.columns[i].columnname, true) == 0)
                    {
                        matchfieldpairs[matchfieldcount].grfield = fld;
                        matchfieldpairs[matchfieldcount].matchcolumnindex = i;
                        ++matchfieldcount;
                        break;
                    }
                }
            }

            // 将 datatable 中的每一条记录转储到 grid++report 的数据集中去
            foreach (datarow dr in dt.rows)
            {
                report.detailgrid.recordset.append();
                for (int i = 0; i < matchfieldcount; ++i)
                {
                    var columnindex = matchfieldpairs[i].matchcolumnindex;
                    if (!dr.isnull(columnindex))
                    {
                        matchfieldpairs[i].grfield.value = dr[columnindex];
                    }
                }
                report.detailgrid.recordset.post();
            }
        }

        /// <summary>
        /// list加载数据集
        /// </summary>
        /// <typeparam name="t"></typeparam>
        /// <param name="report">报表对象</param>
        /// <param name="list">列表数据</param>
        public static void fillrecordtoreport<t>(igridppreport report, list<t> list)
        {
            type type = typeof(t);  //反射类型             

            matchfieldpairtype[] matchfieldpairs = new matchfieldpairtype[math.min(report.detailgrid.recordset.fields.count, type.getproperties().length)];

            //根据字段名称与列名称进行匹配,建立字段与grid++report记录集的字段之间的对应关系
            int matchfieldcount = 0;
            int i = 0;
            memberinfo[] members = type.getmembers();
            foreach (memberinfo memberinfo in members)
            {
                foreach (igrfield fld in report.detailgrid.recordset.fields)
                {
                    if (string.compare(fld.name, memberinfo.name, true) == 0)
                    {
                        matchfieldpairs[matchfieldcount].grfield = fld;
                        matchfieldpairs[matchfieldcount].matchcolumnindex = i;
                        ++matchfieldcount;
                        break;
                    }
                }
                ++i;
            }
            
            // 将 datatable 中的每一条记录转储到 grid++report 的数据集中去
            foreach (t t in list)
            {
                report.detailgrid.recordset.append();
                for (i = 0; i < matchfieldcount; ++i)
                {
                    object objvalue = getpropertyvalue(t, matchfieldpairs[i].grfield.name);
                    if (objvalue != null)
                    {
                        matchfieldpairs[i].grfield.value = objvalue;
                    }
                }
                report.detailgrid.recordset.post();
            }
        }

        /// <summary>
        /// 获取对象实例的属性值
        /// </summary>
        /// <param name="obj">对象实例</param>
        /// <param name="name">属性名称</param>
        /// <returns></returns>
        public static object getpropertyvalue(object obj, string name)
        {
            //这个无法获取基类
            //propertyinfo fieldinfo = obj.gettype().getproperty(name, bf);
            //return fieldinfo.getvalue(obj, null);

            //下面方法可以获取基类属性
            object result = null;
            foreach (propertydescriptor prop in typedescriptor.getproperties(obj))
            {
                if (prop.name == name)
                {
                    result = prop.getvalue(obj);
                }
            }
            return result;
        }
    }

绑定数据的报表效果如下所示 

在Winform开发中使用Grid++报表

导出报表为pdf也是比较常规的操作,这个报表控件也可以实现pdf等格式文件的导出,如下所示。

        private void btnexportpdf_click(object sender, eventargs e)
        {
            list<productinfo> list = bllfactory<product>.instance.getall();

            //从对应文件中载入报表模板数据
            string reportpath = path.combine(application.startuppath, "reports\\testlist.grf");
            gridexporthelper helper = new gridexporthelper(reportpath);

            string filename = "d:\\my.pdf";
            var succeeded = helper.exportpdf(list, filename);
            if(succeeded)
            {
                process.start(filename);
            }
        }

在Winform开发中使用Grid++报表

以上就是利用这个报表控件做的一些功能测试和辅助类封装,方便使用。