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

释放双眼,带上耳机,听听看~!
00:00
00:00

之前一直使用各种报表工具,如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>这样的数据源,不同的方式报表控件的代码绑定不同。

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

  1. /// <summary>
  2. /// 普通连接数据库的例子-打印预览
  3. /// </summary>
  4. private void btnNormalDatabase_Click(object sender, EventArgs e)
  5. {
  6. Report = new GridppReport();
  7. string reportPath = Path.Combine(Application.StartupPath, \"Reports\\\\testgrid++.grf\");
  8. string dbPath = Path.Combine(Application.StartupPath, \"Data\\\\NorthWind.mdb\");
  9. //从对应文件中载入报表模板数据
  10. Report.LoadFromFile(reportPath);
  11. //设置与数据源的连接串,因为在设计时指定的数据库路径是绝对路径。
  12. if (Report.DetailGrid != null)
  13. {
  14. string connstr = Utility.GetDatabaseConnectionString(dbPath);
  15. Report.DetailGrid.Recordset.ConnectionString = connstr;
  16. }
  17. Report.PrintPreview(true);
  18. }

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

  1. Report.FetchRecord += new _IGridppReportEvents_FetchRecordEventHandler(ReportFetchRecord);

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

  1. //在C#中一次填入一条记录不能成功,只能使用一次将记录全部填充完的方式
  2. private void ReportFetchRecord()
  3. {
  4. //将全部记录一次填入
  5. Report.DetailGrid.Recordset.Append();
  6. FillRecord1();
  7. Report.DetailGrid.Recordset.Post();
  8. Report.DetailGrid.Recordset.Append();
  9. FillRecord2();
  10. Report.DetailGrid.Recordset.Post();
  11. Report.DetailGrid.Recordset.Append();
  12. FillRecord3();
  13. Report.DetailGrid.Recordset.Post();
  14. }
  15. private void FillRecord1()
  16. {
  17. C1Field.AsString = \"A\";
  18. I1Field.AsInteger = 1;
  19. F1Field.AsFloat = 1.01;
  20. }
  21. private void FillRecord2()
  22. {
  23. C1Field.AsString = \"B\";
  24. I1Field.AsInteger = 2;
  25. F1Field.AsFloat = 1.02;
  26. }
  27. private void FillRecord3()
  28. {
  29. C1Field.AsString = \"C\";
  30. I1Field.AsInteger = 3;
  31. F1Field.AsFloat = 1.03;
  32. }

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

  1. /// <summary>
  2. /// 绑定实体类集合的例子-打印预览
  3. /// </summary>
  4. private void btnBindList_Click(object sender, EventArgs e)
  5. {
  6. Report = new GridppReport();
  7. //从对应文件中载入报表模板数据
  8. string reportPath = Path.Combine(Application.StartupPath, \"Reports\\\\testList.grf\");
  9. Report.LoadFromFile(reportPath);
  10. Report.FetchRecord += ReportList_FetchRecord;
  11. Report.PrintPreview(true);
  12. }
  13. /// <summary>
  14. /// 绑定DataTable的例子-打印预览
  15. /// </summary>
  16. private void btnBindDatatable_Click(object sender, EventArgs e)
  17. {
  18. Report = new GridppReport();
  19. //从对应文件中载入报表模板数据
  20. string reportPath = Path.Combine(Application.StartupPath, \"Reports\\\\testList.grf\");
  21. Report.LoadFromFile(reportPath);
  22. Report.FetchRecord += ReportList_FetchRecord2;
  23. Report.PrintPreview(true);
  24. }
  25. private void ReportList_FetchRecord()
  26. {
  27. List<ProductInfo> list = BLLFactory<Product>.Instance.GetAll();
  28. GridReportHelper.FillRecordToReport<ProductInfo>(Report, list);
  29. }
  30. private void ReportList_FetchRecord2()
  31. {
  32. var dataTable = BLLFactory<Product>.Instance.GetAllToDataTable();
  33. GridReportHelper.FillRecordToReport(Report, dataTable);
  34. }

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

  1. /// <summary>
  2. /// Gird++报表的辅助类
  3. /// </summary>
  4. public class GridReportHelper
  5. {
  6. private struct MatchFieldPairType
  7. {
  8. public IGRField grField;
  9. public int MatchColumnIndex;
  10. }
  11. /// <summary>
  12. /// 将 DataReader 的数据转储到 Grid++Report 的数据集中
  13. /// </summary>
  14. /// <param name=\"Report\">报表对象</param>
  15. /// <param name=\"dr\">DataReader对象</param>
  16. public static void FillRecordToReport(IGridppReport Report, IDataReader dr)
  17. {
  18. MatchFieldPairType[] MatchFieldPairs = new MatchFieldPairType[Math.Min(Report.DetailGrid.Recordset.Fields.Count, dr.FieldCount)];
  19. //根据字段名称与列名称进行匹配,建立DataReader字段与Grid++Report记录集的字段之间的对应关系
  20. int MatchFieldCount = 0;
  21. for (int i = 0; i < dr.FieldCount; ++i)
  22. {
  23. foreach (IGRField fld in Report.DetailGrid.Recordset.Fields)
  24. {
  25. if (string.Compare(fld.RunningDBField, dr.GetName(i), true) == 0)
  26. {
  27. MatchFieldPairs[MatchFieldCount].grField = fld;
  28. MatchFieldPairs[MatchFieldCount].MatchColumnIndex = i;
  29. ++MatchFieldCount;
  30. break;
  31. }
  32. }
  33. }
  34. // 将 DataReader 中的每一条记录转储到Grid++Report 的数据集中去
  35. while (dr.Read())
  36. {
  37. Report.DetailGrid.Recordset.Append();
  38. for (int i = 0; i < MatchFieldCount; ++i)
  39. {
  40. var columnIndex = MatchFieldPairs[i].MatchColumnIndex;
  41. if (!dr.IsDBNull(columnIndex))
  42. {
  43. MatchFieldPairs[i].grField.Value = dr.GetValue(columnIndex);
  44. }
  45. }
  46. Report.DetailGrid.Recordset.Post();
  47. }
  48. }
  49. /// <summary>
  50. /// 将 DataTable 的数据转储到 Grid++Report 的数据集中
  51. /// </summary>
  52. /// <param name=\"Report\">报表对象</param>
  53. /// <param name=\"dt\">DataTable对象</param>
  54. public static void FillRecordToReport(IGridppReport Report, DataTable dt)
  55. {
  56. MatchFieldPairType[] MatchFieldPairs = new MatchFieldPairType[Math.Min(Report.DetailGrid.Recordset.Fields.Count, dt.Columns.Count)];
  57. //根据字段名称与列名称进行匹配,建立DataReader字段与Grid++Report记录集的字段之间的对应关系
  58. int MatchFieldCount = 0;
  59. for (int i = 0; i < dt.Columns.Count; ++i)
  60. {
  61. foreach (IGRField fld in Report.DetailGrid.Recordset.Fields)
  62. {
  63. if (string.Compare(fld.Name, dt.Columns[i].ColumnName, true) == 0)
  64. {
  65. MatchFieldPairs[MatchFieldCount].grField = fld;
  66. MatchFieldPairs[MatchFieldCount].MatchColumnIndex = i;
  67. ++MatchFieldCount;
  68. break;
  69. }
  70. }
  71. }
  72. // 将 DataTable 中的每一条记录转储到 Grid++Report 的数据集中去
  73. foreach (DataRow dr in dt.Rows)
  74. {
  75. Report.DetailGrid.Recordset.Append();
  76. for (int i = 0; i < MatchFieldCount; ++i)
  77. {
  78. var columnIndex = MatchFieldPairs[i].MatchColumnIndex;
  79. if (!dr.IsNull(columnIndex))
  80. {
  81. MatchFieldPairs[i].grField.Value = dr[columnIndex];
  82. }
  83. }
  84. Report.DetailGrid.Recordset.Post();
  85. }
  86. }
  87. /// <summary>
  88. /// List加载数据集
  89. /// </summary>
  90. /// <typeparam name=\"T\"></typeparam>
  91. /// <param name=\"Report\">报表对象</param>
  92. /// <param name=\"list\">列表数据</param>
  93. public static void FillRecordToReport<T>(IGridppReport Report, List<T> list)
  94. {
  95. Type type = typeof(T); //反射类型
  96. MatchFieldPairType[] MatchFieldPairs = new MatchFieldPairType[Math.Min(Report.DetailGrid.Recordset.Fields.Count, type.GetProperties().Length)];
  97. //根据字段名称与列名称进行匹配,建立字段与Grid++Report记录集的字段之间的对应关系
  98. int MatchFieldCount = 0;
  99. int i = 0;
  100. MemberInfo[] members = type.GetMembers();
  101. foreach (MemberInfo memberInfo in members)
  102. {
  103. foreach (IGRField fld in Report.DetailGrid.Recordset.Fields)
  104. {
  105. if (string.Compare(fld.Name, memberInfo.Name, true) == 0)
  106. {
  107. MatchFieldPairs[MatchFieldCount].grField = fld;
  108. MatchFieldPairs[MatchFieldCount].MatchColumnIndex = i;
  109. ++MatchFieldCount;
  110. break;
  111. }
  112. }
  113. ++i;
  114. }
  115. // 将 DataTable 中的每一条记录转储到 Grid++Report 的数据集中去
  116. foreach (T t in list)
  117. {
  118. Report.DetailGrid.Recordset.Append();
  119. for (i = 0; i < MatchFieldCount; ++i)
  120. {
  121. object objValue = GetPropertyValue(t, MatchFieldPairs[i].grField.Name);
  122. if (objValue != null)
  123. {
  124. MatchFieldPairs[i].grField.Value = objValue;
  125. }
  126. }
  127. Report.DetailGrid.Recordset.Post();
  128. }
  129. }
  130. /// <summary>
  131. /// 获取对象实例的属性值
  132. /// </summary>
  133. /// <param name=\"obj\">对象实例</param>
  134. /// <param name=\"name\">属性名称</param>
  135. /// <returns></returns>
  136. public static object GetPropertyValue(object obj, string name)
  137. {
  138. //这个无法获取基类
  139. //PropertyInfo fieldInfo = obj.GetType().GetProperty(name, bf);
  140. //return fieldInfo.GetValue(obj, null);
  141. //下面方法可以获取基类属性
  142. object result = null;
  143. foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj))
  144. {
  145. if (prop.Name == name)
  146. {
  147. result = prop.GetValue(obj);
  148. }
  149. }
  150. return result;
  151. }
  152. }

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

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

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

  1. private void btnExportPdf_Click(object sender, EventArgs e)
  2. {
  3. List<ProductInfo> list = BLLFactory<Product>.Instance.GetAll();
  4. //从对应文件中载入报表模板数据
  5. string reportPath = Path.Combine(Application.StartupPath, \"Reports\\\\testList.grf\");
  6. GridExportHelper helper = new GridExportHelper(reportPath);
  7. string fileName = \"d:\\\\my.pdf\";
  8. var succeeded = helper.ExportPdf(list, fileName);
  9. if(succeeded)
  10. {
  11. Process.Start(fileName);
  12. }
  13. }

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

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

点点赞赏,手留余香

给TA打赏
共0人
还没有人赞赏,快来当第一个赞赏的人吧!
    站长资讯

    基于keepalived搭建MySQL热机集群

    2020-11-9 3:45:41

    站长资讯

    李宏毅机器学习笔记2:Gradient Descent(附带详细的原理推导过程)

    2020-11-9 3:45:43

    0 条回复 A文章作者 M管理员
    欢迎您,新朋友,感谢参与互动!
      暂无讨论,说说你的看法吧
    个人中心
    购物车
    优惠劵
    今日签到
    私信列表
    搜索