发布时间:2026/8/21 14:37:33
WinForm应用实战开发指南 - 如何在开发中使用Grid++报表 之前一直使用各种报表工具如RDLC、DevExpress套件的XtraReport报表在之前一些文章中也有介绍最近接触锐浪的Grid报表做了一些测试例子和辅助类来处理报表内容觉得还是很不错的特别是它的作者提供了很多报表的设计模板案例功能还是非常强大的。试着用来做一些简单的报表测试下功能发现常规的二维表、套打、条形码二维码等我关注的功能都有是一个比较强大的报表控件本篇随笔主要介绍在Winform开发中使用Grid报表设计报表模板以及绑定数据的处理过程。PS给大家推荐这个WinForm应用界面开发组件——DevExpress WinForms它能完美构建流畅、美观且易于使用的应用程序无论是Office风格的界面还是分析处理大批量的业务数据它都能轻松胜任DevExpress新旧版本帮助文档获取可点击这篇文章查看——《界面控件DevExpress v26.1帮助文档大全CHM版本》报表模板设计这个报表系统报表模板提供了很多案例我们可以大概浏览下其功能。它对应在相应的文件目录里面我们可以逐一查看了解下感觉提供这么多报表还是很赞的我们可以参考着来用非常好。整个报表主要是基于现有数据进行一个报表的模板设计的如果要预览效果我们一般是需要绑定现有的数据可以从各种数据库提供数据源然后设计报表模板进行实时的数据和格式查看及调整。空白的报表模板大概如下所示包含页眉页脚以及明细表格的内容。根据它的教程模仿着简单的做了一个报表也主要是设计报表格式的调整和数据源的处理的关系我们做一个两个报表就可以很快上手了。为了动态的加入我们表格所需要的列我们可以通过数据库里面的字段进行加入首先提供数据源指定我们具体的表即可如果是自定义的信息则可以手工添加字段。这个里面就是配置不同的数据库数据源了。如SQLServer数据库的配置信息如下。为了方便我们可以利用案例的Access数据库也就是Northwind.mdb来测试我们的报表弄好这些我们指定对应的数据表数据即可。这里面配置好数据库表信息后我们就可以用它生成相关的字段和对应的列信息了。修改列的表头让它符合中文的表头列如下所示。我们在页脚出加入了打印时间页码的一些系统变量具体操作就是添加一个综合文本然后在内容里面插入指定的域内容即可如下所示预览报表我们就可以看到具体的报表格式显示了。通过上面的操作感觉生成一个报表还是很方便的接着我有根据需要做了一个二维码的报表显示方便打印资产标签。绑定数据源显示的报表视图如下所示看起来还是蛮好的。数据绑定一般我们绑定数据源有的时候可以直接指定数据库连接有时候可以绑定具体的数据列表如DataTable或者ListT这样的数据源不同的方式报表控件的代码绑定不同。直接绑定数据表的路径如下所示。/// 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和ListT等这样类型数据的动态增加操作。/// 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() { ListProductInfo list BLLFactoryProduct.Instance.GetAll(); GridReportHelper.FillRecordToReportProductInfo(Report, list); } private void ReportList_FetchRecord2() { var dataTable BLLFactoryProduct.Instance.GetAllToDataTable(); GridReportHelper.FillRecordToReport(Report, dataTable); }其中辅助类 GridReportHelper 代码如下所示。/// summary /// Gird报表的辅助类 /// /summary public class GridReportHelper { private struct MatchFieldPairType { public IGRField grField; public int MatchColumnIndex; } /// summary /// 将 DataReader 的数据转储到 GridReport 的数据集中 /// /summary /// param nameReport报表对象/param /// param namedrDataReader对象/param public static void FillRecordToReport(IGridppReport Report, IDataReader dr) { MatchFieldPairType[] MatchFieldPairs new MatchFieldPairType[Math.Min(Report.DetailGrid.Recordset.Fields.Count, dr.FieldCount)]; //根据字段名称与列名称进行匹配建立DataReader字段与GridReport记录集的字段之间的对应关系 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 中的每一条记录转储到GridReport 的数据集中去 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 的数据转储到 GridReport 的数据集中 /// /summary /// param nameReport报表对象/param /// param namedtDataTable对象/param public static void FillRecordToReport(IGridppReport Report, DataTable dt) { MatchFieldPairType[] MatchFieldPairs new MatchFieldPairType[Math.Min(Report.DetailGrid.Recordset.Fields.Count, dt.Columns.Count)]; //根据字段名称与列名称进行匹配建立DataReader字段与GridReport记录集的字段之间的对应关系 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 中的每一条记录转储到 GridReport 的数据集中去 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 nameT/typeparam /// param nameReport报表对象/param /// param namelist列表数据/param public static void FillRecordToReportT(IGridppReport Report, ListT list) { Type type typeof(T); //反射类型 MatchFieldPairType[] MatchFieldPairs new MatchFieldPairType[Math.Min(Report.DetailGrid.Recordset.Fields.Count, type.GetProperties().Length)]; //根据字段名称与列名称进行匹配建立字段与GridReport记录集的字段之间的对应关系 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 中的每一条记录转储到 GridReport 的数据集中去 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 nameobj对象实例/param /// param namename属性名称/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) { ListProductInfo list BLLFactoryProduct.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); } }以上就是利用这个报表控件做的一些功能测试和辅助类封装方便使用。本文转载自博客园 - 伍华聪

相关新闻

2026/8/21 14:37:33

使用DevExpress WPF主题设计器轻松创建Office 2019绿色主题(二)

DevExpress WPF拥有120个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 DevExpress新旧版本帮…

2026/8/21 14:37:33

AQS学习

1. AQS 简介1.1 什么是 AQSAQS(AbstractQueuedSynchronizer)是 Java 并发包(java.util.concurrent.locks)中的一个核心框架类,用于构建锁和其他同步器。AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单…

2026/8/21 17:32:55

RPCS3模拟器从零实战:三步起步,五招榨干性能

RPCS3模拟器从零实战:三步起步,五招榨干性能 【免费下载链接】rpcs3 PlayStation 3 emulator and debugger 项目地址: https://gitcode.com/GitHub_Trending/rp/rpcs3 你在抽屉里翻出当年的PS3游戏光盘,主机却早已黄灯报废&#xff1b…

2026/8/21 13:13:49

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/20 20:11:18

工业传感器与变送器详解:序章 从物理世界到工业数据

序章 从物理世界到工业数据 ——重新认识工业传感器与变送器 工业自动化系统正变得日益复杂。今天的工业现场早已不是简单的控制回路,而是由多层技术共同构成的立体体系:PLC、DCS、SCADA、MES、工业互联网、边缘计算与人工智能。控制系统可以执行复杂算法,工业网络可以实现…

2026/8/21 0:03:13

Linux命令-uucico(UUCP传输程序)

Linux命令-uucico(UUCP传输程序) 🔰简介UUCP 体系简介 📖语法⚙️选项配置文件 💡示例示例 1:基本传输操作示例 2:主模式与从模式示例 3:调试与故障排查示例 4:UUCP 配置…

2026/8/21 0:03:13

Linux命令-uupick(UUCP文件接收工具)

Linux命令-uupick(UUCP文件接收工具)🔰简介uupick 在 UUCP 传输链中的位置📖语法⚙️选项交互命令💡示例示例 1:基本接收操作示例 2:仅处理来自特定系统的文件示例 3:完整 UUCP 文件…

2026/8/21 15:40:01

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/21 15:40:01

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/21 0:31:27

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…