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

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

一、报表模板设计

这个报表系统,报表模板提供了不少案例,咱们能够大概浏览下其功能。工具

它对应在相应的文件目录里面,咱们能够逐一查看了解下,感受提供这么多报表仍是很赞的,咱们能够参考着来用,很是好。测试

整个报表主要是基于现有数据进行一个报表的模板设计的,若是要预览效果,咱们通常是须要绑定现有的数据,能够从各类数据库提供数据源,而后设计报表模板,进行实时的数据和格式查看及调整。spa

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

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

为了动态的加入咱们表格所须要的列,咱们能够经过数据库里面的字段进行加入,首先提供数据源,指定咱们具体的表便可(若是是自定义的信息,则能够手工添加字段)code

这个里面就是配置不一样的数据库数据源了orm

如SQLServer数据库的配置信息以下。对象

为了方便,咱们能够利用案例的Access数据库,也就是Northwind.mdb来测试咱们的报表,弄好这些咱们指定对应的数据表数据便可。blog

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

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

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

预览报表,咱们就能够看到具体的报表格式显示了。

 

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

 

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

 

二、数据绑定

通常咱们绑定数据源,有的时候能够直接指定数据库链接,有时候能够绑定具体的数据列表,如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;
        }
    }

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

导出报表为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);
            }
        }

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

相关文章
相关标签/搜索