这些年的工作当中,最早是在8年前接触到FastReport这个报表工具,从名字上来看,直译过来就是快速报表,正所谓天下武功,唯快不破,FastReport报表早些年确实是制作报表的不二之选,8年前的工作中,涉入到了医疗行业,项目中要使用FastReport.net 打印基因检测报告,效果确实是满足了项目要求。
最新版FastReport.net支持.net core
鸡肋的FastReport.net网页版
回过来看,最近几年的工作中,报表也是一直使用的是FastReport.net ,但转到了BS端,即在网页上打印业务单据,基本上不复杂的效果完全满足要求,而且我还开发了基于ActiveX的控件,以解决浏览器上FastReport报表BS版本比较鸡肋的功能,FastReport.net的网页版本的打印是通过生成PDF文件,然后调用PDF的打印功能来实现打印,如果原生的浏览器打印功能,会存在着页脚被添加一串URL地址、翻页,定制页不能打印的问题。通过开发FastReport.net的ActiveX控件,可以实现用户自定义报表功能,网页直接打印功能,指定默认打印机功能,反正跟桌面版本体验一致的效果。但唯一的缺点是基于IE内核,因ActiveX是弥补IE的缺陷而生的一项技术,等将来有兴趣了,我或许会移植该程序以支持基于Chrome浏览器,让FastReport.net这个报表,不管任何浏览器都获得跟桌面版本一致的体验。
今天要分享给大家的是使用FastReport.net 2017版本而编写的一个demo程序,并提供了示例程序下载;为何使用FastReport.net 2017,那是因为购买的授权是这个版本,当时想着该版本支持 .net core,但实际情况是该版本只是一个过渡版本,对.net core的支持有问题,官方示例程序我是没有运行起来,于是我就变通一下,直接使用 webform方式来实现,因为该报表对webform实现支持是比较良好的,如果有朋友或公司购买了FastReport.net老版本的授权,但想要它支持.net core是行不通的,必须最新版本才行,因此可以像我这样变通解决网页版打印问题。
解决方法如下
1、单独新建一个webform的网站项目,只添加报表相关文件和代码,我们暂且将这个项目称之为FastReport.Print,它是一个BS版本的基于FastReport.net实现打印需求的网站项目,如果您的业务单据较多,可以建很多目录,同时将报表文件扔到相应目录即可,只需要在代码里面指定报表文件即可。
2、正式的网站项目,我们称之为XXXX.Portal,在Portal某个目录的页面上发起打印请求,该页面上放置一个打印按钮,名字叫:批量打印,触发批量打印事件后,从后台获取到数据,然后将打印数据按报表所需要的格式Post到FastReport.Print对应的打印页面即可。记住,一定是发送post请求,至于格式,你可以是任意的,只需要您自己能解析出来即可,将解析出来的数据,在Print项目的页面的C#代码里面,向FastReport.net注册数据源即可。
示例代码解读
下面是aspx页面代码
<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
<%@ Register assembly="FastReport.Web" namespace="FastReport.Web" tagprefix="cc2" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<div>
<h3><a href="https://jhrs.com" target="_blank"> jhrs.com</a> 出品 FastReport 打印功能示例</h3>
</div>
<div class="row">
<cc2:WebReport ID="WebReport1" runat="server" ShowCsvExport="true" ShowExports="true" />
</div>
</asp:Content>
页面代码是一个WebReport的标签,即FastReport的服务器端标签,下面是后台C#代码:
public partial class _Default : Page { protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { string reportFile = Server.MapPath("/report/设备标牌.frx"); //这里为了演示,直接new一个集合,您应该从另外一个项目将数据post过来再反序列化。通过Request.Form["参数名"],将它反序列化即可。 List<SbData> list = new List<SbData>(); for (int i = 0; i < 5; i++) { list.Add(new SbData { 标题= "帝国游戏集团游戏装备标牌", 使用科室 = "机要部" + i, 启用日期 = DateTime.Now.AddDays(i).ToString(), 型号 = "XH34534-" + i, *** = "XLH-3452" + i, 序号 = (i + 1).ToString(), 条码 = "BH20190302002" + i, 生产厂家 = "帝国" + i + "科技有限公司", 规格 = "GGX-1" + i, 设备名称 = "X射線髮射器", 责任人 = "趙佳仁" + i, 质保日期 = DateTime.Now.AddYears(i).ToString() }); } var dt = ToDataTable(list); WebReport1.RegisterData(dt, "设备管理标牌"); WebReport1.Report.Load(reportFile); WebReport1.Prepare(); } } /// <summary> /// 将泛型集合类转换成DataTable /// </summary> /// <typeparam name="T">集合项类型</typeparam> /// <param name="list">集合</param> /// <returns>数据集(表)</returns> public DataTable ToDataTable<T>(IList<T> list) { List<string> propertyNameList = new List<string>(); DataTable result = new DataTable(); if (list.Count > 0) { PropertyInfo[] propertys = list[0].GetType().GetProperties(); foreach (PropertyInfo pi in propertys) { if (propertyNameList.Count == 0) { result.Columns.Add(pi.Name, pi.PropertyType); } else { if (propertyNameList.Contains(pi.Name)) result.Columns.Add(pi.Name, pi.PropertyType); } } for (int i = 0; i < list.Count; i++) { ArrayList tempList = new ArrayList(); foreach (PropertyInfo pi in propertys) { if (propertyNameList.Count == 0) { object obj = pi.GetValue(list[i], null); tempList.Add(obj); } else { if (propertyNameList.Contains(pi.Name)) { object obj = pi.GetValue(list[i], null); tempList.Add(obj); } } } object[] array = tempList.ToArray(); result.LoadDataRow(array, true); } } return result; } } public class SbData { public string 标题 { get; set; } public string 序号 { get; set; } public string 设备名称 { get; set; } public string 规格 { get; set; } public string 型号 { get; set; } public string 启用日期 { get; set; } public string *** { get; set; } public string 生产厂家 { get; set; } public string 条码 { get; set; } public string 责任人 { get; set; } public string 使用科室 { get; set; } public string 质保日期 { get; set; } }
上面的代码,是一个aspx页面后置代码,我们可以在Page_Load事件里面接收正式项目提交过来的打印数据,建议使用json,因为你只需要直接反序列化即可,方便。然后将获取到的值还要转为DataTable,因为FastReport注册数据源我这儿使用的是DataTable类型,至于其它类型,我没有去烟酒是否正常。
FastReport.net打印网页版运行效果一览
网页版的打印效果如下:
上面的报表,排版格式是很简单的,二维码FastReport自带,这里不介绍使用教程,这个示例只是一个很简单的应用,它的更多功能,可以看官方示例及源码。
基于asp.net 的Demo源码下载
以下提供的demo程序,下载后直接使用VS打开即可运行。
源码下载:点击原文链接进行下载